arm-core/api/tests/test_clock.py
Andrey Epifancev b17176f97c fix: «сегодня» для effective_date — дата по Москве (#9 п.6, follow-up #8)
`_today()` в `services/legal_entities.py` берёт московскую дату
(`common/clock.py`: `moscow_date`, `MOSCOW_TZ` = Europe/Moscow; без базы
часовых поясов — фиксированный UTC+3, Москва без перехода на летнее время с
2014 г.). Тесты на границе суток: 23:30 МСК (20:30 UTC) — ещё 4-е, 00:30 МСК
(21:30 UTC того же дня) — уже 5-е, и 4-е становится прошлым. README: даты
перевода/вывода — по Москве.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-05 13:29:00 +04:00

62 lines
2.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""«Сегодня» по Москве для дат перевода/закрытия ЮЛ (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)