Intereting Posts
Автоматическое разрешение Laravel ioc – работает от контроллера, но не от пользовательского класса есть ли способ изменить хэш без табличек радуги? mysql_connect VS mysql_pconnect Какая лучшая библиотека создает текстовое поле с автоматическим предложением AJAX в виде веб-формы? как ограничить определенный домен (ы) электронной почты, а также отправить форму CodeIgniter Form Validation – Получить результат как «массив» Вместо «string» Ошибка API Google API при проверке токена Резервное копирование базы данных mysql и загрузка в виде файла как определить пользовательский внешний ключ в методе Laurvel «belognsToMany»? Регулярное выражение для соответствия датам в формате ГГГГ-ММ-ДД Загрузка фонового изображения Twitter с помощью API и данных с несколькими форматами Получить свойство объекта PHP, которое является числом Преодолеть проблемы кодирования с PHP, SoapServer, UTF-8 и неанглийскими символами? Извлечение содержимого из каждого первого ТД в таблицу Laravel 4 – Попытка получить свойство не объекта

DateTime изменяет временную метку во время зимней смены DST

Сегодня столкнулась с интересной функцией (? DateTime::setTimestamp() поведении PHP DateTime::setTimestamp() . Во время зимнего изменения DST, когда 1 час повторяется дважды, PHP преобразует временную метку, чтобы всегда быть вторым часом. Рассмотрим следующий пример:

 <?php $date = new \DateTime("now", new \DateTimeZone("UTC")); //2018-10-28T01:30:00 UTC, in London DST happens $date->setTimestamp(1540686600); echo $date->getTimestamp() . "\n"; //1540686600 echo $date->format('c') . "\n"; //2018-10-28T00:30:00+00:00 $date->setTimezone(new \DateTimeZone("Europe/London")); echo $date->getTimestamp() . "\n"; //1540690200 $date->setTimezone(new \DateTimeZone("UTC")); echo $date->getTimestamp() . "\n"; //1540690200 echo $date->format('c') . "\n"; //2018-10-28T01:30:00+00:00 - <?php $date = new \DateTime("now", new \DateTimeZone("UTC")); //2018-10-28T01:30:00 UTC, in London DST happens $date->setTimestamp(1540686600); echo $date->getTimestamp() . "\n"; //1540686600 echo $date->format('c') . "\n"; //2018-10-28T00:30:00+00:00 $date->setTimezone(new \DateTimeZone("Europe/London")); echo $date->getTimestamp() . "\n"; //1540690200 $date->setTimezone(new \DateTimeZone("UTC")); echo $date->getTimestamp() . "\n"; //1540690200 echo $date->format('c') . "\n"; //2018-10-28T01:30:00+00:00 

Глядя на источник PHP пытается преобразовать временную метку в локальное время (o_O). Итак, два вопроса:

  • почему происходит преобразование метки времени? Временная метка всегда находится в UTC и должна быть локальной агентом времени / часового пояса
  • есть ли какое-либо простое решение сохранить идентификатор часового пояса и предполагаемую метку времени в объекте DateTime ? (Я знаю о возможности сохранить все в UTC и конвертировать в местный часовой пояс только при показе)

Найдена возможная ошибка, зарегистрированная на PHP

UPD 2016-01-04 (в UTC) :

Суженная проблема для DateTime::getTimestamp() . Рассмотрим следующий код:

 <?php $date = new \DateTime("now", new \DateTimeZone("UTC")); //2018-10-28T00:30:00 UTC $date->setTimestamp(1540686600); echo $date->format('c') . "\n"; //2018-10-28T00:30:00+00:00 $date->setTimezone(new \DateTimeZone("Europe/London")); echo $date->format('c') . "\n"; //2018-10-28T01:30:00+01:00 $date->setTimezone(new \DateTimeZone("UTC")); echo $date->format('c') . "\n"; //2018-10-28T00:30:00+00:00 echo $date->getTimestamp() . "\n"; //1540686600 - <?php $date = new \DateTime("now", new \DateTimeZone("UTC")); //2018-10-28T00:30:00 UTC $date->setTimestamp(1540686600); echo $date->format('c') . "\n"; //2018-10-28T00:30:00+00:00 $date->setTimezone(new \DateTimeZone("Europe/London")); echo $date->format('c') . "\n"; //2018-10-28T01:30:00+01:00 $date->setTimezone(new \DateTimeZone("UTC")); echo $date->format('c') . "\n"; //2018-10-28T00:30:00+00:00 echo $date->getTimestamp() . "\n"; //1540686600 

Здесь timestamp не изменяется, и код работает так, как ожидалось. Следующий код, похожий и приведенный в оригинальном примере, нарушен:

 <?php $date = new \DateTime("now", new \DateTimeZone("UTC")); //2018-10-28T00:30:00 UTC $date->setTimestamp(1540686600); echo $date->format('c') . "\n"; //2018-10-28T00:30:00+00:00 $date->setTimezone(new \DateTimeZone("Europe/London")); echo $date->format('c') . "\n"; //2018-10-28T01:30:00+01:00 //-------------- the only line that was added ------------------ echo $date->getTimestamp() . "\n"; //1540690200 //-------------- end of added line ----------------------------- $date->setTimezone(new \DateTimeZone("UTC")); echo $date->format('c') . "\n"; //2018-10-28T01:30:00+00:00 echo $date->getTimestamp() . "\n"; //1540690200 - <?php $date = new \DateTime("now", new \DateTimeZone("UTC")); //2018-10-28T00:30:00 UTC $date->setTimestamp(1540686600); echo $date->format('c') . "\n"; //2018-10-28T00:30:00+00:00 $date->setTimezone(new \DateTimeZone("Europe/London")); echo $date->format('c') . "\n"; //2018-10-28T01:30:00+01:00 //-------------- the only line that was added ------------------ echo $date->getTimestamp() . "\n"; //1540690200 //-------------- end of added line ----------------------------- $date->setTimezone(new \DateTimeZone("UTC")); echo $date->format('c') . "\n"; //2018-10-28T01:30:00+00:00 echo $date->getTimestamp() . "\n"; //1540690200 

Ты сказал:

Временная метка всегда находится в UTC и должна быть местным временем, агрегированным часовым поясом

Это утверждение противоречит самому себе. Временные метки находятся в UTC, да, но это не локальное время или часовая зона.

Другими словами, временная метка всегда относится к определенному моменту времени. Местное время может быть неоднозначным, но временной отметки нет. Если вам нужен первый экземпляр неоднозначного локального времени, укажите метку времени, которая на час раньше.

Однако ваши данные немного неверны. Указанная вами временная метка, 1540686600 , на самом деле не 1:30 UTC, а соответствует 2018-10-28T01:30:00+01:00 . Таким образом, это действительно первое появление в 1:30 в день переходного летнего перехода на летнее время. Второе возникновение будет 2018-10-28T01:30:00+00:00 , что соответствует 1540690200 .

Что касается вашего второго вопроса:

есть ли какое-либо простое решение сохранить идентификатор часового пояса и предполагаемую метку времени в объекте DateTime?

Вот как работает DateTime в PHP. Он состоит из внутренней метки времени и связанного часового пояса. Это именно то, что вы показываете при вызове setTimezone .