"""«Сегодня» по Москве для дат перевода/закрытия ЮЛ (issue #9 п.6, follow-up #8): граница суток — московская.""" import datetime import pytest from src.common.clock import MOSCOW_TZ, moscow_date from src.common.exceptions import DomainValidationError from src.services import legal_entities from src.services.legal_entities import LegalEntityService UTC = datetime.UTC # 23:30 МСК 4 октября = 20:30 UTC 4 октября; 00:30 МСК 5 октября = 21:30 UTC 4 октября (UTC ещё 4-е) LATE_EVENING_MSK = datetime.datetime(2026, 10, 4, 20, 30, tzinfo=UTC) AFTER_MIDNIGHT_MSK = datetime.datetime(2026, 10, 4, 21, 30, tzinfo=UTC) OCT_4 = datetime.date(2026, 10, 4) OCT_5 = datetime.date(2026, 10, 5) def test_moscow_zone_is_utc_plus_3() -> None: assert LATE_EVENING_MSK.astimezone(MOSCOW_TZ).utcoffset() == datetime.timedelta(hours=3) @pytest.mark.parametrize( ("moment", "expected"), [(LATE_EVENING_MSK, OCT_4), (AFTER_MIDNIGHT_MSK, OCT_5)], ids=["23:30-msk", "00:30-msk"], ) def test_moscow_date_follows_moscow_midnight(moment: datetime.datetime, expected: datetime.date) -> None: assert moscow_date(moment) == expected assert moment.date() == OCT_4 # дата UTC в обоих случаях — 4-е def test_moscow_date_rejects_naive_datetime() -> None: with pytest.raises(ValueError, match="часов"): moscow_date(datetime.datetime(2026, 10, 4, 21, 30)) # noqa: DTZ001 - проверяется отказ на naive @pytest.mark.parametrize( ("moment", "today"), [(LATE_EVENING_MSK, OCT_4), (AFTER_MIDNIGHT_MSK, OCT_5)], ids=["23:30-msk", "00:30-msk"], ) def test_effective_date_today_is_moscow_date( monkeypatch: pytest.MonkeyPatch, moment: datetime.datetime, today: datetime.date ) -> None: monkeypatch.setattr(legal_entities, "utc_now", lambda: moment) assert legal_entities._today() == today LegalEntityService._check_effective_date(today) # сегодня по Москве — можно with pytest.raises(DomainValidationError) as info: LegalEntityService._check_effective_date(today - datetime.timedelta(days=1)) assert info.value.code == "EFFECTIVE_DATE_IN_PAST" def test_after_moscow_midnight_utc_date_is_already_past(monkeypatch: pytest.MonkeyPatch) -> None: """00:30 МСК 5-го: 4-е (ещё «сегодня» по UTC) — уже прошлое.""" monkeypatch.setattr(legal_entities, "utc_now", lambda: AFTER_MIDNIGHT_MSK) with pytest.raises(DomainValidationError): LegalEntityService._check_effective_date(OCT_4)