Объект 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