Как включить полную поддержку UTC для високосных секунд в PHP DateTime?

Я хотел сделать немного DateTime расчеты с Leap Seconds, но он остановился довольно рано, потому что я не мог сказать DateTime что я имел ввиду:

### June 30, 2012 at 23:59:60 UTC ###

$leap = new DateTime('2012-06-30T23:59:60UTC');
var_export($leap);

Выход:

DateTime::__set_state(array(
   'date' => '2012-07-01 00:00:00',
   'timezone_type' => 3,
   'timezone' => 'UTC',
))

Я не могу создать DateTime для этого UTC високосная секунда прошлого года (также не другие високосные секунды, которые я попробовал). Интересно, если DateTime поддерживает високосные секунды вообще, я думал, что есть поддержка UTC, но, вероятно, не для високосных секунд, так что просто поддержка GMT?

2 ответа

Время UNIX не знает о високосных секундах. Что касается этого, каждый день состоит ровно из 86 400 секунд, а время просто пропускает или повторяет секунду время от времени. (Это в значительной степени необходимо, потому что високосные секунды не полностью запланированы заранее. Если бы високосные секунды были подсчитаны во времени UNIX, "отображение" между временем UNIX и удобочитаемыми датами / временем изменится непредсказуемо, так как были объявлены високосные секунды.)

Поскольку все примитивы даты / времени основаны на времени UNIX, PHP также не может легко представлять високосные секунды. Они эффективно невидимы.

Это не совсем ответ, но, по крайней мере, это что-то.

Здесь есть две возможные проблемы:

  1. Как упомянул ircmaxell, PHP может потреблять дополнительную секунду где-то внутри битов манипуляции с часовым поясом, но необходимы дополнительные исследования.
  2. Однако я лично ожидаю, что PHP "исправит" "переполнение" секунд в минуты. DateTime конструктор передает заданный аргумент через тот же код, который обрабатывает strtotime Хорошо известно, что они принимают полностью фиктивные даты (например, 31 февраля) и превращают их во что-то, что, возможно, имеет смысл.

Единственная ссылка на високосные секунды в документации strptime:

"tm_sec" включает в себя любые високосные секунды (в настоящее время до 2 в год).

Например, сокращенно от интерактивного приглашения PHP:

php > $eviler_format = '%Y-%m-%d %H:%M:%S %z';
php > $evil = '2012-12-31 23:59:59 +0000';
php > var_dump(strptime($evil, $eviler_format));
array(9) {
  'tm_sec' =>
  int(59) // ...
}
php > $evil = '2012-12-31 23:59:60 +0000';
php > var_dump(strptime($evil, $eviler_format));
array(9) {
  'tm_sec' =>
  int(60) // ...
}
php > $evil = '2012-12-31 23:59:61 +0000';
php > var_dump(strptime($evil, $eviler_format));
array(9) {
  'tm_sec' =>
  int(61) // ...
}
php > $evil = '2012-12-31 23:59:62 +0000';
php > var_dump(strptime($evil, $eviler_format));
bool(false)

К сожалению, также требуются "високосные секунды", которых нет 31 декабря:

php > $evil = '2012-01-07 23:59:61 +0000';
php > var_dump(strptime($evil, $eviler_format));
array(9) {
  'tm_sec' =>
  int(61)
  'tm_min' =>
  int(59)
  'tm_hour' =>
  int(23)
  'tm_mday' =>
  int(7)
  'tm_mon' =>
  int(0)
  'tm_year' =>
  int(112)
  'tm_wday' =>
  int(6)
  'tm_yday' =>
  int(6)
  'unparsed' =>
  string(0) ""
}

или не в полночь:

php > $evil = '2012-01-07 08:59:61 +0000';
php > var_dump(strptime($evil, $eviler_format));
array(9) {
  'tm_sec' =>
  int(61)
  'tm_min' =>
  int(59)
  'tm_hour' =>
  int(8)
  'tm_mday' =>
  int(7)
  'tm_mon' =>
  int(0)
  'tm_year' =>
  int(112)
  'tm_wday' =>
  int(6)
  'tm_yday' =>
  int(6)
  'unparsed' =>
  string(0) ""
}

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

Вывод: PHP не думает о високосных секундах. Убедитесь, что ваш сервер синхронизирован с вышестоящим NTP-сервером, который заботится об этом, и в конечном итоге все будет в порядке. Если вам нужно позаботиться о точности второго уровня в отношении високосных секунд, возможно, PHP в любом случае вам не подходит.

Другие вопросы по тегам