import sqlite3 import sys import tempfile import unittest from contextlib import closing from datetime import date, datetime, timezone from pathlib import Path CRAWLER_DIR = Path(__file__).resolve().parents[1] if str(CRAWLER_DIR) not in sys.path: sys.path.insert(0, str(CRAWLER_DIR)) from crawler_manager import CrawlerManager from time_utils import ( KST, ensure_kst, kst_day_bounds_utc, parse_legacy_kst_datetime, ) class TimeUtilsTest(unittest.TestCase): def test_new_year_kst_day_uses_previous_utc_date(self): start, end = kst_day_bounds_utc(date(2026, 1, 1)) self.assertEqual("2025-12-31T15:00:00+00:00", start.isoformat()) self.assertEqual("2026-01-01T15:00:00+00:00", end.isoformat()) def test_month_end_is_half_open_at_next_kst_midnight(self): start, end = kst_day_bounds_utc(date(2026, 8, 31)) self.assertEqual("2026-08-30T15:00:00+00:00", start.isoformat()) self.assertEqual("2026-08-31T15:00:00+00:00", end.isoformat()) def test_legacy_naive_sqlite_datetime_is_treated_as_kst(self): parsed = parse_legacy_kst_datetime("2026-08-06T09:00:00") self.assertEqual(KST, parsed.tzinfo) self.assertEqual(9, parsed.hour) def test_aware_utc_datetime_is_converted_to_kst(self): parsed = ensure_kst(datetime(2026, 8, 5, 15, 0, tzinfo=timezone.utc)) self.assertEqual(date(2026, 8, 6), parsed.date()) self.assertEqual(0, parsed.hour) class CrawlerManagerTimezoneTest(unittest.TestCase): def setUp(self): self.temp_dir = tempfile.TemporaryDirectory() self.current = datetime(2026, 8, 5, 19, 59, tzinfo=timezone.utc) self.manager = CrawlerManager( db_path=Path(self.temp_dir.name) / "crawler_manager.db", now_provider=lambda: self.current, ) def tearDown(self): self.temp_dir.cleanup() def test_night_window_uses_kst_when_host_clock_is_utc(self): # UTC 19:59 == KST 04:59 self.assertFalse(self.manager.should_run("plant-a")) # UTC 20:00 == KST 05:00 self.current = datetime(2026, 8, 5, 20, 0, tzinfo=timezone.utc) self.assertTrue(self.manager.should_run("plant-a")) def test_legacy_naive_heartbeat_value_can_be_compared(self): self.current = datetime(2026, 8, 6, 1, 0, tzinfo=timezone.utc) # KST 10:00 self.assertTrue(self.manager.should_save("plant-a", {"kw": 10, "today": 20})) with closing(sqlite3.connect(self.manager.db_path)) as conn: conn.execute( "UPDATE site_data SET updated_at = ? WHERE site_id = ?", ("2026-08-06T08:59:59", "plant-a"), ) conn.commit() self.assertTrue(self.manager.should_save("plant-a", {"kw": 10, "today": 20})) if __name__ == "__main__": unittest.main()