Генератор date
Когда брать. Нужна дата или дата-время — день рождения, дата документа, метка времени события — в заданном диапазоне и в нужном формате вывода.
Даты работают на собственном переносимом рантайме дат TDC: строгий парсер, UTC-календарь и локализованный форматтер, без зависимости от moment.js. Один и тот же конфиг рассчитан на одинаковые даты во всех реализациях.
Примеры вывода ниже иллюстративны — точные значения зависят от сида и могут отличаться между версиями ядра. Неизменны форма и формат.
Кратко
| Атрибут | Что делает |
|---|---|
value | birth, today, now, одна дата или диапазон START..END |
range | Диапазон START..END — более новое написание той же идеи |
from / to | Две границы диапазона, заданные по отдельности |
order | sequential обходит диапазон вместо выбора из него — см. Ось дат |
step | Насколько сдвигается каждая строка на обходимой оси: 15m, 1h30m, 2d, 3mo, 1y |
weekdays | Какие дни недели оставляет обходимая ось: mon..fri, sun,wed |
cycle | false отказывает вместо зацикливания, когда обходимый ОГРАНИЧЕННЫЙ диапазон исчерпан |
format | Формат вывода (см. раздел «Форматирование вывода» ниже); по умолчанию L |
local | Двадцать пять: ar, cs, de, el, en, es, fi, fr, hi, hu, id, it, ja, ko, nl, pl, pt, ru, sv, th, tr, uk, vi, zh-cn, zh-tw. Девятнадцать отзываются ещё и на трёхбуквенный псевдоним — ara, ces, deu, ell, eng, spa, fin, fra, hun, ind, ita, jpn, kor, nld, pol, por, tur, ukr, vie, — а у hi, ru, sv, th, zh-cn, zh-tw псевдонима нет (голое zh принимается и читает традиционную таблицу). Наследуется из <env>, если не задан |
oldest / youngest | Возрастное окно в годах для value="birth" (по умолчанию 80 и 10) |
precision | day, second или millisecond |
of | Отсчитывать от другой колонки дат вместо розыгрыша — см. «Интервал» ниже |
plus | Насколько далеко от неё: 7d, 3..10d, 1..3mo, -10..-3d |
Диапазон описывает только что-то одно из value, range или пары from/to —
это три написания одного и того же. Не задайте ни одного из них — и диапазон пойдёт от
1970-01-01 до текущего момента; см.
Границ нет вовсе.
Последние четыре атрибута относятся к обходимому диапазону и читаются только вместе с
order="sequential". На разыгрываемой дате step или weekdays были бы молча
проигнорированы, поэтому они отвергаются (TDC248).
Случайная дата из диапазона
Задайте value в виде START..END (обе границы включены) — и получите
случайную дату, равномерно распределённую внутри окна.
<gen type="date" value="2020-01-01..2025-12-31" format="YYYY-MM-DD"/>
2024-08-15 2022-02-04 2020-06-21 2025-10-04 2021-03-31
Границы — часть окна. На узком окне в одну неделю это хорошо видно: на достаточном
числе строк встречаются и 2024-06-01, и 2024-06-07:
<gen type="date" value="2024-06-01..2024-06-07" format="YYYY-MM-DD"/>
2024-06-06 2024-06-03 2024-06-01 2024-06-07 2024-06-02 2024-06-02
Входные даты парсятся строго, в одной из форм:
- дата:
YYYY-MM-DD,YYYY.MM.DDилиYYYY/MM/DD; - дата-время:
YYYY-MM-DDTHH:mm,YYYY-MM-DDTHH:mm:ssилиYYYY-MM-DDTHH:mm:ss.SSS; - диапазон:
START..END.
Свободный текст (6 июня, 06/06/24) не принимается — используйте одну из
строгих форм выше.
Атрибут range — то же окно, более новое написание
range="START..END" означает ровно то же, что value="START..END". Оно читается
лучше, когда value иначе выглядело бы как ключевое слово, и это то самое
написание, что и у шаблона date.range.
<gen type="date" range="2020-01-01..2024-12-31" format="YYYY-MM-DD"/>
2023-11-08 2021-09-30 2020-05-23 2024-10-19 2021-01-14
Атрибут format управляет только тем, как дата
записана, — он никогда не меняет окно, а окно никогда не зависит от формата.
from и to — границы по отдельности
Когда яснее назвать две границы порознь, используйте from и to. Это самое
естественное написание для дата-временны́х окон, где диапазон иначе оказался бы
длинной единой строкой.
<gen type="date"
from="2026-05-02T09:00:00"
to="2026-05-02T09:00:05"
format="YYYY-MM-DDTHH:mm:ss"/>
2026-05-02T09:00:04 2026-05-02T09:00:01 2026-05-02T09:00:03 2026-05-02T09:00:00 2026-05-02T09:00:02
Границ нет вовсе — диапазон закрывают часы
Генератор date, которому не дали ни одной границы, всё равно выдаёт дату. Окно
идёт от 1970-01-01 до текущего момента, то есть генератор читает часы, хотя в конфиге
ни одна дата не упомянута:
<gen type="date" format="YYYY-MM-DD"/>
--now 2026-04-23 --now 2027-04-23 1972-06-01 1972-06-17 1994-11-20 1995-04-30 1972-05-06 1972-05-21
Так воспроизводимость теряется проще всего. Задайте генератору две границы или
зафиксируйте часы через --now.
Одна граница третьим вариантом не является для диапазона, из которого ВЫБИРАЮТ:
from без to — это TDC150, а range="2020-01-01.." — TDC151. Там, где значение
разыгрывается, одна граница ничего не говорит о том, что именно разыгрывать. Одной границы
ДОСТАТОЧНО, когда диапазон
обходят — об этом следующий раздел.
Ось дат: обход диапазона вместо выбора из него
Всё, что выше, разыгрывает: каждая строка берёт из окна случайную дату. Попросите по строке на каждый день года — получите повторы и пропуски, потому что розыгрыш именно это и означает.
Добавьте order="sequential" — и диапазон будет обойден. Строка 0 — это начало, строка
1 — один шаг дальше, строка i — это начало + i × шаг. Такая ось времени нужна прогону
тогда, когда данные это ряд, а не выборка: показания, транзакции, журнал.
from в одиночку — ось без конца
Обходимая ось принимает только начало. Её последняя строка — начало + (count − 1) × шаг:
строка 0 и есть само начало. Это следствие длины прогона, а не то, что вы вычисляете и
вписываете руками:
<gen type="date" from="2026-01-01" order="sequential" format="YYYY-MM-DD"/>
2026-01-01 2026-01-02 2026-01-03 2026-01-04 2026-01-05
Поднимите count до миллиона — ось просто пройдёт миллион дней. Ничего не разворачивается
в список, поэтому диапазон не стоит памяти, какой бы длинный он ни был.
step — насколько сдвигается каждая строка
По умолчанию — один день. step принимает число и единицу, и единицы складываются:
| Запись | Означает | Группа |
|---|---|---|
15m | 15 минут | фиксированная |
1h30m | 90 минут | фиксированная |
2 или 2d | 2 дня | фиксированная |
1w | 7 дней | фиксированная |
3mo | 3 календарных месяца | календарная |
1y6mo | 18 календарных месяцев | календарная |
m — это минута, как и во всякой записи такого вида. Месяц — это mo, потому что m
занято; и не M, потому что разница в сорок четыре тысячи раз между тремя минутами и тремя
месяцами не должна держаться на регистре одной буквы.
<gen type="date" from="2026-01-01T09:00:00" order="sequential"
step="15m" format="YYYY-MM-DD HH:mm"/>
2026-01-01 09:00 2026-01-01 09:15 2026-01-01 09:30 2026-01-01 09:45
Шаг бывает ЛИБО фиксированным, ЛИБО календарным, но не тем и другим сразу. 15m — это
всегда 900 000 миллисекунд, а месяц — от 28 до 31 дня. Складываются они только внутри своей
группы, и step="1mo15d" отвергается (TDC247): «месяц и пятнадцать дней» — это 43, 44, 45
или 46 дней в зависимости от того, какую половину применить первой, а конфиг, смысл которого
зависит от невидимого порядка, хуже конфига, который не разбирается. Пишите 45d или 1mo.
Календарный шаг сохраняет день месяца
Каждый шаг отмеряется от начала, а не накапливается. На днях эта разница незаметна, а на месяцах она решает ответ:
<gen type="date" from="2026-01-31" order="sequential" step="1mo" format="YYYY-MM-DD"/>
2026-01-31 2026-02-28 2026-03-31 2026-04-30
Февраль усекается до 28-го, а март возвращается к 31-му. Шаг от усечённого февраля дал бы 28 марта и утащил бы за собой все последующие месяцы.
weekdays — оставить только некоторые дни
Это фильтр, а не шаг:
<gen type="date" from="2026-01-01" order="sequential"
weekdays="mon..fri" format="ddd YYYY-MM-DD"/>
Thu 2026-01-01 Fri 2026-01-02 Mon 2026-01-05 Tue 2026-01-06 Wed 2026-01-07 Thu 2026-01-08
С пятницы на понедельник — прыжок в три дня, и именно поэтому это не шаг: шаг держит интервал ровным, а фильтр его ломает. Разведённые, они складываются — «каждые 12 часов, только в рабочие дни» требует обоих слов:
<gen type="date" from="2026-01-02T00:00:00" order="sequential"
step="12h" weekdays="mon..fri" format="ddd YYYY-MM-DD HH:mm"/>
Fri 2026-01-02 00:00 Fri 2026-01-02 12:00 Mon 2026-01-05 00:00 Mon 2026-01-05 12:00 Tue 2026-01-06 00:00 Tue 2026-01-06 12:00
Диапазон записывается через .., как и всякий диапазон в TDC, а перечисление — через
запятую: weekdays="sun,wed". Диапазон заворачивается: fri..mon — это пятница,
суббота, воскресенье, понедельник. Неделя это круг, и запрет обходить его сделал бы половину
диапазонов невыразимыми.
weekdays отвергают два вида шага (TDC250) — и по двум разным причинам.
Целое число недель каждый раз попадает на один и тот же день недели, поэтому фильтр
совпал бы со всеми строками или ни с одной — полная колонка или пустая, и ни слова о том,
что произошло. Проверяется длина шага, поэтому 14d отвергается ровно так же, как 2w,
а 10d проходит.
Календарный шаг — 1mo, 3mo, 1y — отвергается по обратной причине: он как раз
не фиксирует день недели. Пятнадцатое число за первую половину 2026-го проходит
четверг, воскресенье, воскресенье, среду, пятницу, понедельник. Какие строки переживут
фильтр по дням недели, решал бы календарь, а не то, что написано в конфиге, — поэтому шаг
и фильтр просят выбрать что-то одно.
Если вам нужна была ежемесячная дата, сдвинутая на ближайший рабочий день — как
биллинг переносит счёт с воскресенья, — то сегодня это не выражается, и фильтр этого бы
не сделал: он бы выкинул февраль целиком, а не перенёс его. Календарь рабочих дней —
это другое, и он работает: step="1d" вместе с weekdays="mon..fri", как выше.
Ограниченный диапазон заворачивается
Задайте обходимому диапазону обе границы — и он пойдёт по кругу, когда закончится, как это делает короткий список:
<gen type="date" range="2026-01-01..2026-01-03" order="sequential" format="YYYY-MM-DD"/>
2026-01-01 2026-01-02 2026-01-03 2026-01-01 2026-01-02 2026-01-03 2026-01-01
cycle="false" превращает исчерпание в отказ:
tdcv2: order="sequential" cycle="false": the source has only 2 values, so row 3 has none — shorten count= or lengthen the source
У открытой оси заворачиваться не на чем, поэтому cycle там ничего не значит.
День рождения через value="birth"
value="birth" выдаёт дату рождения относительно текущей даты, ограниченную
возрастным окном. youngest и oldest — это возраст в годах (по умолчанию
10 и 80), поэтому youngest="18" oldest="65" даёт взрослых трудоспособного
возраста.
<gen type="date" value="birth" youngest="18" oldest="65" format="DD.MM.YYYY"/>
05.07.1997 23.11.1985 14.02.2003 30.09.1971 18.06.1990
Зачем это вместо фиксированного диапазона: окно следует за «сейчас», поэтому тот
же конфиг и через год продолжит выдавать правдоподобные возрасты без правки дат. Для
дня рождения, привязанного к цельному синтетическому человеку, шаблон
person.b_day принимает те же атрибуты
oldest/youngest/format.
По этой же причине даты и уезжают. Окно едет вслед за часами, поэтому завтра тот же сид
даст другую дату рождения: возраст держится, дата — нет. Там, где вывод должен стоять на
месте — снапшот-тест, фикстура, баг-репорт, — зафиксируйте часы через
--now.
today и now
value="today" — текущая дата; value="now" — текущая дата и время. Оба
читают часы runtime, поэтому это естественные метки для полей «сформировано» или «по
состоянию на».
<gen type="date" value="today" format="LL" local="ru"/>
<gen type="date" value="now" format="YYYY-MM-DDTHH:mm:ss.SSS"/>
value="today" format="LL" local="ru" 23 апреля 2026 г. value="now" format="YYYY-MM-DDTHH:mm:ss.SSS" 2026-04-23T12:00:00.000
Чтение часов — в этом и смысл обоих, и именно поэтому они невоспроизводимы: сид никак
не влияет на то, какое сегодня число. Зафиксируйте часы через
--now — и today с now в каждом
прогоне вернут названный вами момент.
precision — шаг для дата-временны́х диапазонов
precision задаёт наименьший шаг, которым движется диапазон: day, second или
millisecond. Для пятисекундного окна с шагом в целые секунды:
<gen type="date"
from="2026-05-02T09:00:00"
to="2026-05-02T09:00:05"
precision="second"
format="YYYY-MM-DDTHH:mm:ss"/>
2026-05-02T09:00:04 2026-05-02T09:00:01 2026-05-02T09:00:03 2026-05-02T09:00:00 2026-05-02T09:00:02
Если precision опущен, значение по умолчанию следует типу диапазона:
| Тип диапазона | Шаг по умолчанию | Что меняет precision |
|---|---|---|
только дата (YYYY-MM-DD) | один день | нужен редко — тут и так целые дни |
| дата-время | одна миллисекунда | precision="second" обнуляет миллисекунды |
Используйте precision="second", когда нужны чистые, «человеческие» метки времени
вместо миллисекундного шума; используйте precision="millisecond" (значение
по умолчанию для дата-времени), когда нужна субсекундная точность.
Интервал: дата, отсчитанная от другой даты
Настоящие записи полны пар: поступил и выписан, заказал и отгрузили, выдан и действителен до, начало и конец смены. Вторая дата не независима от первой — она и есть первая плюс длительность, — и два отдельных диапазона этого сказать не могут. Они ставят выписку раньше поступления в изрядной доле строк.
of называет колонку, от которой отсчитывать, а plus — насколько далеко:
<sequence name="Admitted">
<gen type="date" from="2026-01-01" to="2026-03-01" format="YYYY-MM-DD"/>
</sequence>
<sequence name="Discharged">
<gen type="date" of="Admitted" plus="2..14d" format="YYYY-MM-DD"/>
</sequence>
2026-02-06 2026-02-16 2026-02-14 2026-02-23 2026-01-11 2026-01-16 2026-01-11 2026-01-24 2026-02-27 2026-03-06 2026-01-08 2026-01-14
Каждая выписка позже своего поступления, на 2–14 дней — и длительность каждого пребывания разыгрывается для строки отдельно, а именно это два независимых диапазона и выбрасывают.
plus — расстояние
| Запись | Что значит |
|---|---|
7d | ровно семь дней, в каждой строке |
3..10d | от трёх до десяти дней, розыгрыш на строку (границы включены) |
1..3mo | от одного до трёх месяцев, по календарю |
-10..-3d | от трёх до десяти дней раньше источника |
45 | голое число означает дни |
Length m | число из колонки Length, в минутах, в каждой строке своё |
Единицы те же, что у step:
s, m, h, d, w, mo, y — и так же m — это минута, а mo — месяц.
Одно значение — одно и то же расстояние в каждой строке:
<sequence name="Shipped">
<gen type="date" of="Ordered" plus="1d" format="YYYY-MM-DD"/>
</sequence>
2026-05-23 2026-05-24 2026-05-06 2026-05-07 2026-05-13 2026-05-14 2026-05-21 2026-05-22
Меньшая граница пишется первой, как и в любом другом диапазоне. Чтобы отсчитывать
назад, сделайте обе границы отрицательными: plus="-10..-3d" — это от трёх до
десяти дней раньше. plus="10..3d" — опечатка, и она отвергается (TDC264), а не
тихо переворачивается.
Месяцы и годы двигаются по календарю, а не фиксированным числом дней, поэтому
2026-01-31 плюс месяц — это 2026-02-28: то же поджатие, что делает
step.
Расстояние из другой колонки
Конец приёма — это его начало плюс его собственная длительность, а длительность у каждой строки своя: литерал — одно и то же расстояние везде, а диапазон разыгрывается, а не читается. Напишите имя колонки и единицу — и расстояние будет читаться из этой колонки, строка за строкой:
<sequence name="Start">
<gen type="date" from="2026-03-02T08:00" to="2026-03-02T17:00" format="HH:mm"/>
</sequence>
<sequence name="Length"><gen type="text" value="15,30,45,60"/></sequence>
<sequence name="End">
<gen type="date" of="Start" plus="Length m" format="HH:mm"/>
</sequence>
09:26–10:11 (45 min) 09:45–10:45 (60 min) 15:37–15:52 (15 min) 11:39–12:09 (30 min)
Минус в начале считает назад — plus="-Length m" даёт время, когда начинать подготовку, — а
голое имя означает дни, как и голое число. Поле ссылки на пул — такая
же колонка: plus="Room.turnover m". Колонка должна быть объявлена выше этой, как и для of,
и держать одно число на строку (TDC240). Ничего не разыгрывается, поэтому такое смещение не
сдвигает другие колонки.
В каждой ячейке должно быть целое число. Строка с пустой ячейкой — например, её очистил
missing — остаётся без даты, как и строка без исходной даты.
Дробь останавливает прогон с номером строки: 1.5 часа — это девяносто минут, а округление до
одного или двух часов дало бы неверное время в ячейке, которая выглядит правильно. Считайте в
единице помельче.
Смещение читает значение, а не напечатанный текст
Колонка дат печатает представление своей даты. 03/02/2026 — это 3 февраля при
local="en" и 2 марта при local="ru", а format="MMMM D" вообще выбрасывает
год. Поэтому смещение не читает ячейку вовсе: колонка, от которой оно
отсчитывает, хранит саму сгенерированную дату, и арифметика идёт по ней. Любой
format и любая локаль подходят.
<env count="4" seed="visit" local="ru">
<sequence name="Visit"><gen type="date" from="2026-03-01" to="2026-03-31"/></sequence>
<sequence name="Followup"><gen type="date" of="Visit" plus="2w"/></sequence>
</env>
20.03.2026 03.04.2026 22.03.2026 05.04.2026 27.03.2026 10.04.2026 09.03.2026 23.03.2026
Единственный случай, когда читать нечего, — дата, которую TDC не генерировал:
например, колонка из file. Там есть только текст, поэтому он
должен быть в форме ISO (YYYY-MM-DD), которая означает одно и то же в любой
локали. Всё остальное отвергается, а не угадывается.
Источник может быть обходимым, разыгранным или другим смещением
of= читает всё, что произвела названная колонка. Обходимый источник — это как раз та
пара, которую настоящие записи просят чаще всего: заказы идут по календарю день за днём, а
доставка — через несколько дней после своего заказа:
<sequence name="Ordered">
<gen type="date" from="2026-01-01" order="sequential" step="1d" format="YYYY-MM-DD"/>
</sequence>
<sequence name="Delivered">
<gen type="date" of="Ordered" plus="2..9d" format="YYYY-MM-DD"/>
</sequence>
2026-01-01 2026-01-06 2026-01-02 2026-01-06 2026-01-03 2026-01-12 2026-01-04 2026-01-11
Единственный источник, от которого отсчитывать не от чего, — повторяющийся: ячейка,
собранная через repeat=, содержит несколько дат через разделитель. Такое отвергается по
имени, а не отвечается пустой колонкой.
Цепочки и пустые ячейки
Смещение само по себе — дата, которую произвёл движок, так что от неё может отсчитывать третья колонка: подписан, истекает через год, напомнить за месяц до того.
<sequence name="Signed"><gen type="date" from="2026-01-15" to="2026-02-15" format="D MMMM YYYY"/></sequence>
<sequence name="Expires"><gen type="date" of="Signed" plus="1y" format="D MMMM YYYY"/></sequence>
<sequence name="Remind"><gen type="date" of="Expires" plus="-30d" format="D MMMM YYYY"/></sequence>
5 February 2026 | 5 February 2027 | 6 January 2027 31 January 2026 | 31 January 2027 | 1 January 2027 13 February 2026 | 13 February 2027 | 14 January 2027 20 January 2026 | 20 January 2027 | 21 December 2026
Строка, у которой в источнике нет даты — та, что отсеял фильтр parent, или та,
которую обнулил missing, — не получает даты и
здесь. Отсчитывать не от чего, а придумать значение означало бы поставить
уверенно выглядящую дату в ячейку, которая по конфигурации должна быть пустой.
В ветке
Смещение читает только свою строку, поэтому оно тоже может быть одной из веток построчного
выбора: <case> на любой глубине или
одной из веток <gen if="…"> последовательности. Каждая строка ветки отмеряется от своей даты.
<tdc>
<env count="6" seed="ship" local="ru">
<sequence name="Ordered"><gen type="date" from="2026-03-01" to="2026-03-31" format="D MMMM"/></sequence>
<sequence name="Method"><gen type="text" value="курьер,самовывоз"/></sequence>
<switch name="Ready" on="Method">
<case is="курьер"><gen type="date" of="Ordered" plus="2..5d" format="D MMMM"/></case>
<case is="самовывоз"><data>в тот же день, на стойке</data></case>
</switch>
</env>
<block><line><data>${{Ordered}} | ${{Method}} | ${{Ready}}</data></line></block>
</tdc>
23 марта | курьер | 27 марта 6 марта | курьер | 11 марта 13 марта | самовывоз | в тот же день, на стойке 21 марта | самовывоз | в тот же день, на стойке 7 марта | самовывоз | в тот же день, на стойке 17 марта | курьер | 19 марта
Диапазон в plus= внутри ветки берёт шаг каждой строки из её собственного потока, поэтому
строка сохраняет свой шаг, когда меняется раскладка ветки вокруг неё.
Что исключает of
of ставит дату относительно другой колонки, поэтому атрибуты, задающие
собственный жребий генератора, больше ничего не значат: value, from, to,
range, oldest, youngest, order и step. Написанный рядом с of, любой из
них отвергается (TDC264), а не игнорируется: конфигурация, которая просит
июньские даты и получает январские, права насчёт того, о чём просила, и не права
насчёт того, что получила.
Колонка, названная в of, должна быть объявлена выше смещения (TDC240) —
то же правило, что у running и stat.
Смещение — колонка, вычисленная из другой, поэтому оно не бывает частью или полем составной
<sequence> (TDC295): части записи разыгрываются вместе, а вычисленная дата, переехавшая на
другую строку, эту строку больше не описывает. Объявите его отдельной последовательностью.
Слой форматирования исключён по той же причине, по какой он исключён у бегущего итога:
смещение строится в порядке объявления, до того как этот слой запускается. mask,
case, missing, missing_as, repeat, anomaly, anomaly_factor и percent
отказываются (TDC015), а не игнорируются. Применяйте их там, где значение
печатается — ${{Later|mask:x}}, ${{Later|upper}}: там они работают и сейчас.
Обычный type="date" без of читает каждый из них как обычно; не может именно
смещение.
Смещение читает соседнюю колонку по ходу сборки строки, чего потоковый путь пока
не умеет, поэтому конфигурация со смещением собирается
в памяти. TDC направляет её туда сам; заметить это
можно, только если принудительно взять потоковый движок через --engine 2 — он
откажет по имени, а не станет приближать.
Форматирование вывода
format — это шаблон из маркеров. Он меняет только то, как дата записана, —
само значение не трогается. По умолчанию — L (локаль-зависимая короткая дата).
Все маркеры на одном зафиксированном моменте — вторник 5 марта 2024, 09:04:07. День и месяц взяты однозначными нарочно, чтобы пары «с нулём / без нуля» отличались на глаз:
| Маркер | Значение | Пример |
|---|---|---|
YYYY | год из 4 цифр | 2024 |
YY | год из 2 цифр | 24 |
MMMM | полное имя месяца | March |
MMM | короткое имя месяца | Mar |
MM | месяц из 2 цифр | 03 |
M | месяц без ведущего нуля | 3 |
DD | день из 2 цифр | 05 |
D | день без ведущего нуля | 5 |
dddd | полное имя дня недели | Tuesday |
ddd | короткое имя дня недели | Tue |
HH | час из 2 цифр (24ч) | 09 |
H | час без ведущего нуля | 9 |
mm | минута из 2 цифр | 04 |
m | минута без ведущего нуля | 4 |
ss | секунда из 2 цифр | 07 |
s | секунда без ведущего нуля | 7 |
SSS | миллисекунды | 000 |
Z | смещение UTC с двоеточием | +00:00 |
ZZ | смещение UTC без двоеточия | +0000 |
ISO | дата в формате ISO 8601 | 2024-03-05 |
ISO_TIME | дата и время в ISO 8601 | 2024-03-05T09:04:07 |
L | локаль-зависимая короткая дата | 03/05/2024 |
LL | локаль-зависимая длинная дата | March 5, 2024 |
LLL | длинная дата со временем | March 5, 2024 09:04 |
LLLL | она же с днём недели | Tuesday, March 5, 2024 09:04 |
Каждое имя из таблицы сочетается с остальными. LL [at] HH:mm даёт
March 5, 2024 at 00:00; именованные формы — не ключевые слова, работающие только
поодиночке.
Буква, похожая на токен, но токеном не являющаяся, — ошибка, а не текст. hh:mm A —
это 12-часовые часы и метка AM/PM из Moment, которых у TDC нет; раньше они печатали сами
себя — hh:00 A, — и прогон молчал. Теперь это не проходит check и говорит, что делать:
error[TDC152]: date format: "hh" is not a token — write it as [hh] if it is meant to be literal text
Обычные слова не затронуты — их буквы не входят в набор токенов: DD of MM по-прежнему
даёт 05 of 03. Всё, что нужно сохранить дословно, берите в скобки — это и так правило
ниже.
mm — это минуты; месяц — MM. %m и написанный от руки yyyy-mm-dd означают месяц,
так что YYYY-mm-DD — лёгкая описка, и у даты без времени она печатает 2025-00-24 в каждой
строке. Формат с минутами, рядом с которыми нет ни часа, ни секунд, получает
предупреждение; HH:mm и mm:ss не трогаются:
warning[TDC310]: "mm" in format="YYYY-mm-DD" is minutes, and nothing else here is a time of day
Имена месяцев и дней недели, а также четыре формы L, следуют локали — см.
ниже. Всё остальное одинаково на любом языке.
Одна и та же дата в четырёх форматах — сид один, поэтому дата в каждой строке одинакова, различается только запись:
<gen type="date" value="2020-01-01..2024-12-31" format="YYYY-MM-DD"/>
<gen type="date" value="2020-01-01..2024-12-31" format="DD.MM.YYYY"/>
<gen type="date" value="2020-01-01..2024-12-31" format="DD MMM YYYY"/>
<gen type="date" value="2020-01-01..2024-12-31" format="LL"/>
YYYY-MM-DD DD.MM.YYYY DD MMM YYYY LL 2023-11-08 08.11.2023 08 Nov 2023 November 8, 2023 2021-09-30 30.09.2021 30 Sep 2021 September 30, 2021 2020-05-23 23.05.2020 23 May 2020 May 23, 2020
Литеральный текст в скобках
Всё, что в квадратных скобках, копируется в вывод дословно, поэтому дату можно обернуть в фиксированный текст:
<gen type="date" value="2024-03-15..2024-03-15" format="[дата:] YYYY-MM-DD"/>
дата: 2024-03-15
Локаль-зависимые форматы: L и LL
L, LL, LLL и LLLL следуют локали, взятой из атрибута local (или local на
<env>), — как и маркеры имён MMMM, MMM, dddd и ddd.
Локаль по умолчанию — en. Числовые шаблоны вроде
YYYY-MM-DD и DD.MM.YYYY никогда не зависят от локали — только от написанного вами
шаблона.
Откуда берутся слова: двадцать четыре локали встроены в движок, а любая другая, чей
пак данных возит DATE_LOCALE.json — таких семьдесят, — переводит свои даты, как
только пак виден. Грузинский, латышский, казахский и им подобные теперь печатают свои
месяцы и дни недели, включая падежную форму месяца в дате (15 იანვარს), — раньше они
молча падали в английский. Файл возит L и LL; LLL и LLLL берутся из него, если
записаны, и выводятся иначе — LL плюс время, день недели впереди. Локаль совсем без
слов дат по-прежнему печатает английский, и валидатор говорит об этом вслух, а не
пропускает молча.
Вот фиксированная дата 2024-03-15 под format="LL", сначала в локали по умолчанию
(en), затем та же дата, перерисованная с local="ru", чтобы показать
локализованное имя месяца и длинную форму, — намеренная демонстрация локализации:
<gen type="date" value="2024-03-15..2024-03-15" format="LL"/> <!-- по умолчанию en -->
<gen type="date" value="2024-03-15..2024-03-15" format="LL" local="ru"/> <!-- русская -->
по умолчанию (en) March 15, 2024 local="ru" 15 марта 2024 г.
L смещается так же: 03/15/2024 в en, 15.03.2024 в ru.
Подводные камни, всё в одном месте
- Входные даты парсятся строго — используйте
YYYY-MM-DD(или.//), а не свободный текст. - Обе границы диапазона включены.
value,rangeиfrom/to— три написания одного окна, берите то, что читается лучше.L/LLменяются сlocal;YYYY-MM-DDи подобные — нет.- Диапазоны только из дат шагают по дням; дата-временны́е — по миллисекундам, если не задан
precision. order="sequential"ОБХОДИТ диапазон; без него каждая строка — самостоятельный розыгрыш.- На обходимой оси
m— это минута, аmo— месяц.step="1mo15d"отвергается: пишите45dили1mo. weekdaysфильтрует,stepзадаёт темп. Они складываются, и одно не заменяет другое.today,now,value="birth"и генератор без границ читают часы, поэтому одним сидом их не воспроизвести — фиксируйте часы через--now.ofотсчитывает от другой колонки, аplusговорит насколько. Названная колонка должна быть объявлена выше, а атрибуты, ограничивающие собственный жребий генератора (from,to,value,range,order,step,oldest,youngest), рядом с ним отвергаются.- Смещение работает от даты, которую сгенерировала колонка-источник, а не от напечатанного
ею текста, поэтому подходят любой
formatи любая локаль. Только дата, которую TDC не генерировал — прочитанная из файла, — обязана быть в форме ISO. formatприменяется только к датам. На шаблонных идентификаторах (ИНН, СНИЛС, телефон…) это ошибка — оформляйте их фильтрами интерполяции.