php дает неправильный ответ при использовании часового пояса Австралия/Сидней

Я разрабатываю веб-сайт для работы в Австралии.

поэтому я установил часовой пояс следующим образом.

date_default_timezone_set('Australia/Sydney');

Мне нужно рассчитать количество дней между двумя датами.

Я обнаружил странное поведение в октябре месяце.

 $now = strtotime('2013-10-06'); // or your date as well
 $your_date = strtotime('2013-10-01');
 $datediff = $now - $your_date;
 echo floor($datediff/(60*60*24));//gives output 5, this is right



 $now = strtotime('2013-10-07'); // or your date as well
 $your_date = strtotime('2013-10-01');
 $datediff = $now - $your_date;
 echo floor($datediff/(60*60*24));//gives output 5, this is wrong, but it should be 6 here

после 07.10.2013 он всегда дает на один день меньше ответа. С другими часовыми поясами все в порядке. Возможно, это связано с переходом на летнее время. Но какое решение для этого.

Пожалуйста помоги.

Спасибо


person user974172    schedule 19.06.2013    source источник
comment
вы можете использовать время utc, и когда вам нужно, вы можете применить смещение для отображения даты и времени в вашем регионе   -  person Arun Killu    schedule 19.06.2013
comment
Хммм... если моя интерпретация верна, strtotime не должен управлять часовым поясом, поэтому вам придется управлять этим самостоятельно. Используйте DateTime($dateStr, new DateTimeZone($timezone)); вместо   -  person Precastic    schedule 19.06.2013
comment
На самом деле, поцарапайте это. 6 правильно. Почему он должен поставить 5? Летнее время вступает в силу только в 3 часа ночи 7-го см. перевод часов в Сиднее   -  person Precastic    schedule 19.06.2013
comment
Очень хороший вопрос, и он иллюстрирует, почему вы должны отделять даты местного календаря от мгновенного времени в своем мышлении.   -  person Matt Johnson-Pint    schedule 19.06.2013


Ответы (1)


Почему написано 5 и почему это технически правильно

В Сиднее переход на летнее время начинается в 02:00 06.10.2013: 00 - так что вы теряете час на свиданиях, охватывающих это.

Когда вы вызываете функцию strtime, она интерпретирует время как время в Сиднее, но возвращает временную метку Unix. Если вы преобразуете второй набор меток времени в UTC, вы получите диапазон от 2013-09-30 14:00:00 до 2013-10-06 13:00:00, что не совсем 6 дней, поэтому округлить до 5.

Как получить разницу во времени, игнорируя переходы на летнее время

Вместо этого попробуйте использовать объекты DateTime, например

$tz=new DateTimeZone('Australia/Sydney');
$start=new DateTime('2013-10-01', $tz);
$end=new DateTime('2013-10-07', $tz);

$diff=$end->diff($start);

//displays 6
echo "difference in days is ".$diff->d."\n";

Почему DateTime::diff работает по-другому?

Вы можете спросить: «Почему это работает?» - ведь между этими временами действительно не 6 дней, а 5 дней и 23 часа.

Причина в том, что DateTime::diff фактически корректирует переходы на летнее время. Мне пришлось прочитать исходный код, чтобы понять это - исправление происходит внутри внутреннего timelib_diff. Эта коррекция происходит, если верно все следующее

  • каждый DateTime использует один и тот же часовой пояс
  • часовой пояс должен быть географическим идентификатором, а не аббревиатурой, такой как GMT
  • каждый DateTime должен иметь разные смещения DST (т.е. один в DST и один нет)

Чтобы проиллюстрировать этот момент, вот что произойдет, если мы используем два раза всего несколько часов по обе стороны от переключения на летнее время.

$tz=new DateTimeZone('Australia/Sydney');
$start=new DateTime('2013-10-06 00:00:00', $tz);
$end=new DateTime('2013-10-06 04:00:00', $tz);

//diff will correct for the DST transition
$diffApparent=$end->diff($start);

//but timestamps represent the reality
$diffActual=($end->getTimestamp() - $start->getTimestamp()) / 3600;

echo "Apparent difference is {$diffApparent->h} hours\n";
echo "Actual difference is {$diffActual} hours\n";

Это выводит

Apparent difference is 4 hours
Actual difference is 3 hours
person Paul Dixon    schedule 19.06.2013
comment
спасибо чувак, ты меня понял. но как решить эту проблему, как я могу получить 6 вместо 5. - person user974172; 19.06.2013
comment
разместил код, который дает ответ 6 - было интересно изучить, почему он тоже отображает 6! - person Paul Dixon; 19.06.2013
comment
Отличный ответ Пол. Глядя на исходный код для timelib_diff, на который вы ссылались, я прав, думая, что это работает только тогда, когда два значения DateTime имеют один и тот же часовой пояс? - person Matt Johnson-Pint; 19.06.2013
comment
Я разъяснил логику, используемую для принятия решения о применении этого исправления. - person Paul Dixon; 19.06.2013