2010-10-27 2 views
25

Есть ли какая-либо функция, эквивалентная DateTime :: diff() в PHP 5.2?Что можно использовать для DateTime :: diff() для PHP 5.2?

Мой локальный сервер - это PHP 5.3 и использует DateTime :: diff(). то я обнаружил, что мой сайт использует PHP 5.2 и дает ошибку.

Fatal error: Call to undefined method DateTime::diff() in /var/www/some/other/dir/web/daikon/modules/projects/views/admin/log/admin_log_list.php on line 40 

РНР код:

foreach ($logs as $key => $list){ 
... 
// show date in European way dd-mm-yyyy not in MySQL way yyyy-mm-dd 
    $newdate =new DateTime($list['date']) ; 
    echo "<td class=\"left\" width=\"8%\">".$newdate->format('d-m-Y')."</td>\n"; 
    $starttime = new DateTime($list['start_time']); 
    echo "<td width=\"7%\">".date_format($starttime, 'H:i')."</td>\n"; 
    $finishtime = new DateTime($list['finish_time']); 
    echo "<td width=\"8%\">".date_format($finishtime, 'H:i')."</td>\n"; 
    $timediff = 0; 
    $interval = $starttime->diff($finishtime); 
    $hours = $interval->format('%h'); 
    $minutes = $interval->format('%i'); 
    $timediff = $hours * 60 + $minutes; 
+0

Почему бы вам не выбрать ответ? – realtebo

ответ

2

Да, это раздражает, что функция не превратить его в PHP5.2.

Предполагаю, что вы не можете обновить до 5.3? Вы должны изучить это; есть очень мало причин не обновлять; но я предполагаю, что вы не можете по какой-либо причине.

Первый совет: Если вам нужно только диф менее 24 часов, вы можете просто вычесть две метки времени, и сделать $time_diff = date('H:i:s',$subtracted_value);

Если вы делаете больше, чем 24 часа посмотреть различия, но ты в порядке с просто возвращающим количество дней вместе с разницей во времени, вы можете расширить описанную выше технику, выполнив расчет модуля по вычитаемому значению, против количества секунд в сутки (то есть 24 * 60 * 60, что составляет 86400)

$subtracted_value = $date1 - $date2; 
$days_diff = $subtracted_value % 86400; 
$time_diff = date('H:i:s',$subtracted_value); 

Если вам нужны недели, вы можете, конечно, сделать $days_diff % 7.

К сожалению, ручная техника разрушается после нескольких недель, потому что месяцы и годы имеют переменную длину (технические дни тоже, учитывая летнее время, но вы, вероятно, можете игнорировать это, тем более, что вы только когда-либо будете час, максимум), но, надеюсь, это достаточно хорошо, чтобы вы начали.

+0

Разве вам не нужно делиться на 86400, а не модулем? –

+0

@Rocket .... hmm, возможно.Этот ответ был давным-давно, поэтому я не могу вспомнить, о чем я думал, но вы вполне можете быть правы. – Spudley

+0

Я понимаю, что это был старый ответ, но я нашел его в Google после поиска того, как использовать 'DateTime :: diff()' на PHP 5.2. –

38

ответ Spudley не работает для меня - вычитания любого DateTime из другого 0 дает на моей системе.

Я был в состоянии получить его на работу с помощью DateTime :: формата с Спецификатором «U» (секунды с Unix эпохи):

$start = new DateTime('2010-10-12'); 
$end = new DateTime(); 
$days = round(($end->format('U') - $start->format('U'))/(60*60*24)); 

Это работает как на моей системе DEV (5.3.4) и моей системы развертывания (5.2.11).

+2

Почти идеально, за исключением того, что вы использовали 'abs()', которые предполагают, что он всегда положительный. – Raptor

+1

Спасибо, что указали это, @ShivanRaptor. Я оглянулся на код, который я написал для этого, и он требует положительной ценности и всегда сравнивается сегодня с датой в прошлом. Ошибка в этом коде заключалась в том, что я вычитал сегодня с даты начала, а не наоборот, поэтому я использовал 'abs()', чтобы преобразовать его в положительное значение. Я обновил образец выше, чтобы вернуть отрицательное значение, если конечная дата предшествует дате начала, которая является поведением 'DateTime :: diff()' по умолчанию. –

+0

Мне нужно было добавить персетез в верхнюю часть деления: '$ days = round (($ end-> format ('U') - $ start-> format ('U'))/(60 * 60 * 24)) ' –

2

Spudley был близок, но вам нужно использовать gmdate not date.

Так это работает в течение 24 часов или меньше (если это положительное значение, по крайней мере):

$difference = $date2->format('U') - $date1->format('U'); 
$time_diff = gmdate('H:i:s',$difference); 
0

PHP имеет методы для работы с Unix временными метками.

Как уже отмечалось другими, при работе с секундами с даты Unix легко рассчитать время.

StrToTime РНР() преобразует дату в метку времени:

$diff = round((strtotime($list['start']) - strtotime($list['finish']))/86400); 

Если вы хотите, чтобы вычислить до текущего времени, времени() обеспечивает временную метку "сейчас":

$diff = round((time() - strtotime($list['date']))/86400); 

86400 - это количество секунд в день.
Если вы хотите конвертировать лет использовать 31557000, который почти точно 365,24219 * 86400.

Дополнительным преимуществом является то, что StrToTime может взять дату ввода в почти любом читаемом формате, так что очень легко работать с кодом внутри.

3

Я использую это, кажется, работает хорошо - очевидно, вы можете добавить второй параметр, чтобы сделать его более гибким:

function GetDateDiffFromNow($originalDate) 
{ 
    $unixOriginalDate = strtotime($originalDate); 
    $unixNowDate = strtotime('now'); 
    $difference = $unixNowDate - $unixOriginalDate ; 
    $days = (int)($difference/86400); 
    $hours = (int)($difference/3600); 
    $minutes = (int)($difference/60); 
    $seconds = $difference; 

    // now do what you want with this now and return ... 
} 
3

Я пытался улучшить ответ Кристофера Pickslay в.

Я сделал эту функцию, которая возвращает и объект с большинством свойств исходного объекта DateInterval.

Не существует свойства «дней», потому что это похоже на some bug на моем тестовом сервере (он всегда возвращает 6015).

Кроме того, я предполагаю, что каждый месяц имеет 30 дней, что определенно не является точным, но может помочь.

function dateTimeDiff($date1, $date2) { 

    $alt_diff = new stdClass(); 
    $alt_diff->y = floor(abs($date1->format('U') - $date2->format('U'))/(60*60*24*365)); 
    $alt_diff->m = floor((floor(abs($date1->format('U') - $date2->format('U'))/(60*60*24)) - ($alt_diff->y * 365))/30); 
    $alt_diff->d = floor(floor(abs($date1->format('U') - $date2->format('U'))/(60*60*24)) - ($alt_diff->y * 365) - ($alt_diff->m * 30)); 
    $alt_diff->h = floor(floor(abs($date1->format('U') - $date2->format('U'))/(60*60)) - ($alt_diff->y * 365*24) - ($alt_diff->m * 30 * 24) - ($alt_diff->d * 24)); 
    $alt_diff->i = floor(floor(abs($date1->format('U') - $date2->format('U'))/(60)) - ($alt_diff->y * 365*24*60) - ($alt_diff->m * 30 * 24 *60) - ($alt_diff->d * 24 * 60) - ($alt_diff->h * 60)); 
    $alt_diff->s = floor(floor(abs($date1->format('U') - $date2->format('U'))) - ($alt_diff->y * 365*24*60*60) - ($alt_diff->m * 30 * 24 *60*60) - ($alt_diff->d * 24 * 60*60) - ($alt_diff->h * 60*60) - ($alt_diff->i * 60)); 
    $alt_diff->invert = (($date1->format('U') - $date2->format('U')) > 0)? 0 : 1 ; 

    return $alt_diff; 
}  
+0

хорошо, исправлено отверстие - но репликации выглядят немного лишними для меня ... – BananaAcid

+0

с этим вместо 30 мы можем рассчитать точные дни месяца: cal_days_in_month (CAL_GREGORIAN, 8, 2003); –

6

Мне просто нужно было (к сожалению) для плагина WordPress. Это я использую функцию в 2 раза:

  1. В моем классе вызывающего -> Diff() (мой класс расширяет DateTime, так $ это является эталонным DateTime)

    function diff ($secondDate){ 
        $firstDateTimeStamp = $this->format("U"); 
        $secondDateTimeStamp = $secondDate->format("U"); 
        $rv = ($secondDateTimeStamp - $firstDateTimeStamp); 
        $di = new DateInterval($rv); 
        return $di; 
    } 
    
  2. Тогда я воссоздал поддельный DateInterval класс (потому что DateInterval действует только в PHP> = 5.3) следующим образом:

    Class DateInterval { 
        /* Properties */ 
        public $y = 0; 
        public $m = 0; 
        public $d = 0; 
        public $h = 0; 
        public $i = 0; 
        public $s = 0; 
    
        /* Methods */ 
        public function __construct ($time_to_convert /** in seconds */) { 
         $FULL_YEAR = 60*60*24*365.25; 
         $FULL_MONTH = 60*60*24*(365.25/12); 
         $FULL_DAY = 60*60*24; 
         $FULL_HOUR = 60*60; 
         $FULL_MINUTE = 60; 
         $FULL_SECOND = 1; 
    
    //  $time_to_convert = 176559; 
         $seconds = 0; 
         $minutes = 0; 
         $hours = 0; 
         $days = 0; 
         $months = 0; 
         $years = 0; 
    
         while($time_to_convert >= $FULL_YEAR) { 
          $years ++; 
          $time_to_convert = $time_to_convert - $FULL_YEAR; 
         } 
    
         while($time_to_convert >= $FULL_MONTH) { 
          $months ++; 
          $time_to_convert = $time_to_convert - $FULL_MONTH; 
         } 
    
         while($time_to_convert >= $FULL_DAY) { 
          $days ++; 
          $time_to_convert = $time_to_convert - $FULL_DAY; 
         } 
    
         while($time_to_convert >= $FULL_HOUR) { 
          $hours++; 
          $time_to_convert = $time_to_convert - $FULL_HOUR; 
         } 
    
         while($time_to_convert >= $FULL_MINUTE) { 
          $minutes++; 
          $time_to_convert = $time_to_convert - $FULL_MINUTE; 
         } 
    
         $seconds = $time_to_convert; // remaining seconds 
         $this->y = $years; 
         $this->m = $months; 
         $this->d = $days; 
         $this->h = $hours; 
         $this->i = $minutes; 
         $this->s = $seconds; 
        } 
    } 
    

Надежда, что помогает кому-то.

+0

приятно, но почему бы не использовать функцию mod ('%') (и целочисленное деление) вместо цикла, чтобы получить остаток –

0

Обратите внимание, что если ваш объект DateTime был создан из строки даты без какой-либо информации о часовом поясе (как в '2012-01-01 05:00:00', как из mysql), то установка часового пояса позже с помощью объектов DateTimeZone через setTimeZone() не изменяет внутреннюю метку времени объектов DateTime.

$localtime = new DateTime('2012-01-01 08:00:00+02:00'); // Europe/Copenhagen (+ daylight savings) 
$localtime->setTimezone(new DateTimeZone('UTC')); // convert local time to utc 

$utctime = new DateTime('2012-01-01 06:00:00'); // timezone assumed utc, but is in fact unknown 
$utctime->setTimezone(new DateTimeZone('UTC')); // trying to rectify missing timezone which fails, because the internal timestamp isn't modified, although any other format than 'U' may indicate so 
#$utctime = new DateTime('2012-01-01 06:00:00+00:00'); // timezone stated, this works 

$diff = intval($localtime->format('U')) - intval($utctime->format('U')); 
echo $diff; // expecting zero 
0

Это лучшее решение для вашего вопроса.

<?php 

/* Find difference between two dates in days. PHP 5.2.x. */ 

$d1 = date('Y-m-d', strtotime('2013-06-13')); 
$d2 = date("Y-m-d"); 
echo diff($d1, $d2); 

function diff($date1, $date2) { 
    $diff = abs(strtotime($date2) - strtotime($date1)); 
    $years = floor($diff/(365*60*60*24)); 
    $months = floor(($diff - $years * 365*60*60*24)/(30*60*60*24)); 
    $days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/(60*60*24)); 
    return $days; 
} 
?>