У меня есть веб-приложение, которое хранит все даты в виде штампов времени UTC. Даты изменяются для целей отображения для клиентов, использующих настройку часового пояса. Тем не менее, я попал в крайний случай в прошлое воскресенье (2 ноября 2014 года), когда DST закончилось в США. Я думал, что мой код обработал этот случай, потому что он использует strtotime и "+1 Day", но это не так. Вот код, который у меня есть:
$current_date_start=$this->date_start; //$this->date_start is a UTC timestamp
$current_date_end=strtotime('+1 day', $current_date_start);
do
{
$current_date_start=strtotime('+1 day', $current_date_start);
$current_date_end=strtotime('+1 day', $current_date_start);
echo format_local_date($current_date_start,'America/Los_Angeles',"D F j Y H i s")."<br />";
}
while ($current_date_start<$this->date_end);
function format_local_date($timestamp,$timezone,$format_str='')
{
$date_time=new DateTime_52("now",new DateTimeZone($timezone));
$date_time->setTimestamp($timestamp);
if ($format_str=='')
$format_str="F j Y";
return $date_time->format($format_str);
}
//
//DateTime_52 class
//
/**
* Provides backwards support for php 5.2 lack of setTimestamp and getTimestamp
*/
class DateTime_52 extends DateTime{
/**
* Set the time of the datetime object by a unix timestamp
* @param int $unixtimestamp
* @return DateTime_52
*/
public function setTimestamp($unixtimestamp){
if(!is_numeric($unixtimestamp) && !is_null($unixtimestamp)){
trigger_error('DateTime::setTimestamp() expects parameter 1 to be long, '.gettype($unixtimestamp).' given', E_USER_WARNING);
} else {
$default_timezone=date_default_timezone_get();
$this_timezone= $this->getTimezone();
date_default_timezone_set($this->getTimezone()->getName());
$this->setDate(date('Y', $unixtimestamp), date('n', $unixtimestamp), date('d', $unixtimestamp));
$this->setTime(date('G', $unixtimestamp), date('i', $unixtimestamp), date('s', $unixtimestamp));
date_default_timezone_set($default_timezone);
}
return $this;
}
/**
* Get the time of the datetime object as a unix timestamp
* @return int a unix timestamp representing the time in the datetime object
*/
public function getTimestamp(){
return $this->format('U');
}
}
И вот вывод:
Sun November 2 2014 00 00 00
Sun November 2 2014 23 00 00
Mon November 3 2014 23 00 00
Tue November 4 2014 23 00 00
Wed November 5 2014 23 00 00
Thu November 6 2014 23 00 00
Fri November 7 2014 23 00 00
Sat November 8 2014 23 00 00
Как вы можете видеть, он упал час. Очевидно, что крайний регистр DST. Но я думал, что "+1 Day" должен справиться с этим. ПОМОГИТЕ!
Ваш порядок действий неверен. Вы добавляете +1 день к времени UTC, которое не имеет дисперсии DST. Сначала вы должны сначала преобразовать в локальный часовой пояс, а THEN добавить свой +1 день, и это будет делать трюк, так как расчет будет в правильном часовом поясе, чтобы сделать эту проверку автоматически, как ожидалось.