Как изменить логику получения сегодняшнего тарифа с учетом часового пояса?
Что проверяют
Понимаете ли вы, что «сегодня» не существует без часового пояса: в 01:00 по Москве на сервере в UTC ещё вчерашний день. Проверяют, чей пояс вы берёте и как собираетесь это тестировать. Следом обычно спрашивают про переход на летнее время и про границу суток.
Как отвечать
Начните с вопроса к бизнесу: тариф считается по поясу клиента, региона обслуживания или компании. Это требование, а не техническая деталь. Дальше каркас:
- явная зона:
LocalDate today = LocalDate.now(clock.withZone(zoneId)), гдеzoneIdэтоZoneId.of("Europe/Moscow")из профиля. ВызовLocalDate.now()без аргументов берёт пояс JVM по умолчанию, а в контейнере это почти всегда UTC; Clockв зависимостях: сервис получаетjava.time.Clockбином, в тестах подставляетсяClock.fixed(...), и граница суток проверяется детерминированно;- хранение: моменты событий держите как
Instant(в PostgreSQL этоtimestamptz), а сроки действия тарифа какLocalDateв той зоне, по которой он продаётся; - выборка: полуоткрытый интервал
valid_from <= :today and (valid_to is null or valid_to > :today)прямо в SQL, а не фильтр всего списка в памяти.
Про переходы времени: сутки бывают длиной 23 или 25 часов, а в некоторых зонах в день перехода вообще нет полуночи. Поэтому начало дня получают через today.atStartOfDay(zoneId), а не склейкой даты с 00:00. Правила зон живут в базе tzdata внутри JDK, и её нужно обновлять вместе с JDK.
Где спотыкаются
Хардкодят смещение ZoneOffset.ofHours(3). Для региона, где правила меняются, это ошибка: нужен идентификатор зоны, а не число.
Сравнивают через isAfter и isBefore с обеих сторон и теряют тариф ровно в момент его начала. Интервалы должны быть полуоткрытыми.
Вызывают now() прямо в бизнес-логике. Такой код не проверить на полночь и на день перевода часов, и баги находят пользователи.