БлогNot. DateTime::diff или глючная "разница дат" в PHP 5.3.X

DateTime::diff или глючная "разница дат" в PHP 5.3.X

Даже обновил себе на локалхосте PHP до версии 5.3.5, чтобы полюбоваться на это чудо. Дело в том, что разницу между датами в месяцах, днях, неделях, годах и прочем мне приходилось писать и на мобильной Java, и на Javascript, не говоря уж о всяких Си и Паскалях. Увы, не самый лёгкий в мире расчёт, учитывая феврали, високосные годы и отсутствие в большинстве языков готовых методов для сложения-вычитания дат.

Предвкушая, как удобно будет посчитать разницу в датах, я написал маленький тестовый сценарий:

<?php
 @date_default_timezone_set (date_default_timezone_get());
  //Чтоб дальше не ругался предупреждениями на date()
 $tm1 = date ("Y-m-d H:m:s",mktime (0,0,0,date("m"),date("d"),date("Y")));
 $dt1 = new DateTime($tm1);
 $d='';
 $year=2011;
 $month=2;
 $day=16;
 //Можно вызвать с параметром вида ?d=2011-07-15
 if (isset($_GET['d'])) $d=htmlspecialchars(strip_tags(trim($_GET['d'])));
 if (!empty($d)) { list ($year,$month,$day)=explode("-",$d); }
 $tm2 = date ("Y-m-d H:m:s",mktime (0,0,0,$month,$day,$year));
 $dt2 = new DateTime($tm2); 
 $interval = $dt2->diff($dt1);
 print_r($interval);
?>

...и вот что он мне выдал:

DateInterval Object ( [y] => 0 [m] => 4 [d] => 21 [h] => 0 [i] => 5 [s] => 0 [invert] => 0 [days] => 141 )

Вроде как, всё верно.

Проверим на ещё одной дате (23.05.1971). Мой старенький мидлет говорит:

14655 дней;
2093 недели и 4 дня;
40 лет, 1 месяц, 14 дней

Скрипт говорит:

DateInterval Object ( [y] => 40 [m] => 1 [d] => 14 [h] => 0 [i] => 2 [s] => 0 [invert] => 0 [days] => 14655 )

И на этот раз всё правильно, если не считать непонятно откуда взявшихся 2 минут.

Но для даты 21.10.1940, от которой сегодня прошло 25826 дней или 70 лет, 8 месяцев и 16 дней, получается уже вот что:

DateInterval Object ( [y] => 70 [m] => 8 [d] => 15 [h] => 23 [i] => 57 [s] => 0 [invert] => 0 [days] => 25825 )

Конечно, я не считал это вручную, но вряд ли ошибка - в моём старом расчёте, достаточно взглянуть на дополнительные 23 часа 57 минут в результатах класса. Получается, что класс годится только если анализировать и округлять дополнительные поля для часов и минут. Можно, видимо, сделать и проще - просто добавлять к исходной дате час или два - не сработало!

Нехороший баг метода diff - для первого числа месяца возвращается не то число дней (общее число дней при этом правильное):

1) 1 месяц, 8 дней; 39 дней; 5 недель, 4 дня
2) 1 месяц, 8 дней; 38 дней; 5 недель, 3 дня
3) 1 месяц, 7 дней; 37 дней; 5 недель, 2 дня
4) 1 месяц, 6 дней; 36 дней; 5 недель, 1 день

Здесь мы считали число дней от 1-4 июня 2011 до 10 июля 2011, обратите внимание на одинаковые "8 дней" в первых двух строках. Ещё один бросающийся в глаза баг - от 1 февраля до 1 марта пройдёт 0 месяцев.

Позднее, возможно, напишу на этой основе скриптик. А пока мешает истекшее на сегодня свободное время, плюс то, что метод DateTime::diff появился в PHP 5.3, а у меня на внешнем сервере стоит проверенный временем 5.2.17.

 Скрипт накидал, статья и скрипт здесь

07.07.2011, 21:06 [15715 просмотров]


теги: ошибка php дата

показать комментарии (1)