Разбирает строку времени по заданному формату

# DateTimeImmutable::createFromFormat

# date_create_immutable_from_format

(PHP 5 >= 5.5.0, PHP 7, PHP 8)

DateTimeImmutable::createFromFormat -- date_create_immutable_from_format — Разбирает строку времени по заданному формату

### Описание

Объектно-ориентированный стиль

public static function DateTimeImmutable::createFromFormat(string `$format`, string `$datetime`, ?DateTimeZone `$timezone` = `null`): DateTimeImmutable|false

Процедурный стиль

function date_create_immutable_from_format(string `$format`, string `$datetime`, ?DateTimeZone `$timezone` = `null`): DateTimeImmutable|false

Метод возвращает новый объект DateTimeImmutable, который представляет строку даты и времени `datetime` в формате `format`.

### Список параметров

`format`

  Формат даты и времени в виде строки (string), которому соответствует значение второго аргумента функции. Список параметров форматирования приводят следующие параграфы. В большей части случаев работают те же символы, что и для функции date().

  Метод инициализирует каждое поле текущей датой и временем системы. Поля часто приходится «обнулять» до значений начала эпохи Unix — `1970-01-01 00:00:00 UTC`. Поля, которые не указали в строке формата `format`, сбрасывают до начальных значений Unix-эпохи путём включения в начало строки формата символа `!` или в конец строки формата символа `|`. Подробнее о работе символов рассказывает документация к каждому параметру в таблице ниже.

  Метод анализирует формат слева направо, поэтому в отдельных случаях порядок расположения символов формата влияет на результат. Методу вначале требуется проанализировать год, например, через символы `Y` или `y`, если строка формата содержит символ `z`, для которого метод ищет день года.

  Символы для разбора чисел допускают широкий диапазон значений, который выходит за пределы логического диапазона. Например, символ `d`, для которого метод ищет в строке разбора день месяца, принимает значения в диапазоне от `00` до `99`. Единственное ограничение — количество цифр. При установке значения за пределами диапазона срабатывает механизм переполнения анализатора даты и времени. Примеры показывают поведение при переполнении.

  Метод разбирает данные для буквы формата в жадном режиме — считывает предельное для формата количество цифр, поэтому в строке `datetime` иногда не остаётся символов для следующих букв формата, и результат становится непредсказуемым. Пример на этой странице также иллюстрирует эту проблему.

  Список символов, которые распознаёт строка формата `format`
  Символ в строке `format` | Описание | Пример доступных для разбора значений
  --- | --- | ---
  День | --- | ---
  `d` и `j` | День месяца, 2 цифры с ведущим нулём или без него | От `01` до `31` или от `1` до `31`. Параметр принимает двузначные числа, которые превышают количество дней в месяце, тогда месяц переполняется и разница переносится на следующий месяц. Например, число 33 с январём означает 2 февраля
  `D` и `l` | Текстовое представление дня недели | От `Mon` до `Sun` или от `Sunday` до `Saturday`. Дата переполняется до следующей даты с заданным названием дня недели, если заданное название дня недели отличается от названия дня, который принадлежит разобранной дате (или дате по умолчанию). Примеры ниже содержат объяснение
  `S` | Английское наращение — суффикс для порядкового числительного, которое означает день месяца, 2 буквы. Метод пропустит эти буквы при разборе строки | `st`, `nd`, `rd` или `th`
  `z` | День года начиная с 0; перед параметром требуется указать параметр `Y` или `y` | От `0` до `365`. Параметр принимает трёхзначные числа, которые превышают количество дней в году, тогда год переполняется и разница переносится на следующий год. Например, число 366 с 2022 годом означает 2 января 2023 года
  Месяц | --- | ---
  `F` и `M` | Текстовое представление названия месяца, например January или Sept | С `January` по `December` или с `Jan` по `Dec`
  `m` и `n` | Числовое представление номера месяца в году с ведущим нулём или без него | От `01` до `12` или от `1` до `12`. Параметр принимает двузначные числа больше 12, тогда год переполняется и разница переносится на следующий год. Например, число 13 означает январь следующего года
  Год | --- | ---
  `X` и `x` | Полное числовое представление года длиной до 19 цифр с необязательным префиксом `+` или `-` | Примеры: `0055`, `787`, `1999`, `-2003`, `+10191`
  `Y` | Полное числовое представление года длиной до 4 цифр | Примеры: `25` (аналогично `0025`), `787`, `1999`, `2003`
  `y` | Двузначное представление года в диапазоне 1970-2069 включительно | Примеры: `99` или `03`, которые метод интерпретирует как `1999` и `2003`
  Время | --- | ---
  `a` и `A` | Ante meridiem (лат. «до полудня») или Post meridiem (лат. «после полудня») | Регистронезависимые обозначения `am` или `pm`
  `g` и `h` | 12-часовой формат часа с ведущим нулём или без него | От `1` до `12` или от `01` до `12`. Параметр принимает двузначные числа больше 12, тогда день переполняется и разница переносится на следующий день. Например, число `14` означает `02` часа следующего AM- или PM-периода
  `G` и `H` | 24-часовой формат часа с ведущим нулём или без него | От `0` до `23` или от `00` до `23`. Параметр принимает двузначные числа больше 24, тогда день переполняется и разница переносится на следующий день. Например, число `26` означает `02:00` следующего дня
  `i` | Минуты с ведущим нулём | От `00` до `59`. Параметр принимает двузначные числа больше 59, тогда час переполняется и разница переносится на следующий час. Например, число `66` означает `:06` минут следующего часа
  `s` | Секунды с ведущим нулём | От `00` до `59`. Параметр принимает двузначные числа больше 59, тогда час переполняется и разница переносится на следующую минуту. Например, число `90` означает `:30` секунд следующей минуты
  `v` | Миллисекунды длиной до 3 цифр | Примеры: `12` (`0.12` секунды), `345` (`0.345` секунды)
  `u` | Микросекунды длиной до 6 цифр | Примеры: `45` (`0.45` секунды), `654321` (`0.654321` секунды)
  Часовой пояс | --- | ---
  `e`, `O`, `p`, `P` и `T` | Идентификатор часового пояса, разница в часах относительно UTC, разница относительно UTC с двоеточием между часами и минутами или аббревиатура часового пояса | Примеры: `UTC`; `GMT`; `Atlantic/Azores`, `+0200`, `+02:00` или `EST`; `MDT`
  Полные дата и время | --- | ---
  `U` | Количество секунд с начала эпохи Unix — January 1 1970 00:00:00 GMT | Пример: `1292177455`
  Пробел и разделители | --- | ---
  `` (пробел) | Ноль или более символов пробела, табуляции, неразрывного пробела NBSP (U+A0) или узкого неразрывного пробела NNBSP (U+202F) | Пример: `"\t"`, `" "`
  `#` | Один из следующих символов разделения: `;`, `:`, `/`, `.`, `,`, `-`, `(` или `)` | Пример: `/`
  `;`, `:`, `/`, `.`, `,`, `-`, `(` или `)` | Заданный символ | Пример: `-`
  `?` | Случайный байт | Пример: `^`. Предостережение: для символов в кодировке UTF-8 иногда требуется указать больше одного символа `?`, поскольку в Юникоде отдельные символы кодируются больше чем одним байтом. Разобрать многобайтовые символы помогает модификатор `*`
  `*` | Случайные байты до следующего разделителя или цифры | Пример: символ `*` в строке формата `Y-*-d` для строки разбора `2009-aWord-08` будет соответствовать части `aWord`
  `!` | Сбрасывает поля «год», «месяц», «день», «час», «минута», «секунда», «милли-» или «микросекунда» и «часовой пояс» до начальных значений Unix-эпохи: `0` для часа, минуты и секунды, `1` для месяца и дня, `1970` для года и часового пояса по умолчанию | Без символа `!` метод установит полям текущие дату и время системы
  `|` | Сбрасывает значения полей «год», «месяц», «день», «час», «минута», «секунда», «милли-» или «микросекунда» и «часовой пояс», которые метод ещё не разобрал, до начальных значений Unix-эпохи | Формат `Y-m-d|` установит год, месяц и день на основе информации, которую нашёл в строке для разбора, а для часа, минуты и секунды установит значение 0
  `+` | С этим спецификатором формата лишние данные в конце строки разбора, добавят в структуру, которую создаёт метод, не ошибку, а предупреждение | Содержала ли строка разбора в конце лишние данные, покажет метод DateTime::getLastErrors()

  Символы в строке формата, которые метод не распознал, вызовут сбой разбора, и метод добавит в структуру с предупреждениями и ошибками, которую он создаёт, сообщение об ошибке. Сообщения об ошибке запрашивают методом DateTime::getLastErrors().

  При включении в строку формата `format` буквальных символов, символы экранируют обратным слешем: `\`.

  Метод сгенерирует дату и время на основе информации в строке разбора, а частям даты и времени, которые не указали в строке формата `format`, установит текущее время системы, если строка формата `format` не содержит символ `!`.

  Метод сгенерирует дату и время на основе информации в строке разбора, а частям даты и времени, которые не указали в строке формата `format`, и значениям слева от символа `!` установит значения даты и времени начала Unix-эпохи, если строка формата `format` содержит символ `!`.

  Метод установит нулевые значения остальным полям времени, которые не указали в строке формата, если разобрал хотя бы один символ для поля времени.

  Начало эпохи Unix — 1970-01-01 00:00:00 UTC.

`datetime`

  Строка, которая представляет время.

`timezone`

  Объект класса DateTimeZone, который представляет часовой пояс.

  Метод установит текущий часовой пояс, если часовой пояс `timezone` опустили или установили для параметра значение `null`, а дата и время `datetime` не содержит часового пояса.

  > Замечание:

  > Метод проигнорирует параметр `timezone` и текущий часовой пояс, если параметр `datetime` либо содержит метку времени UNIX наподобие `946684800`, либо указывает часовой пояс наподобие `2010-01-28T15:00:00+02:00`.

### Возвращаемые значения

Метод возвращает новый экземпляр класса DateTimeImmutable или `false`, если возникла ошибка.

### Ошибки

Метод выбрасывает исключение ValueError, если параметр `datetime` содержит NUL-байты.

### Список изменений

Версия | Описание
--- | ---
8.2.9 | Спецификатор `` (пробел) теперь также поддерживает символы неразрывного пробела NBSP (U+A0) и узкого неразрывного пробела NNBSP (U+202F).
8.2.0 | Добавили спецификаторы `X` и `x` для параметра `format`.
8.0.21, 8.1.8, 8.2.0 | Теперь метод выбрасывает исключение ValueError, если в параметр `datetime` передали NULL-байты, что раньше метод без предупреждения игнорировал.
7.3.0 | Добавили спецификатор `v` для параметра `format`.

### Примеры

Пример #1 Пример использования метода DateTimeImmutable::createFromFormat()

Объектно-ориентированный стиль

    <?php

    $date = DateTimeImmutable::createFromFormat('j-M-Y', '15-Feb-2009');
    echo $date->format('Y-m-d');

Пример #2 Пример передачи в метод DateTimeImmutable::createFromFormat() предопределённых констант формата

Объектно-ориентированный стиль

    <?php

    $date = DateTimeImmutable::createFromFormat(
        DateTimeInterface::ISO8601,
        '2004-02-12T15:19:21+00:00'
    );
    echo $date->format('c e') . "\n";

    $date = DateTimeImmutable::createFromFormat(
        DateTimeInterface::RFC3339_EXTENDED,
        '2013-10-14T09:00:00.000+02:00'
    );
    echo $date->format('c e') . "\n";

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

Пример #3 Тонкости работы метода DateTimeImmutable::createFromFormat()

    <?php

    echo 'Текущее время: ' . date('Y-m-d H:i:s') . "\n";

    // Поля «год», «месяц» и «день» метод распознает в строке разбора,
    // а поля «час», «минута» и «секунда» заполнит значениями системного времени
    $format = 'Y-m-d';
    $date = DateTimeImmutable::createFromFormat($format, '2009-02-15');
    echo "Формат: $format; " . $date->format('Y-m-d H:i:s') . "\n";

    // Метод распознает каждое поле в строке разбора
    $format = 'Y-m-d H:i:s';
    $date = DateTimeImmutable::createFromFormat($format, '2009-02-15 15:16:17');
    echo "Формат: $format; " . $date->format('Y-m-d H:i:s') . "\n";

    /**
     * Метод распознает каждое поле в строке разбора,
     * а затем сбросит поля «год» и «месяц» на начальные значения даты и времени Unix-эпохи,
     * поскольку эти параметры оказались слева от символа «!» в строке формата,
     * а поля «день», «час», «минута» и «секунда» сохранят значения, которые получили из строки разбора,
     * поскольку эти параметры оказались справа от символа «!» и метод распознал для них значения;
     * дробная часть времени со значением долей секунды вернёт значение 000000, поскольку метод
     * не разобрал ни милли-, ни микросекунды, а другие поля времени при этом указали
     */
    $format = 'Y-m-!d H:i:s';
    $date = DateTimeImmutable::createFromFormat($format, '2009-02-15 15:16:17');
    echo "Формат: $format; " . $date->format('Y-m-d H:i:s.u') . "\n";

    /**
     * Метод заполнит поле «день» значением «15», поскольку в строке формата указали символ дня
     * и метод распознал в строке разбора значение для этого параметра,
     * а остальные поля даты и времени метод сбросит на начальные значения
     * даты и времени эпохи Unix, поскольку для этих полей не указали
     * параметры и значения в строках формата и разбора
     */
    $format = '!d';
    $date = DateTimeImmutable::createFromFormat($format, '15');
    echo "Формат: $format; " . $date->format('Y-m-d H:i:s') . "\n";

    /**
     * Метод заполнит поле «минуты» значением 15,
     * поскольку распознал в строке разбора значение для символа минут i.
     * Поля «год», «месяц» и «день» получат значения системной даты,
     * поскольку метод не разобрал эти поля в строках формата и разбора, а в строке формата
     * не было символов «!» или «|», при которых год, месяц и день получили бы значения начала Unix-эпохи.
     * А остальным полям времени метод установит нулевые значения,
     * поскольку метод не нашёл эти параметры и значения для них в строках формата и разбора,
     * но методу удалось разобрать хотя бы одно временно́е поле
     */
    $format = 'i';
    $date = DateTimeImmutable::createFromFormat($format, '15');
    echo "Формат: $format; " . $date->format('Y-m-d H:i:s') . "\n";

Вывод приведённого примера будет похож на:

    Текущее время: 2022-06-02 15:50:46
    Формат: Y-m-d; 2009-02-15 15:50:46
    Формат: Y-m-d H:i:s; 2009-02-15 15:16:17
    Формат: Y-m-!d H:i:s; 1970-01-15 15:16:17
    Формат: !d; 1970-01-15 00:00:00
    Формат: i; 2022-06-02 00:15:00

Пример #4 Пример строки формата с литеральными символами

    <?php

    echo DateTimeImmutable::createFromFormat('H\h i\m s\s','23h 15m 03s')->format('H:i:s');

Вывод приведённого примера будет похож на:

    23:15:03

Пример #5 Пример поведения при переполнении

    <?php

    echo DateTimeImmutable::createFromFormat('Y-m-d H:i:s', '2021-17-35 16:60:97')->format(DateTimeImmutable::RFC2822);

Вывод приведённого примера будет похож на:

    Sat, 04 Jun 2022 17:01:37 +0000

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

1. `97` секунд переполняют `1` минуту и оставляют `37` секунд.
2. `61` минута переполняет `1` час и оставляет `1` минуту.
3. `35` дней переполняют `1` месяц и оставляют `4` дня. Количество дней, которое останется, зависит от месяца, поскольку не в каждом месяце одинаковое количество дней.
4. `18` месяцев переполняют `1` год и оставляют `6` месяцев.

Пример #6 Пример поведения при переполнении названия дня недели

    <?php

    $d = DateTime::createFromFormat(DateTimeInterface::RFC1123, 'Mon, 3 Aug 2020 25:00:00 +0000');
    echo $d->format(DateTime::RFC1123), "\n";

Вывод приведённого примера будет похож на:

    Mon, 10 Aug 2020 01:00:00 +0000

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

1. Из-за переполнения дня количеством часов дата `3 Aug 2020 25:00:00`, понедельник, перетекает на `(Tue) 4 Aug 2020 01:00`, вторник.
2. Метод применяет понедельник — `Mon`, что переносит дату на следующий период с аналогичным названием дня недели — `Mon, 10 Aug 2020 01:00:00`. Объяснение относительных ключевых слов наподобие `Mon` описывает раздел об относительных форматах.

Метод DateTimeImmutable::getLastErrors() помогает обнаружить переполнение дат и включает предупреждение, если возникло переполнение.

Пример #7 Пример обнаружения переполнения дат

    <?php

    $d = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', '2021-17-35 16:60:97');
    echo $d->format(DateTimeImmutable::RFC2822), "\n\n";

    var_dump(DateTimeImmutable::getLastErrors());

Вывод приведённого примера будет похож на:

    Sat, 04 Jun 2022 17:01:37 +0000

    array(4) {
      'warning_count' =>
      int(2)
      'warnings' =>
      array(1) {
        [19] =>
        string(27) "The parsed date was invalid"
      }
      'error_count' =>
      int(0)
      'errors' =>
      array(0) {
      }
    }

Пример #8 Пример жадного поведения при разборе

    <?php

    print_r(date_parse_from_format('Gis', '60101'));

Вывод приведённого примера будет похож на:

    Array
    (
        [year] =>
        [month] =>
        [day] =>
        [hour] => 60
        [minute] => 10
        [second] => 0
        [fraction] => 0
        [warning_count] => 1
        [warnings] => Array
            (
                [5] => The parsed time was invalid
            )

        [error_count] => 1
        [errors] => Array
            (
                [4] => A two digit second could not be found
            )

        [is_localtime] =>
    )

Символ формата `G` разбирает поле «час» в 24-часовом формате с ведущим нулём или без него. Для разбора поля «час» методу требуется разобрать 1 или 2 цифры. Поскольку строка формата первым содержит параметр G, и строка разбора в начале содержит две цифры, которые идут одна за другой, метод жадно считывает значение часа как `60`.

Каждому из следующих символов формата `i` и `s` требуется две цифры. Поэтому число `10` передаётся как значение параметра `i`, который ищет в строке разбора двузначное число для установки значения полю «минута», а для разбора параметра `s`, который также ищет двузначное число для установки значения полю «секунда», не остаётся цифр.

На эту проблему в структуре, которую создаёт метод, указывает массив `errors`.

Кроме того, значение `60` для поля «час» лежит за пределами диапазона `0`-`24`, что добавляет в массив `warnings` предупреждение о недействительности времени.

### Смотрите также

- DateTimeImmutable::__construct() - Возвращает новый объект DateTimeImmutable
- DateTimeImmutable::getLastErrors() - Возвращает предупреждения и ошибки
- checkdate() - Проверяет корректность даты по григорианскому календарю
- strptime() - Разбирает строку даты и времени, которую сгенерировала функция strftime

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open