- 13 конвенций по осям arch / lang / stack / common; репозитории берут оттуда копии в свой docs/conventions/ и коммитят их у себя - conv — синхронизация копий: add / status / diff / pull / push, локальные регионы исключены из сравнения, поэтому расхождение не даёт шума
75 lines
5.0 KiB
Markdown
75 lines
5.0 KiB
Markdown
---
|
||
status: рекомендуемая
|
||
---
|
||
|
||
# Время
|
||
|
||
Один формат времени на всё приложение: хранение, логи, API, обмен с
|
||
внешними системами. Разные форматы в разных слоях — источник ошибок,
|
||
которые всплывают через полгода на границе перехода на летнее время.
|
||
|
||
## Формат
|
||
|
||
- **RFC 3339, UTC, суффикс `Z`**: `2026-06-28T11:23:45Z`.
|
||
- **Ширина фиксируется на каждый носитель** и внутри него не плавает.
|
||
Лексикографическая сортировка равна хронологии только среди строк
|
||
одинаковой длины: `…00.123Z` сортируется раньше `…00.12Z`, хотя
|
||
хронологически позже. Ради этого формат и фиксируется — `ORDER BY
|
||
created_at` по текстовому полю обязан давать порядок событий.
|
||
- Разные носители могут иметь разную точность: строки БД и строки лога
|
||
между собой никогда не сравниваются. Требование — не «одна точность на
|
||
приложение», а «внутри колонки и внутри потока логов ширина одна».
|
||
- Локальное время не хранится и не передаётся **нигде** — ни в БД, ни в
|
||
логах, ни в JSON API.
|
||
|
||
## Генерирует приложение, а не хранилище
|
||
|
||
- Единая точка получения «сейчас» и единая точка форматирования и разбора —
|
||
как с идентификаторами (`arch/db-identifiers.md`). Прямые вызовы часов по
|
||
коду не разбросаны: иначе ни формат, ни зона не гарантированы.
|
||
- **Дефолты в схеме БД не используем.** Забытая вставка `created_at`
|
||
должна падать громко, а не тихо получать значение от БД — иначе
|
||
расходятся источник времени (сервер БД) и его формат.
|
||
|
||
## Длительность — не метка времени
|
||
|
||
Измерение длительности операции — отдельная величина: число (обычно
|
||
миллисекунды) в поле вида `duration_ms`, а не разность двух меток и не
|
||
время в формате выше. Засекает её тот слой, который делает вызов.
|
||
|
||
**Интервал измеряется монотонными часами процесса**, а не вычитанием
|
||
сохранённых меток: стенные часы подводит NTP, они могут шагнуть назад и
|
||
дать отрицательную длительность. Из этого следует, что источник меток
|
||
времени и источник интервалов — разные, даже если оба называются «часы».
|
||
|
||
## Зоны
|
||
|
||
Единственное место, где появляется не-UTC, — **отображение пользователю**.
|
||
Зона берётся из конфигурации (`arch/config.md`), значение по умолчанию —
|
||
`UTC`. На хранение, сортировку и логи она не влияет.
|
||
|
||
Если бизнес-логика оперирует календарными сущностями («сегодня»,
|
||
«за месяц»), зона указывается **явно** в месте вычисления — молчаливое
|
||
использование системной зоны процесса запрещено: она разная на ноутбуке и в
|
||
контейнере. По умолчанию это та же зона, что и для отображения; если
|
||
календарная логика требует другой, это записывается явно.
|
||
|
||
Конвенция описывает фиксацию **свершившихся моментов**. Планирование
|
||
будущих событий — отдельный случай (там хранят локальное время плюс имя
|
||
зоны, потому что правила зон меняются); пока такой сущности нет, правило не
|
||
формулируем.
|
||
|
||
<!-- local:механизировано -->
|
||
<!-- /local -->
|
||
|
||
<!-- local:отступления -->
|
||
<!-- /local -->
|
||
|
||
## Связано
|
||
|
||
- `arch/config.md` — где задаётся зона отображения.
|
||
- `arch/db-identifiers.md` — то же правило «генерирует приложение» для id.
|
||
|
||
<!-- local:связано -->
|
||
<!-- /local -->
|