Skip to content

Instantly share code, notes, and snippets.

@fey
Created July 11, 2025 16:02
Show Gist options
  • Save fey/cf87a900d8c192ace66d19afb8904784 to your computer and use it in GitHub Desktop.
Save fey/cf87a900d8c192ace66d19afb8904784 to your computer and use it in GitHub Desktop.
Custom date time format
<?php
declare(strict_types=1);
// Написать функцию с сигнатурой
// function dateFormat(DateTimeInterface $dt, string $format): string
// $date = new DateTime('2025-06-03 15:07:09');
// echo dateFormat($date, 'y-M-d H:mm:ss') . PHP_EOL; // 2025-6-3 15:07:09
// echo dateFormat($date, 'yy \yy\y') . PHP_EOL; // 25 y2025y
// echo dateFormat($date, 'H\H:mm\m:ss hh\:m:s') . PHP_EOL; // 15H:07m:09 03\:7:9
// где $format это формат даты включающий следующие спецсимволы:
// y - Полное числовое представление года, не менее 4 цифр: 2000, 2025 и т.д.
// yy - Две последние цифры года с дополнением нулями, если необходимо: 99, 05 и т.д.
// M - Порядковый номер месяца без ведущего нуля: от 1 до 12.
// MM - Порядковый номер месяца с ведущим нулём: от 01 до 12.
// d - День месяца без ведущего нуля: от 1 до 31.
// dd - День месяца, 2 цифры с ведущим нулём: от 01 до 31.
// h - Часы в 12-часовом формате без ведущего нуля: от 1 до 12.
// hh - Часы в 12-часовом формате с ведущим нулём: от 01 до 12.
// H - Часы в 24-часовом формате без ведущего нуля: от 0 до 23.
// HH - Часы в 24-часовом формате с ведущим нулём: от 00 до 23.
// m - Минуты без ведущего нуля: от 0 до 59.
// mm - Минуты с ведущим нулём от 00 до 59.
// s - Секунды без ведущего нуля: от 0 до 59.
// ss - Секунды с ведущим нулём: от 00 до 59.
// Примечание: если строка формата содержит символы, совпадающие с вышеперечисленными,
// но не являющиеся параметрами форматирования,
// то их следует экранировать с помощью символа обратного слэша "\".
function dateFormat(DateTimeInterface $dt, string $format): string
{
// Сопоставление ключ-формат => ключ-формат DateTime
// Порядок важен
$formatCharsMap = [
// yy - Две последние цифры года с дополнением нулями, если необходимо: 99, 05 и т.д.
'yy' => 'y',
// y - Полное числовое представление года, не менее 4 цифр: 2000, 2025 и т.д.
'y' => 'o',
// MM - Порядковый номер месяца с ведущим нулём: от 01 до 12.
'MM' => 'm',
// M - Порядковый номер месяца без ведущего нуля: от 1 до 12.
'M' => 'n',
// dd - День месяца, 2 цифры с ведущим нулём: от 01 до 31.
'dd' => 'd',
// d - День месяца без ведущего нуля: от 1 до 31.
'd' => 'j',
// hh - Часы в 12-часовом формате с ведущим нулём: от 01 до 12.
'hh' => 'h',
// h - Часы в 12-часовом формате без ведущего нуля: от 1 до 12.
'h' => 'g',
// H - Часы в 24-часовом формате без ведущего нуля: от 0 до 23.
'H' => 'G',
// HH - Часы в 24-часовом формате с ведущим нулём: от 00 до 23.
'HH' => 'H',
// mm - Минуты с ведущим нулём от 00 до 59.
'mm' => 'i',
// m - Минуты без ведущего нуля: от 0 до 59.
'm' => fn (DateTime $dt) => (string) intval($dt->format('i')),
// ss - Секунды с ведущим нулём: от 00 до 59.
'ss' => 's',
// s - Секунды без ведущего нуля: от 0 до 59. в Datetime нет для этого формата
's' => fn (DateTime $dt) => (string) intval($dt->format('s')),
];
$customDtTemplates = array_keys($formatCharsMap);
$regexCharsTemplate = implode('|', $customDtTemplates);
$dtFormatRegex = "/(?<!\\\)({$regexCharsTemplate})/";
$resultFormat = preg_replace_callback_array([
$dtFormatRegex => static function (array $matches) use ($formatCharsMap, $dt): string {
$key = $matches[0];
$dtTemplate = $formatCharsMap[$key];
if (is_string($dtTemplate )) {
return $dtTemplate;
}
if (is_callable($dtTemplate)) {
return $dtTemplate($dt);
}
throw new RuntimeException("Unhandled dt temlate key. Given key: {$key}");
},
"/\\\(?![yMdHhms])/" => static fn() => '\\\\\\',
], $format);
return $dt->format($resultFormat);
}
$date = new DateTime('2025-06-03 15:07:09');
test('2025-6-3 15:07:09', dateFormat($date, 'y-M-d H:mm:ss'));
test('15H:07m:09 03\:7:9', dateFormat($date, 'H\H:mm\m:ss hh\:m:s'));
test('25 y2025y', dateFormat($date, 'yy \yy\y'));
echo dateFormat($date, 'y-M-d H:mm:ss') . PHP_EOL; // 2025-6-3 15:07:09
echo dateFormat($date, 'yy \yy\y') . PHP_EOL; // 25 y2025y
echo dateFormat($date, 'H\H:mm\m:ss hh\:m:s') . PHP_EOL; // 15H:07m:09 03\:7:9
function test($expected, $actual): void
{
try {
assert($expected === $actual);
} catch (\AssertionError) {
echo "failed tests. Expected === actual. {$expected} === {$actual}\n";
exit(1);
}
echo "Ok!\n";
}

Comments are disabled for this gist.