Перейти к основному содержимому

Генератор date

Когда брать. Нужна дата или дата-время — день рождения, дата документа, метка времени события — в заданном диапазоне и в нужном формате вывода.

Даты работают на собственном переносимом рантайме дат TDC: строгий парсер, UTC-календарь и локализованный форматтер, без зависимости от moment.js. Один и тот же конфиг рассчитан на одинаковые даты во всех реализациях.

Примеры вывода ниже иллюстративны — точные значения зависят от сида и могут отличаться между версиями ядра. Неизменны форма и формат.

Кратко

АтрибутЧто делает
valuebirth, today, now, одна дата или диапазон START..END
rangeДиапазон START..END — более новое написание той же идеи
from / toДве границы диапазона, заданные по отдельности
ordersequential обходит диапазон вместо выбора из него — см. Ось дат
stepНасколько сдвигается каждая строка на обходимой оси: 15m, 1h30m, 2d, 3mo, 1y
weekdaysКакие дни недели оставляет обходимая ось: mon..fri, sun,wed
cyclefalse отказывает вместо зацикливания, когда обходимый ОГРАНИЧЕННЫЙ диапазон исчерпан
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)
precisionday, 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"/>
./run demo.tdc (5 строк)
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"/>
./run demo.tdc (6 строк)
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"/>
./run demo.tdc (5 строк)
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"/>
./run demo.tdc (5 строк)
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"/>
./run demo.tdc — тот же сид, с разницей в год
--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"/>
./run axis.tdc (count=5)
2026-01-01
2026-01-02
2026-01-03
2026-01-04
2026-01-05

Поднимите count до миллиона — ось просто пройдёт миллион дней. Ничего не разворачивается в список, поэтому диапазон не стоит памяти, какой бы длинный он ни был.

step — насколько сдвигается каждая строка

По умолчанию — один день. step принимает число и единицу, и единицы складываются:

ЗаписьОзначаетГруппа
15m15 минутфиксированная
1h30m90 минутфиксированная
2 или 2d2 дняфиксированная
1w7 днейфиксированная
3mo3 календарных месяцакалендарная
1y6mo18 календарных месяцевкалендарная

m — это минута, как и во всякой записи такого вида. Месяц — это mo, потому что m занято; и не M, потому что разница в сорок четыре тысячи раз между тремя минутами и тремя месяцами не должна держаться на регистре одной буквы.

<gen type="date" from="2026-01-01T09:00:00" order="sequential"
step="15m" format="YYYY-MM-DD HH:mm"/>
./run axis.tdc (count=4)
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"/>
./run axis.tdc (count=4)
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"/>
./run axis.tdc (count=6)
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"/>
./run axis.tdc (count=6)
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"/>
./run axis.tdc (count=7)
2026-01-01
2026-01-02
2026-01-03
2026-01-01
2026-01-02
2026-01-03
2026-01-01

cycle="false" превращает исчерпание в отказ:

./run axis.tdc (диапазон из 2 дней, count=4, 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"/>
./run demo.tdc (5 строк)
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"/>
./run demo.tdc
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"/>
./run demo.tdc (5 строк)
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>
./run stay.tdc (6 строк)
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голое число означает дни

Единицы те же, что у 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>
./run ship.tdc (4 строки)
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.

Смещение читает значение, а не напечатанный текст

Колонка дат печатает представление своей даты. 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>
./run visit.tdc (4 строки)
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>
./run orders.tdc (4 строки)
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>
./run lease.tdc (4 строки)
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, — не получает даты и здесь. Отсчитывать не от чего, а придумать значение означало бы поставить уверенно выглядящую дату в ячейку, которая по конфигурации должна быть пустой.

Что исключает of

of ставит дату относительно другой колонки, поэтому атрибуты, задающие собственный жребий генератора, больше ничего не значат: value, from, to, range, oldest, youngest, order и step. Написанный рядом с of, любой из них отвергается (TDC264), а не игнорируется: конфигурация, которая просит июньские даты и получает январские, права насчёт того, о чём просила, и не права насчёт того, что получила.

Колонка, названная в of, должна быть объявлена выше смещения (TDC240) — то же правило, что у running и stat. Слой форматирования исключён по той же причине, по какой он исключён у бегущего итога: смещение строится в порядке объявления, до того как этот слой запускается. 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 86012024-03-05
ISO_TIMEдата и время в ISO 86012024-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. Всё, что нужно сохранить дословно, берите в скобки — это и так правило ниже.

Имена месяцев и дней недели, а также четыре формы 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"/>
./run demo.tdc
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"/>
./run demo.tdc
дата: 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"/> <!-- русская -->
./run demo.tdc
по умолчанию (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 применяется только к датам. На шаблонных идентификаторах (ИНН, СНИЛС, телефон…) это ошибка — оформляйте их фильтрами интерполяции.

См. также

  • format, range и local в справочнике атрибутов.
  • Шаблоныperson.b_day и date.range используют то же форматирование дат.