feat(ddl): часовые пояса — линза названа явно #75

Merged
ddmitry merged 6 commits from docs/63-timezone-convention into main 2026-08-08 20:16:58 +03:00
Owner
  • Зачем:
    • стенд стоял на неявном умолчании: колонки времени объявлены без пояса, и
      сходилось всё лишь потому, что пояс сервера — UTC. Правило нужно принять
      до того, как написаны dds.* и витрины: там оно и понадобится — воронки,
      удержание, «покупки по дням».
  • Что:
    • конвенция записана в docs/architecture/storage.md, раздел «Часовые
      пояса»: линза называется явно — в типе колонки либо в вызове функции;
      какая именно, решает слой по тому, кого он обслуживает.
    • ODS говорит на языке выгрузки: UTCEventTimeDateTime('UTC'),
      служебные метки _load_ts и kafka_timestampDateTime64(3, 'UTC')
      в обоих слоях.
    • parseDateTimeOrNull получил третьим аргументом 'UTC': суффикс Z
      маска сверяет как букву и выбрасывает, поэтому тип колонки путь записи
      не чинит.
    • контракт схемы, «описание выгрузки» и таблица колонок мастер-спеки
      несут тип с поясом; имя Europe/Samara стоит комментарием к
      COUNTER_TIMEZONE_MINUTES.
    • учебный комментарий про пояс — у первой колонки, где он назван.
  • Проверка:
    • make lint, make typecheck, make test (407)
    • make clean && make up && make check-clickhouse — 9 из 9
    • make smoke — 20, make check-services — 7
    • замер тикета повторён: под session_timezone='Europe/Samara' колонка
      показана 2026-05-31 23:37:00, как и без настроек — глаз и GROUP BY
      перестали спорить

Разбор двух холодных ревью и снятые замеры — комментарием в #63.

Closes #63

- Зачем: - стенд стоял на неявном умолчании: колонки времени объявлены без пояса, и сходилось всё лишь потому, что пояс сервера — UTC. Правило нужно принять до того, как написаны `dds.*` и витрины: там оно и понадобится — воронки, удержание, «покупки по дням». - Что: - конвенция записана в `docs/architecture/storage.md`, раздел «Часовые пояса»: линза называется явно — в типе колонки либо в вызове функции; какая именно, решает слой по тому, кого он обслуживает. - ODS говорит на языке выгрузки: `UTCEventTime` — `DateTime('UTC')`, служебные метки `_load_ts` и `kafka_timestamp` — `DateTime64(3, 'UTC')` в обоих слоях. - `parseDateTimeOrNull` получил третьим аргументом `'UTC'`: суффикс `Z` маска сверяет как букву и выбрасывает, поэтому тип колонки путь записи не чинит. - контракт схемы, «описание выгрузки» и таблица колонок мастер-спеки несут тип с поясом; имя `Europe/Samara` стоит комментарием к `COUNTER_TIMEZONE_MINUTES`. - учебный комментарий про пояс — у первой колонки, где он назван. - Проверка: - `make lint`, `make typecheck`, `make test` (407) - `make clean && make up && make check-clickhouse` — 9 из 9 - `make smoke` — 20, `make check-services` — 7 - замер тикета повторён: под `session_timezone='Europe/Samara'` колонка показана `2026-05-31 23:37:00`, как и без настроек — глаз и `GROUP BY` перестали спорить Разбор двух холодных ревью и снятые замеры — комментарием в #63. Closes #63
ddmitry added 5 commits 2026-08-08 20:00:41 +03:00
- Зачем:
  - пояс в стенде нигде не назван: числа верны только потому, что сервер
    ClickHouse стоит в UTC, а правило понадобится в dds и витринах —
    воронки, удержание, «покупки по дням» (#63).
- Что:
  - раздел «Часовые пояса»: пояс — линза, называется в типе колонки либо в
    вызове; какая именно — решает слой (ODS на языке выгрузки, DDS и витрины
    на языке бизнеса); день берётся из EventDate.
  - названы оба перехода, где пояс выбирается, включая разбор строки в
    матвью — он берёт пояс у сервера и тип колонки этого не чинит.
  - отвергнутые варианты прозой: умолчание сервера, TZ серверу, ODS в поясе
    счётчика, хранение местного времени.
  - три замера ушли в «Что проверено», сверка с документацией — от 8 августа.
- Проверка:
  - make lint
  - DDL к конвенции ещё не приведён: документ описывает цель, код идёт
    следом тем же тикетом.
- Зачем:
  - раздел «Часовые пояса» прошёл два холодных ревью — по дефектам и по
    уместности. Первое поймало ложный замер и три расхождения с живым
    стендом, второе — материал не своей зоны и дубли (#63).
- Что:
  - замер «расхождение живёт по HTTP» отозван: мерил toString(UTCEventTime)
    в родном клиенте против голой колонки по HTTP, а это разные вещи.
    Перемерено — клиенты ведут себя одинаково; записан верный факт: вывод
    колонки идёт по поясу сессии, функция — по поясу типа.
  - «по поясу сервера» заменено на «по поясу сессии, а тот по умолчанию
    серверный» — в разделе и в ADR 0005; утверждение в ледгере переписано
    под измеренный раскол вывода и типа.
  - PARTITION BY toDate(_load_ts) больше не выдаётся за уже соблюдённое
    правило: _load_ts сегодня DateTime64(3) без пояса.
  - абзац ADR 0005 больше не спорит с цитатой вызова строкой выше.
  - вырезано: веер отклонённых вариантов под заголовком (живые отказы
    разложены прозой по своим абзацам, как принято в этом документе),
    ссылка на несуществующую связку в world.py, осиротевшая строка про
    Grafana, абзац про пояс показа — он уехал комментарием в #63.
- Проверка:
  - make lint
  - замеры повторены на живом стенде 8 августа 2026 года
  - DDL к конвенции по-прежнему не приведён: документы описывают цель
- Зачем:
  - конвенция #63 записана, а код её не достиг: колонки времени стояли без
    пояса, и сходилось всё лишь потому, что пояс сервера — UTC.
- Что:
  - UTCEventTime объявлен DateTime('UTC'), служебные метки _load_ts и
    kafka_timestamp — DateTime64(3, 'UTC') в STG и ODS.
  - parseDateTimeOrNull получил третьим аргументом 'UTC': маска сверяет
    суффикс Z как букву, зоны из строки не берёт вовсе.
  - контракт схемы и описание выгрузки несут тип с поясом; имя пояса
    Europe/Samara встало рядом со смещением в world.py, сходимость сверяет
    тест.
  - учебный комментарий о линзе — у первой колонки с явным поясом.
- Проверка:
  - make lint, make typecheck, make test (408 тестов)
  - make clean && make up && make check-clickhouse — 9 из 9
  - замер тикета повторён: под session_timezone='Europe/Samara' колонка
    показана 2026-05-31 23:37:00, как и без настроек

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Зачем:
  - линия дефектов нашла три неверных утверждения и мёртвый замер, линия
    уместности — три пересказа уже сказанного.
- Что:
  - «тип колонки не решает, какое число ляжет» сужено до правды: разбор
    отдаёт готовое число, а пояс приёмника решал бы судьбу строки.
  - замер до правки типов помечен как неповторяемый на нынешнем стенде.
  - правило о поясе сервера привязано к местам, где линза что-то решает:
    матвью приёма пояс не называет, и это не нарушение.
  - убраны: пересказ механики в ADR 0005, четыре строки учебного
    комментария, утверждение о порядке файлов и «секунды от начала эпохи»
    у миллисекундной метки.
- Проверка:
  - make lint, make typecheck, make test (408 тестов)
  - make clean && make up && make check-clickhouse — 9 из 9

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Зачем:
  - константу COUNTER_TIMEZONE не читал ни один модуль, единственным её
    читателем был тест про неё же; связь имени и смещения держится тем, что
    они стоят в одной строке.
- Что:
  - COUNTER_TIMEZONE снят, имя пояса ушло комментарием к
    COUNTER_TIMEZONE_MINUTES.
  - тест сходимости имени и смещения снят вместе с ним; test_world.py
    вернулся к прежнему виду.
- Проверка:
  - make lint, make typecheck, make test (407 тестов)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ddmitry added 1 commit 2026-08-08 20:16:02 +03:00
- Зачем:
  - фраза «Date не участвует вовсе» выводила тип из-под общего правила:
    про объявление это правда, про употребление — нет. Считая время по
    EventDate без имени пояса, легко получить часы вне диапазона.
- Что:
  - фраза заменена на две: Date хранит только номер дня, пояс при счёте
    времени называют руками, промах виден по часам за границами 0–23.
- Проверка:
  - замерено на стенде: без имени пояса часы от начала суток идут -4…19,
    отрицательных 15 843 события; с названным поясом — 0…23

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ddmitry merged commit 5d012cc222 into main 2026-08-08 20:16:57 +03:00
ddmitry deleted branch docs/63-timezone-convention 2026-08-08 20:16:58 +03:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ddmitry/clickstream-data-platform#75