Объект DateTime
не связан его меткой времени? Или getTimestamp () имеет какой-то побочный эффект при использовании при изменении DST?
Детали
При установке метки времени объекта DateTime
находящегося в DST
(это означает, что время форматирования существует как до, так и после смены часов), возвращаемая временная метка отличается от установленной временной метки.
$ php --version PHP 7.1.3 (cli) (built: Mar 17 2017 16:59:59) ( NTS ) Copyright (c) 1997-2017 The PHP Group Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies
воспроизводить
Рассмотрим следующий скрипт php
:
date_default_timezone_set('Europe/Berlin'); $date = new DateTime(); $set_timestamp = 1319932800; $date->setTimestamp($set_timestamp); $get_timestamp = $date->getTimestamp(); fwrite(STDERR, $set_timestamp . "\n"); // 1319932800 fwrite(STDERR, $get_timestamp . "\n"); // 1319936400 **(WHY IS THIS DIFFERENT?)**
-date_default_timezone_set('Europe/Berlin'); $date = new DateTime(); $set_timestamp = 1319932800; $date->setTimestamp($set_timestamp); $get_timestamp = $date->getTimestamp(); fwrite(STDERR, $set_timestamp . "\n"); // 1319932800 fwrite(STDERR, $get_timestamp . "\n"); // 1319936400 **(WHY IS THIS DIFFERENT?)**
Почему печатные значения не равны?
Прежде всего, временная метка unix всегда находится в UTC, поэтому у нее нет часовой пояс и DST.
С другой стороны, объект DateTime
сохраняет только локальное время («local» означает, какой часовой пояс установлен в экземпляре DateTime
) .
Поэтому вы должны установить часовой пояс на +00: 00 или UTC, прежде чем устанавливать временную метку, чтобы избежать ненужных преобразований времени и угадывания DST.
У вас есть два варианта:
DateTime
Конструктор будет отменять часовой пояс по умолчанию и явно установлен на +00: 00, когда он получит отметку времени (начатую с @
) в первом параметре:
$set_timestamp = 1319932800; $date = new DateTime('@' . $set_timestamp); print($set_timestamp . "\n"); print($date->getTimestamp() . "\n");
Info: в этом случае параметр конструктора timezone всегда будет переопределен.
setTimestamp()
Вызовите setTimezone()
с setTimezone()
DateTimeZone('+00:00')
или DateTimeZone('UTC')
перед вызовом setTimestamp()
:
$set_timestamp = 1319932800; $date = new DateTime(); $date->setTimezone(new DateTimeZone('UTC')); $date->setTimestamp($set_timestamp); print($set_timestamp . "\n"); print($date->getTimestamp() . "\n");
-$set_timestamp = 1319932800; $date = new DateTime(); $date->setTimezone(new DateTimeZone('UTC')); $date->setTimestamp($set_timestamp); print($set_timestamp . "\n"); print($date->getTimestamp() . "\n");
Конечно, оба этих случая будут:
1319932800 1319932800
date_default_timezone_set()
в этих случаях не требуется, потому что вы не хотите ничего делать с местным временем.
Однако, когда вы хотите напечатать $date
в человекообразном формате (поэтому, когда вы конвертируете временную метку unix в локальное время), часовой пояс будет интересным снова.
\DateTime
не сохраняет метки времени, кроме локального времени, и выполняет преобразования в методе метрической метки и времени .
Это приводит к побочному эффекту один раз в год, когда DST отключается, поскольку оба временных знака 1319932800..1319936400 и 1319936400..1319940000 разрешены в одно и то же местное время:
https://www.epochconverter.com/timezones?q=1319936399&tz=Europe%2FBerlin https://www.epochconverter.com/timezones?q=1319939999&tz=Europe%2FBerlin