""" Tests for timezone utility module. Validates centralized timezone helpers that ensure scheduling logic uses explicit America/Chicago timezone rather than relying on OS defaults. """ import pytest from datetime import datetime, timezone from zoneinfo import ZoneInfo from utils.timezone import ( CHICAGO_TZ, now_utc, now_chicago, to_chicago, to_discord_timestamp, ) class TestChicagoTZ: """Tests for the CHICAGO_TZ constant.""" def test_chicago_tz_is_zoneinfo(self): """CHICAGO_TZ should be a ZoneInfo instance for America/Chicago.""" assert isinstance(CHICAGO_TZ, ZoneInfo) assert str(CHICAGO_TZ) == "America/Chicago" class TestNowUtc: """Tests for now_utc().""" def test_returns_aware_datetime(self): """now_utc() should return a timezone-aware datetime.""" result = now_utc() assert result.tzinfo is not None def test_returns_utc(self): """now_utc() should return a datetime in UTC.""" result = now_utc() assert result.tzinfo == timezone.utc class TestNowChicago: """Tests for now_chicago().""" def test_returns_aware_datetime(self): """now_chicago() should return a timezone-aware datetime.""" result = now_chicago() assert result.tzinfo is not None def test_returns_chicago_tz(self): """now_chicago() should return a datetime in America/Chicago timezone.""" result = now_chicago() assert result.tzinfo == CHICAGO_TZ class TestToChicago: """Tests for to_chicago().""" def test_converts_utc_datetime(self): """to_chicago() should correctly convert a UTC datetime to Chicago time.""" # 2024-07-15 18:00 UTC = 2024-07-15 13:00 CDT (UTC-5 during summer) utc_dt = datetime(2024, 7, 15, 18, 0, 0, tzinfo=timezone.utc) result = to_chicago(utc_dt) assert result.hour == 13 assert result.tzinfo == CHICAGO_TZ def test_handles_naive_datetime_assumes_utc(self): """to_chicago() should treat naive datetimes as UTC.""" naive_dt = datetime(2024, 7, 15, 18, 0, 0) result = to_chicago(naive_dt) # Same as converting from UTC utc_dt = datetime(2024, 7, 15, 18, 0, 0, tzinfo=timezone.utc) expected = to_chicago(utc_dt) assert result.hour == expected.hour assert result.tzinfo == CHICAGO_TZ def test_preserves_already_chicago(self): """to_chicago() on an already-Chicago datetime should be a no-op.""" chicago_dt = datetime(2024, 7, 15, 13, 0, 0, tzinfo=CHICAGO_TZ) result = to_chicago(chicago_dt) assert result.hour == 13 assert result.tzinfo == CHICAGO_TZ def test_winter_offset(self): """to_chicago() should use CST (UTC-6) during winter months.""" # 2024-01-15 18:00 UTC = 2024-01-15 12:00 CST (UTC-6 during winter) utc_dt = datetime(2024, 1, 15, 18, 0, 0, tzinfo=timezone.utc) result = to_chicago(utc_dt) assert result.hour == 12 class TestToDiscordTimestamp: """Tests for to_discord_timestamp().""" def test_default_style(self): """to_discord_timestamp() should use 'f' style by default.""" dt = datetime(2024, 7, 15, 18, 0, 0, tzinfo=timezone.utc) result = to_discord_timestamp(dt) unix_ts = int(dt.timestamp()) assert result == f"" def test_relative_style(self): """to_discord_timestamp() with style='R' should produce relative format.""" dt = datetime(2024, 7, 15, 18, 0, 0, tzinfo=timezone.utc) result = to_discord_timestamp(dt, style="R") unix_ts = int(dt.timestamp()) assert result == f"" def test_all_styles(self): """to_discord_timestamp() should support all Discord timestamp styles.""" dt = datetime(2024, 7, 15, 18, 0, 0, tzinfo=timezone.utc) unix_ts = int(dt.timestamp()) for style in ("R", "f", "F", "t", "T", "d", "D"): result = to_discord_timestamp(dt, style=style) assert result == f"" def test_naive_datetime_assumes_utc(self): """to_discord_timestamp() should treat naive datetimes as UTC.""" naive_dt = datetime(2024, 7, 15, 18, 0, 0) aware_dt = datetime(2024, 7, 15, 18, 0, 0, tzinfo=timezone.utc) assert to_discord_timestamp(naive_dt) == to_discord_timestamp(aware_dt) def test_chicago_datetime_same_instant(self): """to_discord_timestamp() should produce the same unix timestamp regardless of tz.""" utc_dt = datetime(2024, 7, 15, 18, 0, 0, tzinfo=timezone.utc) chicago_dt = utc_dt.astimezone(CHICAGO_TZ) assert to_discord_timestamp(utc_dt) == to_discord_timestamp(chicago_dt)