время: приём чужого офсета и регистрация исключений линтера
- arch R13: валидное по RFC 3339 значение с чужим офсетом нормализуется при разборе; канонический вид — обязательство писателя, не контракт с партнёром - go R13: исключение регистрируется директивой //nolint на месте вызова, а не exclude-записью в конфиге, которая адресует путём и отвязывается
This commit is contained in:
@@ -60,6 +60,21 @@
|
|||||||
разберёт час перехода на зимнее время: этот час идёт дважды, две записи
|
разберёт час перехода на зимнее время: этот час идёт дважды, две записи
|
||||||
получают одинаковую метку, и порядок между ними не восстанавливается ничем.
|
получают одинаковую метку, и порядок между ними не восстанавливается ничем.
|
||||||
|
|
||||||
|
### R13. Чужой вход нормализуется при разборе, а не отклоняется
|
||||||
|
|
||||||
|
**ДОЛЖЕН.** Валидное по RFC 3339 значение с офсетом, отличным от `Z`, или с
|
||||||
|
долями секунды принимается от внешней системы и приводится к каноническому
|
||||||
|
виду (R1) в точке разбора (R5).
|
||||||
|
|
||||||
|
**Почему.** Канонический вид — обязательство нашего писателя, а не
|
||||||
|
контракт, наложенный на внешние системы: `…14:23:45+03:00` называет тот же
|
||||||
|
момент, что `…11:23:45Z`, и отклонять его — значит ломать интеграцию со
|
||||||
|
стороной, которая стандарт соблюла. Пропущенное же как есть, такое значение
|
||||||
|
нарушает форму и ширину носителя (R1, R2) и портит сортировку выборочно —
|
||||||
|
только на записях, пришедших извне, и далеко от места разбора. Нормализация
|
||||||
|
в единой точке разбора оставляет ровно одно место, где неканонический вид
|
||||||
|
существует, — по ту сторону границы его уже нет.
|
||||||
|
|
||||||
### R5. Единая точка получения «сейчас», форматирования и разбора
|
### R5. Единая точка получения «сейчас», форматирования и разбора
|
||||||
|
|
||||||
**ДОЛЖЕН.** Один модуль отдаёт текущий момент, он же форматирует и разбирает
|
**ДОЛЖЕН.** Один модуль отдаёт текущий момент, он же форматирует и разбирает
|
||||||
|
|||||||
@@ -53,6 +53,22 @@ layout — а расхождение проявится не на записи,
|
|||||||
«починены» тем, кто увидит в них дефект, и конвенция начнёт противоречить
|
«починены» тем, кто увидит в них дефект, и конвенция начнёт противоречить
|
||||||
сама себе.
|
сама себе.
|
||||||
|
|
||||||
|
### R13. Исключение регистрируется директивой на месте вызова, а не в конфиге линтера
|
||||||
|
|
||||||
|
**ДОЛЖЕН.** Исключение из R3 оформляется как `//nolint:forbidigo // <причина>`
|
||||||
|
на строке вызова; exclude-записи в конфигурации линтера для него не
|
||||||
|
заводятся.
|
||||||
|
|
||||||
|
**Почему.** Запись в конфиге — второй реестр тех же двух мест: она адресует
|
||||||
|
исключение путём к файлу, отвязывается при переносе кода и продолжает
|
||||||
|
разрешать `time.Now()` там, где исключения уже нет, — молча. Директива
|
||||||
|
переезжает вместе с кодом, и grep по `nolint:forbidigo` даёт весь список —
|
||||||
|
та исчерпываемость, которой требует R3, проверяется одной командой. Голый
|
||||||
|
`//nolint` без имени правила глушит на строке все проверки сразу, а без
|
||||||
|
причины неотличим от заглушенного дефекта; обе деградации штатно ловит
|
||||||
|
`nolintlint` (`require-specific`, `require-explanation`) — стандартный
|
||||||
|
способ дисциплинировать директивы в golangci-lint.
|
||||||
|
|
||||||
### R4. В БД время хранится с секундной точностью, ширина 20 символов
|
### R4. В БД время хранится с секундной точностью, ширина 20 символов
|
||||||
|
|
||||||
**ДОЛЖЕН.** Каноническое значение в колонке — `2026-06-28T11:23:45Z`.
|
**ДОЛЖЕН.** Каноническое значение в колонке — `2026-06-28T11:23:45Z`.
|
||||||
@@ -86,7 +102,9 @@ layout — а расхождение проявится не на записи,
|
|||||||
офсеты, отличные от `Z`, — разбор шире вывода. Канонический вид гарантирует
|
офсеты, отличные от `Z`, — разбор шире вывода. Канонический вид гарантирует
|
||||||
**писатель**, а не читатель; пока писатель один, этого достаточно, но
|
**писатель**, а не читатель; пока писатель один, этого достаточно, но
|
||||||
значение из чужой системы, положенное в базу как пришло, нарушает R4 и
|
значение из чужой системы, положенное в базу как пришло, нарушает R4 и
|
||||||
обнаруживается не на записи, а на первой сортировке.
|
обнаруживается не на записи, а на первой сортировке. Само решение
|
||||||
|
«нормализовать, а не отклонять» — базовое (`arch/time.md` R13); здесь —
|
||||||
|
Go-механика, из-за которой его легко нарушить незаметно.
|
||||||
|
|
||||||
### R7. В драйвер передаётся строка, а не `time.Time`
|
### R7. В драйвер передаётся строка, а не `time.Time`
|
||||||
|
|
||||||
@@ -166,6 +184,6 @@ func utcTime(_ []string, a slog.Attr) slog.Attr {
|
|||||||
|
|
||||||
## Связано
|
## Связано
|
||||||
|
|
||||||
- `arch/time.md` — базовая конвенция: UTC как формат хранения, явная зона в
|
- `arch/time.md` — базовая конвенция: UTC как формат хранения, нормализация
|
||||||
календарных вычислениях.
|
чужого входа, явная зона в календарных вычислениях.
|
||||||
- `lang/go/config.md` — валидация зоны отображения загрузчиком конфига.
|
- `lang/go/config.md` — валидация зоны отображения загрузчиком конфига.
|
||||||
|
|||||||
Reference in New Issue
Block a user