DateTime

Модуль DateTime предоставляет набор функций для работы с датами и временем в YDB. Они поддерживают все доступные типы данных временных меток и интервалов как с базовым диапазоном допустимых значений, так и с расширенным. Кроме того, эти функции используют собственное внутреннее представление значений, в котором каждое значение разбивается на отдельные компоненты. Это представление описано ниже.

Самые простые операции с временными метками и интервалами можно выполнять и без использования модуля DateTime. Например, преобразование между строками и временными метками по ISO 8601 доступно через CAST, изменить точность временной метки также можно с помощью CAST, а между временными метками и интервалами работают арифметические операторы. Модуль DateTime предназначен для задач, где этих базовых операций недостаточно и требуются более сложные преобразования.

Внутренний формат представления

Большинство функций модуля DateTime оперируют не исходными временными метками и интервалами, а внутренним представлением, основанным на специальном типе данных ресурс. Оно представляет собой указатель на структуру данных в памяти, где компоненты времени хранятся раздельно. Работа с ресурсом происходит исключительно через функции модуля DateTime. Типовой сценарий работы с этим модулем (примеры см. в конце статьи) следующий:

  1. Вызвать функцию Split, чтобы получить из исходной временной метки внутреннее представление, либо Parse..., чтобы получить его из строки.

  2. При необходимости вызвать функции, модифицирующие это внутреннее представление нужным образом, например Shift..., StartOf... или Update....

  3. Вызвать одну из функций для создания нового значения на основе внутреннего представления, которое уже можно сохранять в таблицы или возвращать из запроса:

    • Make..., чтобы создать из внутреннего представления новую временную метку (не обязательно той же точности, что и исходная);
    • Format, чтобы получить строковое представление;
    • Get..., чтобы получить отдельные компоненты.

В YDB поддерживается два диапазона допустимых значений временных меток: базовый и расширенный. В модуле DateTime им соответствуют два отдельных внутренних представления: Resource<TM> для базовых типов данных и Resource<TM64> для типов данных с расширенным диапазоном допустимых значений.

Resource<TM> и Resource<TM64> содержат следующие компоненты дат:

  • Year (для Resource<TM> 12 бит, беззнаковый; для Resource<TM64> 19 бит, знаковый);
  • Month (4 бита);
  • Day (5 бит);
  • Hour (5 бит);
  • Minute (6 бит);
  • Second (6 бит);
  • Microsecond (20 бит);
  • TimezoneId (16 бит);
  • DayOfYear (9 бит) — день от начала года;
  • WeekOfYear (6 бит) — неделя от начала года, 1 января всегда относится к первой неделе;
  • WeekOfYearIso8601 (6 бит) — неделя года согласно ISO 8601 (первой неделей считается та, в которой 4 января);
  • DayOfWeek (3 бита) — день недели.

Если таймзона не GMT, то в компонентах хранится локальное время в соответствующей таймзоне.

Split

Преобразование из простого типа YDB во внутреннее представление модуля DateTime. Преобразование всегда выполняется успешно, при условии что на вход функции подаётся требуемое значение.

Список функций

  • DateTime::Split(Date/TzDate/Datetime/TzDatetime/Timestamp/TzTimestamp{Flags:AutoMap}) -> Resource<TM>;
  • DateTime::Split(Date32/TzDate32/Datetime64/TzDatetime64/Timestamp64/TzTimestamp64{Flags:AutoMap}) -> Resource<TM64>.

Функции, принимающие на вход Resource<TM> или Resource<TM64>, могут быть вызваны непосредственно от простого типа даты/времени. В этом случае будет сделано неявное преобразование через вызов соответствующей функции Split.

Make...

Сборка простого типа YDB из внутреннего представления модуля DateTime. Преобразование всегда выполняется успешно, если на вход функции подаётся требуемое значение.

Список функций

  • DateTime::MakeDate(Resource<TM>{Flags:AutoMap}) -> Date
  • DateTime::MakeDate32(Resource<TM64>{Flags:AutoMap}) -> Date32;
  • DateTime::MakeTzDate32(Resource<TM64>{Flags:AutoMap}) -> TzDate32;
  • DateTime::MakeDatetime(Resource<TM>{Flags:AutoMap}) -> Datetime;
  • DateTime::MakeTzDatetime(Resource<TM>{Flags:AutoMap}) -> TzDatetime;
  • DateTime::MakeDatetime64(Resource<TM64>{Flags:AutoMap}) -> Datetime64;
  • DateTime::MakeTzDatetime64(Resource<TM64>{Flags:AutoMap}) -> TzDatetime64;
  • DateTime::MakeTimestamp(Resource<TM>{Flags:AutoMap}) -> Timestamp;
  • DateTime::MakeTzTimestamp(Resource<TM>{Flags:AutoMap}) -> TzTimestamp;
  • DateTime::MakeTimestamp64(Resource<TM64>{Flags:AutoMap}) -> Timestamp64;
  • DateTime::MakeTzTimestamp64(Resource<TM64>{Flags:AutoMap}) -> TzTimestamp64.

Примеры

SELECT
    DateTime::MakeTimestamp(DateTime::Split(Datetime("2019-01-01T15:30:00Z"))),
      -- 2019-01-01T15:30:00.000000Z
    DateTime::MakeDate(Datetime("2019-01-01T15:30:00Z")),
      -- 2019-01-01
    DateTime::MakeTimestamp(DateTime::Split(TzDatetime("2019-01-01T00:00:00,Europe/Moscow"))),
      -- 2018-12-31T21:00:00Z (конвертация в UTC)
    DateTime::MakeDate(TzDatetime("2019-01-01T12:00:00,GMT"))
      -- 2019-01-01 (Datetime -> Date с неявным Split)

Get...

Получение компоненты внутреннего представления.

Список функций

  • DateTime::GetYear(Resource<TM>{Flags:AutoMap}) -> Uint16;
  • DateTime::GetYear(Resource<TM64>{Flags:AutoMap}) -> Int32;
  • DateTime::GetDayOfYear(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> Uint16;
  • DateTime::GetMonth(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> Uint8;
  • DateTime::GetMonthName(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> String;
  • DateTime::GetWeekOfYear(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> Uint8;
  • DateTime::GetWeekOfYearIso8601(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> Uint8;
  • DateTime::GetDayOfMonth(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> Uint8;
  • DateTime::GetDayOfWeek(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> Uint8;
  • DateTime::GetDayOfWeekName(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> String;
  • DateTime::GetHour(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> Uint8;
  • DateTime::GetMinute(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> Uint8;
  • DateTime::GetSecond(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> Uint8;
  • DateTime::GetMillisecondOfSecond(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> Uint32;
  • DateTime::GetMicrosecondOfSecond(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> Uint32;
  • DateTime::GetTimezoneId(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> Uint16;
  • DateTime::GetTimezoneName(Resource<TM>/Resource<TM64>{Flags:AutoMap}) -> String.

Примеры

$tm = DateTime::Split(TzDatetime("2019-01-09T00:00:00,Europe/Moscow"));

SELECT
    DateTime::GetDayOfMonth($tm) as Day, -- 9
    DateTime::GetMonthName($tm) as Month, -- "January"
    DateTime::GetYear($tm) as Year, -- 2019
    DateTime::GetTimezoneName($tm) as TzName, -- "Europe/Moscow"
    DateTime::GetDayOfWeekName($tm) as WeekDay; -- "Wednesday"

Update

Обновление одной или нескольких компонент во внутреннем представлении. Возвращает либо обновлённую копию, либо NULL, если после обновления получается некорректная дата или возникают другие противоречия.

Список функций

DateTime::Update(Resource<TM>{Flags:AutoMap}, [ Year:Uint16?, Month:Uint8?, Day:Uint8?, Hour:Uint8?, Minute:Uint8?, Second:Uint8?, Microsecond:Uint32?, Timezone:String? ]) -> Resource<TM>?
DateTime::Update(Resource<TM64>{Flags:AutoMap}, [ Year:Int32?, Month:Uint8?, Day:Uint8?, Hour:Uint8?, Minute:Uint8?, Second:Uint8?, Microsecond:Uint32?, Timezone:String? ]) -> Resource<TM64>?

Примеры

$tm = DateTime::Split(Timestamp("2019-01-01T01:02:03.456789Z"));

SELECT
    DateTime::MakeDate(DateTime::Update($tm, 2012)), -- 2012-01-01
    DateTime::MakeDate(DateTime::Update($tm, 2000, 6, 6)), -- 2000-06-06
    DateTime::MakeDate(DateTime::Update($tm, NULL, 2, 30)), -- NULL (30 февраля)
    DateTime::MakeDatetime(DateTime::Update($tm, NULL, NULL, 31)), -- 2019-01-31T01:02:03Z
    DateTime::MakeDatetime(DateTime::Update($tm, 15 as Hour, 30 as Minute)), -- 2019-01-01T15:30:03Z
    DateTime::MakeTimestamp(DateTime::Update($tm, 999999 as Microsecond)), -- 2019-01-01T01:02:03.999999Z
    DateTime::MakeTimestamp(DateTime::Update($tm, "Europe/Moscow" as Timezone)), -- 2018-12-31T22:02:03.456789Z (конвертация в UTC)
    DateTime::MakeTzTimestamp(DateTime::Update($tm, "Europe/Moscow" as Timezone)); -- 2019-01-01T01:02:03.456789,Europe/Moscow

From...

Получение Timestamp из количества секунд/миллисекунд/микросекунд от начала эпохи в UTC. При выходе за границы Timestamp возвращается NULL.

Список функций

  • DateTime::FromSeconds(Uint32{Flags:AutoMap}) -> Timestamp;
  • DateTime::FromSeconds64(Int64{Flags:AutoMap}) -> Timestamp64;
  • DateTime::FromMilliseconds(Uint64{Flags:AutoMap}) -> Timestamp;
  • DateTime::FromMilliseconds64(Int64{Flags:AutoMap}) -> Timestamp64;
  • DateTime::FromMicroseconds(Uint64{Flags:AutoMap}) -> Timestamp;
  • DateTime::FromMicroseconds64(Int64{Flags:AutoMap}) -> Timestamp64.

To...

Получение количества секунд/миллисекунд/микросекунд от начала эпохи в UTC из простого типа.

Список функций

  • DateTime::ToSeconds(Date/Datetime/Timestamp/TzDate/TzDatetime/TzTimestamp{Flags:AutoMap}) -> Uint32;
  • DateTime::ToSeconds(Date32/Datetime64/Timestamp64/TzDate32/TzDatetime64/TzTimestamp64{Flags:AutoMap}) -> Int64;
  • DateTime::ToMilliseconds(Date/Datetime/Timestamp/TzDate/TzDatetime/TzTimestamp{Flags:AutoMap}) -> Uint64;
  • DateTime::ToMilliseconds(Date32/Datetime64/Timestamp64/TzDate32/TzDatetime64/TzTimestamp64{Flags:AutoMap}) -> Int64;
  • DateTime::ToMicroseconds(Date/Datetime/Timestamp/TzDate/TzDatetime/TzTimestamp{Flags:AutoMap}) -> Uint64;
  • DateTime::ToMicroseconds(Date32/Datetime64/Timestamp64/TzDate32/TzDatetime64/TzTimestamp64{Flags:AutoMap}) -> Int64.

Примеры

SELECT
    DateTime::FromSeconds(1546304523), -- 2019-01-01T01:02:03.000000Z
    DateTime::ToMicroseconds(Timestamp("2019-01-01T01:02:03.456789Z")); -- 1546304523456789

Interval...

Преобразования между Interval и различными единицами измерения времени.

Список функций

  • DateTime::ToDays(Interval{Flags:AutoMap}) -> Int32;
  • DateTime::ToDays(Interval64{Flags:AutoMap}) -> Int32;
  • DateTime::ToHours(Interval{Flags:AutoMap}) -> Int32;
  • DateTime::ToHours(Interval64{Flags:AutoMap}) -> Int64;
  • DateTime::ToMinutes(Interval{Flags:AutoMap}) -> Int32;
  • DateTime::ToMinutes(Interval64{Flags:AutoMap}) -> Int64;
  • DateTime::ToSeconds(Interval{Flags:AutoMap}) -> Int64;
  • DateTime::ToSeconds(Interval64{Flags:AutoMap}) -> Int64;
  • DateTime::ToMilliseconds(Interval{Flags:AutoMap}) -> Int64;
  • DateTime::ToMilliseconds(Interval64{Flags:AutoMap}) -> Int64;
  • DateTime::ToMicroseconds(Interval{Flags:AutoMap}) -> Int64;
  • DateTime::ToMicroseconds(Interval64{Flags:AutoMap}) -> Int64;
  • DateTime::IntervalFromDays(Int32{Flags:AutoMap}) -> Interval;
  • DateTime::Interval64FromDays(Int32{Flags:AutoMap}) -> Interval64;
  • DateTime::IntervalFromHours(Int32{Flags:AutoMap}) -> Interval;
  • DateTime::Interval64FromHours(Int64{Flags:AutoMap}) -> Interval64;
  • DateTime::IntervalFromMinutes(Int32{Flags:AutoMap}) -> Interval;
  • DateTime::Interval64FromMinutes(Int64{Flags:AutoMap}) -> Interval64;
  • DateTime::IntervalFromSeconds(Int64{Flags:AutoMap}) -> Interval;
  • DateTime::Interval64FromSeconds(Int64{Flags:AutoMap}) -> Interval64;
  • DateTime::IntervalFromMilliseconds(Int64{Flags:AutoMap}) -> Interval;
  • DateTime::Interval64FromMilliseconds(Int64{Flags:AutoMap}) -> Interval64;
  • DateTime::IntervalFromMicroseconds(Int64{Flags:AutoMap}) -> Interval;
  • DateTime::Interval64FromMicroseconds(Int64{Flags:AutoMap}) -> Interval64.

AddTimezone никак не влияет на вывод ToSeconds(), поскольку ToSeconds() всегда возвращают время в таймзоне GMT.

Interval также можно создавать из строкового литерала в формате ISO 8601.

Важно

На данный момент поддерживаются только литералы для детерминированных интервалов. Все размерности больше недели — M (месяц) и Y (год) — не являются фиксированными, поскольку их продолжительность определяется только внешним контекстом, календарём.

AddTimezone никак не влияет на вывод ToSeconds(), поскольку ToSeconds() всегда возвращают время в таймзоне GMT.

Interval также можно создавать из строкового литерала в формате ISO 8601.

Примеры

SELECT
    DateTime::ToDays(Interval("PT3000M")), -- 2
    DateTime::IntervalFromSeconds(1000000), -- 11 days 13 hours 46 minutes 40 seconds
    DateTime::ToDays(CAST('2018-01-01' as date) - CAST('2017-12-31' as date)); --1

StartOf... / EndOf... / TimeOfDay

Получить начало (конец) периода, содержащего дату/время. При некорректном результате возвращается NULL. Если таймзона не GMT, то начало (конец) периода будет в указанной временной зоне.

Список функций

  • DateTime::StartOfYear(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::StartOfYear(Resource<TM64>{Flags:AutoMap}) -> Resource<TM64>?;
  • DateTime::EndOfYear(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::EndOfYear(Resource<TM64>{Flags:AutoMap}) -> Resource<TM64>?;
  • DateTime::StartOfQuarter(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::StartOfQuarter(Resource<TM64>{Flags:AutoMap}) -> Resource<TM64>?;
  • DateTime::EndOfQuarter(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::EndOfQuarter(Resource<TM64>{Flags:AutoMap}) -> Resource<TM64>?;
  • DateTime::StartOfMonth(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::StartOfMonth(Resource<TM64>{Flags:AutoMap}) -> Resource<TM64>?;
  • DateTime::EndOfMonth(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::EndOfMonth(Resource<TM64>{Flags:AutoMap}) -> Resource<TM64>?;
  • DateTime::StartOfWeek(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::StartOfWeek(Resource<TM64>{Flags:AutoMap}) -> Resource<TM64>?;
  • DateTime::EndOfWeek(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::EndOfWeek(Resource<TM64>{Flags:AutoMap}) -> Resource<TM64>?;
  • DateTime::StartOfDay(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::StartOfDay(Resource<TM64>{Flags:AutoMap}) -> Resource<TM64>?;
  • DateTime::EndOfDay(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::EndOfDay(Resource<TM64>{Flags:AutoMap}) -> Resource<TM64>?;
  • DateTime::StartOf(Resource<TM>{Flags:AutoMap}, Interval{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::StartOf(Resource<TM64>{Flags:AutoMap}, Interval64{Flags:AutoMap}) -> Resource<TM64>?;
  • DateTime::EndOf(Resource<TM>{Flags:AutoMap}, Interval{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::EndOf(Resource<TM64>{Flags:AutoMap}, Interval64{Flags:AutoMap}) -> Resource<TM64>?.

Функции StartOf/EndOf предназначены для группировки в пределах суток по произвольному периоду. Результат отличается от входного значения только компонентами времени. Период более суток трактуется как сутки (эквивалентно StartOfDay/EndOfDay). Если в сутках не содержится целого числа периодов, производится округление к ближайшему времени от начала суток, кратному указанному периоду. При нулевом интервале выход совпадает со входом. Отрицательный интервал трактуется как положительный.

Функции EndOf... предназначены для получения последнего момента времени, находящегося в том же выбранном интервале, что и заданный.

Поведение функций с периодами больше дня отличается от поведения одноимённых функций в старой библиотеке. Компоненты времени всегда обнуляются (это логично, поскольку эти функции в основном используются для группировки по периоду). Отдельно существует возможность выделить время в пределах суток:

  • DateTime::TimeOfDay(Resource<TM>{Flags:AutoMap}) -> Interval;
  • DateTime::TimeOfDay(Resource<TM64>{Flags:AutoMap}) -> Interval64.

Примеры

SELECT
    DateTime::MakeDate(DateTime::StartOfYear(Date("2019-06-06"))),
      -- 2019-01-01 (неявный Split здесь и дальше)
    DateTime::MakeDatetime(DateTime::StartOfQuarter(Datetime("2019-06-06T01:02:03Z"))),
      -- 2019-04-01T00:00:00Z (компоненты времени обнулены)
    DateTime::MakeDate(DateTime::StartOfMonth(Timestamp("2019-06-06T01:02:03.456789Z"))),
      -- 2019-06-01
    DateTime::MakeDate(DateTime::StartOfWeek(Date("1970-01-01"))),
      -- NULL (начало эпохи - четверг, начало недели - 1969-12-29, выход за границы)
    DateTime::MakeTimestamp(DateTime::StartOfWeek(Date("2019-01-01"))),
      -- 2018-12-31T00:00:00Z
    DateTime::MakeDatetime(DateTime::StartOfDay(Datetime("2019-06-06T01:02:03Z"))),
      -- 2019-06-06T00:00:00Z
    DateTime::MakeTzDatetime(DateTime::StartOfDay(TzDatetime("1970-01-01T05:00:00,Europe/Moscow"))),
      -- NULL (в GMT выход за эпоху)
    DateTime::MakeTzTimestamp(DateTime::StartOfDay(TzTimestamp("1970-01-02T05:00:00.000000,Europe/Moscow"))),
      -- 1970-01-02T00:00:00,Europe/Moscow (начало дня по Москве)
    DateTime::MakeDatetime(DateTime::StartOf(Datetime("2019-06-06T23:45:00Z"), Interval("PT7H"))),
      -- 2019-06-06T21:00:00Z
    DateTime::MakeDatetime(DateTime::StartOf(Datetime("2019-06-06T23:45:00Z"), Interval("PT20M"))),
      -- 2019-06-06T23:40:00Z
    DateTime::TimeOfDay(Timestamp("2019-02-14T01:02:03.456789Z"));
      -- 1 hour 2 minutes 3 seconds 456789 microseconds

Shift...

Прибавить/вычесть заданное количество единиц к компоненте во внутреннем представлении и обновить остальные поля.
Возвращает либо обновлённую копию, либо NULL, если после обновления получается некорректная дата или возникают другие противоречия.

Список функций

  • DateTime::ShiftYears(Resource<TM>{Flags:AutoMap}, Int32) -> Resource<TM>?;
  • DateTime::ShiftYears(Resource<TM64>{Flags:AutoMap}, Int32) -> Resource<TM64>?;
  • DateTime::ShiftQuarters(Resource<TM>{Flags:AutoMap}, Int32) -> Resource<TM>?;
  • DateTime::ShiftQuarters(Resource<TM64>{Flags:AutoMap}, Int32) -> Resource<TM64>?;
  • DateTime::ShiftMonths(Resource<TM>{Flags:AutoMap}, Int32) -> Resource<TM>?;
  • DateTime::ShiftMonths(Resource<TM64>{Flags:AutoMap}, Int32) -> Resource<TM64>?.

Если в результате номер дня в месяце превышает максимально возможный, то в поле Day будет записан последний день месяца,
время при этом не изменится (см. примеры).

Примеры

$tm1 = DateTime::Split(Datetime("2019-01-31T01:01:01Z"));
$tm2 = DateTime::Split(TzDatetime("2049-05-20T12:34:50,Europe/Moscow"));

SELECT
    DateTime::MakeDate(DateTime::ShiftYears($tm1, 10)), -- 2029-01-31T01:01:01
    DateTime::MakeDate(DateTime::ShiftYears($tm2, -10000)), -- NULL (выход за границы)
    DateTime::MakeDate(DateTime::ShiftQuarters($tm2, 0)), -- 2049-05-20T12:34:50,Europe/Moscow
    DateTime::MakeDate(DateTime::ShiftQuarters($tm1, -3)), -- 2018-04-30T01:01:01
    DateTime::MakeDate(DateTime::ShiftMonths($tm1, 1)), -- 2019-02-28T01:01:01
    DateTime::MakeDate(DateTime::ShiftMonths($tm1, -35)), -- 2016-02-29T01:01:01

Format

Получить строковое представление момента времени, используя произвольную строку форматирования.

Список функций

  • DateTime::Format(String, alwaysWriteFractionalSeconds:Bool?) -> (Resource<TM64>{Flags:AutoMap}) -> String

Поддерживается множество спецификаторов для строки форматирования:

  • %% - символ %;
  • %Y — год, 1–6 цифр и знак для дат до н.э.;
  • %m — месяц, 2 цифры;
  • %d — день, 2 цифры;
  • %H - час 2 цифры;
  • %M - минуты 2 цифры;
  • %S — секунды, 2 цифры или XX.XXXXXX, если есть микросекунды (и только если флаг alwaysWriteFractionalSeconds не установлен в True);
  • %z+hhmm или -hhmm;
  • %Z - IANA имя таймзоны;
  • %b - короткое трехбуквенное английское название месяца (Jan);
  • %B - полное английское название месяца (January).

Все остальные символы строки форматирования переносятся без изменений.

Примеры

$format = DateTime::Format("%Y-%m-%d %H:%M:%S %Z");

SELECT
    $format(DateTime::Split(TzDatetime("2019-01-01T01:02:03,Europe/Moscow")));
      -- "2019-01-01 01:02:03 Europe/Moscow"

Parse/Parse64

Парсит строку во внутреннее представление с использованием произвольной строки форматирования. Для незаполненных полей используются значения по умолчанию. При возникновении ошибок возвращается NULL.

Список функций

  • DateTime::Parse(String) -> (String{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::Parse64(String) -> (String{Flags:AutoMap}) -> Resource<TM64>?.

Реализованные спецификаторы:

  • %% - символ %;
  • %Y — год, 4 цифры — при использовании Parse, или 1–6 цифр и знак для дат до н.э. — при использовании Parse64;
  • %m — месяц, 2 цифры;
  • %d — день, 2 цифры;
  • %H — час, 2 цифры;
  • %M — минуты, 2 цифры;
  • %S — секунды, могут включать микросекунды в форматах от XX до XX.XXXXXX;
  • %Z — имя таймзоны в формате IANA (например, GMT);
  • %b — короткое трёхбуквенное регистронезависимое английское название месяца (например, Jan).
  • %B - полное регистронезависимое английское название месяца (January).

Примеры

$parse1 = DateTime::Parse("%H:%M:%S");
$parse2 = DateTime::Parse("%S");
$parse3 = DateTime::Parse("%m/%d/%Y");
$parse4 = DateTime::Parse("%Z");
$parse5 = DateTime::Parse64("%m/%d/%Y");

SELECT
    DateTime::MakeDatetime($parse1("01:02:03")), -- 1970-01-01T01:02:03Z
    DateTime::MakeTimestamp($parse2("12.3456")), -- 1970-01-01T00:00:12.345600Z
    DateTime::MakeTimestamp($parse3("02/30/2000")), -- NULL (Feb 30)
    DateTime::MakeTimestamp($parse4("Canada/Central")), -- 1970-01-01T06:00:00Z (конвертация в UTC)
    DateTime::MakeTimestamp64($parse5("02/10/1931")), -- 1931-02-10T00:00:00Z (конвертация в UTC)

Parse конкретных форматов

Для распространённых форматов есть врапперы вокруг соответствующих методов util. Можно получить только TM с компонентами в UTC таймзоне.

Список функций

  • DateTime::ParseRfc822(String{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::ParseIso8601(String{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::ParseHttp(String{Flags:AutoMap}) -> Resource<TM>?;
  • DateTime::ParseX509(String{Flags:AutoMap}) -> Resource<TM>?.

Примеры

SELECT
    DateTime::MakeTimestamp(DateTime::ParseRfc822("Fri, 4 Mar 2005 19:34:45 EST")),
      -- 2005-03-05T00:34:45Z
    DateTime::MakeTimestamp(DateTime::ParseIso8601("2009-02-14T02:31:30+0300")),
      -- 2009-02-13T23:31:30Z
    DateTime::MakeTimestamp(DateTime::ParseHttp("Sunday, 06-Nov-94 08:49:37 GMT")),
      -- 1994-11-06T08:49:37Z
    DateTime::MakeTimestamp(DateTime::ParseX509("20091014165533Z"))
      -- 2009-10-14T16:55:33Z

Типовые сценарии

Преобразования между строками и секундами

Преобразование строковой даты (в таймзоне Москвы) в секунды (в таймзоне GMT):

$datetime_parse = DateTime::Parse("%Y-%m-%d %H:%M:%S");
$datetime_parse_tz = DateTime::Parse("%Y-%m-%d %H:%M:%S %Z");

SELECT
    DateTime::ToSeconds(TzDatetime("2019-09-16T00:00:00,Europe/Moscow")) AS md_us1, -- 1568581200
    DateTime::ToSeconds(DateTime::MakeDatetime($datetime_parse_tz("2019-09-16 00:00:00" || " Europe/Moscow"))), -- 1568581200
    DateTime::ToSeconds(DateTime::MakeDatetime(DateTime::Update($datetime_parse("2019-09-16 00:00:00"), "Europe/Moscow" AS Timezone))), -- 1568581200
    -- НЕПРАВИЛЬНО (Date импортирует время как GMT, а AddTimezone никак не влияет на ToSeconds, которая всегда возвращает время в таймзоне GMT)
    DateTime::ToSeconds(AddTimezone(Date("2019-09-16"), 'Europe/Moscow')) AS md_us2, -- 1568592000

Преобразование строковой даты (в таймзоне Москвы) в секунды (в таймзоне Москвы). Поскольку DateTime::ToSeconds() экспортирует только GMT, придется временно забыть о таймзонах и работать только в GMT (выглядит это так, как будто временно мы считаем, что в Москве таймзона GMT):

$date_parse = DateTime::Parse("%Y-%m-%d");
$datetime_parse = DateTime::Parse("%Y-%m-%d %H:%M:%S");
$datetime_parse_tz = DateTime::Parse("%Y-%m-%d %H:%M:%S %Z");

SELECT
    DateTime::ToSeconds(Datetime("2019-09-16T00:00:00Z")) AS md_ms1, -- 1568592000
    DateTime::ToSeconds(Date("2019-09-16")) AS md_ms2, -- 1568592000
    DateTime::ToSeconds(DateTime::MakeDatetime($date_parse("2019-09-16"))) AS md_ms3, -- 1568592000
    DateTime::ToSeconds(DateTime::MakeDatetime($datetime_parse("2019-09-16 00:00:00"))) AS md_ms4, -- 1568592000
    DateTime::ToSeconds(DateTime::MakeDatetime($datetime_parse_tz("2019-09-16 00:00:00 GMT"))) AS md_ms5, -- 1568592000

    -- НЕПРАВИЛЬНО (импортирует время в таймзоне Москвы, а RemoveTimezone никак не влияет на ToSeconds)
    DateTime::ToSeconds(RemoveTimezone(TzDatetime("2019-09-16T00:00:00,Europe/Moscow"))) AS md_ms6, -- 1568581200
    DateTime::ToSeconds(DateTime::MakeDatetime($datetime_parse_tz("2019-09-16 00:00:00 Europe/Moscow"))) AS md_ms7 -- 1568581200

Преобразование секунд (в таймзоне GMT) в строковую дату (в таймзоне Москвы):

$date_format = DateTime::Format("%Y-%m-%d %H:%M:%S %Z");
SELECT
    $date_format(AddTimezone(DateTime::FromSeconds(1568592000), 'Europe/Moscow')) -- "2019-09-16 03:00:00 Europe/Moscow"

Преобразование секунд (в таймзоне Москвы) в строковую дату (в таймзоне Москвы). Здесь таймзона %Z выводится для справки - обычно выводить ее не нужно, потому что она будет равна "GMT" и может сбить с толку.

$date_format = DateTime::Format("%Y-%m-%d %H:%M:%S %Z");
SELECT
    $date_format(DateTime::FromSeconds(1568592000)) -- "2019-09-16 00:00:00 GMT"

Преобразование секунд (в таймзоне GMT) в трехбуквенное название дня недели (в таймзоне Москвы):

SELECT
    SUBSTRING(DateTime::GetDayOfWeekName(AddTimezone(DateTime::FromSeconds(1568581200), "Europe/Moscow")), 0, 3) -- "Mon"

Форматирование даты и времени

Обычно для форматирования времени используется отдельное именованное выражение, но можно обойтись и без него:

$date_format = DateTime::Format("%Y-%m-%d %H:%M:%S %Z");

SELECT

   -- Вариант с именованным выражением

   $date_format(AddTimezone(DateTime::FromSeconds(1568592000), 'Europe/Moscow')),

   -- Вариант без именованного выражения

   DateTime::Format("%Y-%m-%d %H:%M:%S %Z")
       (AddTimezone(DateTime::FromSeconds(1568592000), 'Europe/Moscow'))
;

Преобразование типов

Так можно преобразовывать только константы:

SELECT
    TzDatetime("2019-09-16T00:00:00,Europe/Moscow"), -- 2019-09-16T00:00:00,Europe/Moscow
    Date("2019-09-16") -- 2019-09-16

А так - константу, именованное выражение или поле таблицы:

SELECT
CAST("2019-09-16T00:00:00,Europe/Moscow" AS TzDatetime), -- 2019-09-16T00:00:00,Europe/Moscow
    CAST("2019-09-16" AS Date) -- 2019-09-16

Преобразование времени в дату

CAST в Date или TzDate дает такую дату в таймзоне GMT, в которую происходит полночь по локальному времени (например, для московского времени 2019-10-22 00:00:00, будет возвращена дата 2019-10-21). Для получения даты в локальной таймзоне можно использовать DateTime::Format.

$x = Datetime("2019-10-21T21:00:00Z");
SELECT
    AddTimezone($x, "Europe/Moscow"), -- 2019-10-22T00:00:00,Europe/Moscow
    CAST($x as TzDate), -- 2019-10-21,GMT
    CAST(AddTimezone($x, "Europe/Moscow") as TzDate), -- 2019-10-21,Europe/Moscow
    CAST(AddTimezone($x, "Europe/Moscow") as Date), -- 2019-10-21
  DateTime::Format("%Y-%m-%d %Z")(AddTimezone($x, "Europe/Moscow")), -- 2019-10-22 Europe/Moscow

Стоит отметить, что некоторые значения в типaх TzDatetime и TzTimestamp, имеющие положительное смещение таймзоны, не могут быть преобразованы в тип TzDate. Рассмотрим следующий пример:

SELECT CAST(TzDatetime("1970-01-01T23:59:59,Europe/Moscow") as TzDate);
/* Fatal: Timestamp 1970-01-01T23:59:59.000000,Europe/Moscow cannot be casted to TzDate */

Не существует такого значения, начиная с Unix epoch, которым можно представить полночь 01.01.1970 для московского времени. В результате, такое преобразование считается невозможным и генерирует ошибку времени выполнения.

В то же время, значения, имеющие отрицательное смещение таймзоны, возвращают корректный результат:

SELECT CAST(TzDatetime("1970-01-01T23:59:59,America/Los_Angeles") as TzDate);
/* 1970-01-01,America/Los_Angeles */

Летнее время

Обратите внимание, что летнее время зависит от года:

SELECT
    RemoveTimezone(TzDatetime("2019-09-16T10:00:00,Europe/Moscow")) as DST1, -- 2019-09-16T07:00:00Z
    RemoveTimezone(TzDatetime("2008-12-03T10:00:00,Europe/Moscow")) as DST2, -- 2008-12-03T07:00:00Z
    RemoveTimezone(TzDatetime("2008-07-03T10:00:00,Europe/Moscow")) as DST3, -- 2008-07-03T06:00:00Z (DST)
Предыдущая
Следующая