Як обчислити різницю між двома датами за допомогою PHP?


722

У мене є дві дати форми:

Start Date: 2007-03-24 
End Date: 2009-06-26

Тепер мені потрібно знайти різницю між цими двома в наступному вигляді:

2 years, 3 months and 2 days

Як я можу це зробити в PHP?


1
2 роки 94 дні. Розрахувати місяці з урахуванням високосних років було б проблематично. Наскільки точно це потрібно?
dbasnett

Відповіді:


526

Використовуйте це для застарілого коду (PHP <5.3). Поновлення рішення див. У відповідь jurka нижче

Ви можете використовувати strtotime () для перетворення двох дат у unix час, а потім обчислити кількість секунд між ними. З цього досить просто обчислити різні періоди часу.

$date1 = "2007-03-24";
$date2 = "2009-06-26";

$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));

printf("%d years, %d months, %d days\n", $years, $months, $days);

Редагувати: Очевидно, що кращий спосіб зробити це, як описано у jurka нижче. Мій код, як правило, рекомендується, лише якщо у вас немає PHP 5.3 або вище.

Кілька людей у ​​коментарях зазначили, що наведений вище код - це лише наближення. Я все ще вважаю, що для більшості цілей це нормально, оскільки використання діапазону - це скоріше для того, щоб зрозуміти, скільки часу пройшло чи залишилось, а не для точності - якщо ви хочете це зробити, просто виведіть дату.

Попри все, я вирішив розглянути скарги. Якщо вам справді потрібен точний діапазон, але ви не маєте доступу до PHP 5.3, використовуйте код нижче (він також повинен працювати в PHP 4). Це прямий порт коду, який PHP використовує внутрішньо для обчислення діапазонів, за винятком того, що він не враховує літній час. Це означає, що він вимикається не більше години, але крім цього він повинен бути правильним.

<?php

/**
 * Calculate differences between two dates with precise semantics. Based on PHPs DateTime::diff()
 * implementation by Derick Rethans. Ported to PHP by Emil H, 2011-05-02. No rights reserved.
 * 
 * See here for original code:
 * http://svn.php.net/viewvc/php/php-src/trunk/ext/date/lib/tm2unixtime.c?revision=302890&view=markup
 * http://svn.php.net/viewvc/php/php-src/trunk/ext/date/lib/interval.c?revision=298973&view=markup
 */

function _date_range_limit($start, $end, $adj, $a, $b, $result)
{
    if ($result[$a] < $start) {
        $result[$b] -= intval(($start - $result[$a] - 1) / $adj) + 1;
        $result[$a] += $adj * intval(($start - $result[$a] - 1) / $adj + 1);
    }

    if ($result[$a] >= $end) {
        $result[$b] += intval($result[$a] / $adj);
        $result[$a] -= $adj * intval($result[$a] / $adj);
    }

    return $result;
}

function _date_range_limit_days($base, $result)
{
    $days_in_month_leap = array(31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    $days_in_month = array(31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

    _date_range_limit(1, 13, 12, "m", "y", &$base);

    $year = $base["y"];
    $month = $base["m"];

    if (!$result["invert"]) {
        while ($result["d"] < 0) {
            $month--;
            if ($month < 1) {
                $month += 12;
                $year--;
            }

            $leapyear = $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0);
            $days = $leapyear ? $days_in_month_leap[$month] : $days_in_month[$month];

            $result["d"] += $days;
            $result["m"]--;
        }
    } else {
        while ($result["d"] < 0) {
            $leapyear = $year % 400 == 0 || ($year % 100 != 0 && $year % 4 == 0);
            $days = $leapyear ? $days_in_month_leap[$month] : $days_in_month[$month];

            $result["d"] += $days;
            $result["m"]--;

            $month++;
            if ($month > 12) {
                $month -= 12;
                $year++;
            }
        }
    }

    return $result;
}

function _date_normalize($base, $result)
{
    $result = _date_range_limit(0, 60, 60, "s", "i", $result);
    $result = _date_range_limit(0, 60, 60, "i", "h", $result);
    $result = _date_range_limit(0, 24, 24, "h", "d", $result);
    $result = _date_range_limit(0, 12, 12, "m", "y", $result);

    $result = _date_range_limit_days(&$base, &$result);

    $result = _date_range_limit(0, 12, 12, "m", "y", $result);

    return $result;
}

/**
 * Accepts two unix timestamps.
 */
function _date_diff($one, $two)
{
    $invert = false;
    if ($one > $two) {
        list($one, $two) = array($two, $one);
        $invert = true;
    }

    $key = array("y", "m", "d", "h", "i", "s");
    $a = array_combine($key, array_map("intval", explode(" ", date("Y m d H i s", $one))));
    $b = array_combine($key, array_map("intval", explode(" ", date("Y m d H i s", $two))));

    $result = array();
    $result["y"] = $b["y"] - $a["y"];
    $result["m"] = $b["m"] - $a["m"];
    $result["d"] = $b["d"] - $a["d"];
    $result["h"] = $b["h"] - $a["h"];
    $result["i"] = $b["i"] - $a["i"];
    $result["s"] = $b["s"] - $a["s"];
    $result["invert"] = $invert ? 1 : 0;
    $result["days"] = intval(abs(($one - $two)/86400));

    if ($invert) {
        _date_normalize(&$a, &$result);
    } else {
        _date_normalize(&$b, &$result);
    }

    return $result;
}

$date = "1986-11-10 19:37:22";

print_r(_date_diff(strtotime($date), time()));
print_r(_date_diff(time(), strtotime($date)));

1
Якщо ви використовуєте клас DateTime, ви можете перейти до формату $ date-> ("U"), щоб отримати часову позначку unix.
Джон Крам

4
Це неправда, якщо вам доводиться мати справу з літнім / зимовим часом. У цьому конкретному випадку, коли ви регулюєте літній / зимовий час, один день дорівнює 23 або 25 годин.
Арно

4
Що ж, такий же аргумент можна зробити і в високосні роки. Це також не враховує. Проте я не переконаний, що ви навіть хочете це врахувати, оскільки ми обговорюємо діапазон. Семантика для діапазону дещо відрізняється, ніж для абсолютної дати.
Еміль Н

9
Ця функція невірна. Це добре для наближення, але неправильне для точних діапазонів. Для одного, він передбачає, що в місяць є 30 днів, що означає, що між 1 лютого та 1 березня буде однакова різниця днів, як і з 1 липня по 1 серпня (незалежно від високосного року).
Онобрев

1
У PHP змінні посилання є у підписі функції, а не у виклику. Перемістіть усі свої &підписи.
Пол Тарджан

909

Я пропоную використовувати об'єкти DateTime та DateInterval.

$date1 = new DateTime("2007-03-24");
$date2 = new DateTime("2009-06-26");
$interval = $date1->diff($date2);
echo "difference " . $interval->y . " years, " . $interval->m." months, ".$interval->d." days "; 

// shows the total amount of days (not divided into years, months and days like above)
echo "difference " . $interval->days . " days ";

читати більше php DateTime :: diff керівництво

З посібника:

Станом на PHP 5.2.2, об'єкти DateTime можна порівняти за допомогою операторів порівняння.

$date1 = new DateTime("now");
$date2 = new DateTime("tomorrow");

var_dump($date1 == $date2); // bool(false)
var_dump($date1 < $date2);  // bool(true)
var_dump($date1 > $date2);  // bool(false)

14
+1 DateTime обробляє високосні роки та часові пояси належним чином, і на полиці є гарна книга: phparch.com/books/…
hakre

3
Чи існує метод, який дає загальну кількість секунд між двома DateTimes? (без додавання компонентів, тобто)
картопля

1
@Panique Інтервал $ -> дні та $ інтервал-> d - це різні міри. ваш коментар вище правильний "показує загальну кількість днів (не поділяється на роки, місяці та дні, як вище)"
jurka

1
@potatoe Ви, мабуть, хочете $date2->format('U') - $date1->format('U').
Пауло Фрейтас

3
зауважте, що виникла помилка, у якій DateInterval має неправильне властивість днів ( завжди 6015 ) для Windows з деякими версіями PHP: bugs.php.net/bug.php?id=51184 (див. коментарі до виправлення / вирішення)
Pim Schaaf

73

Найкращий спосіб дії - це використання DateTimeDateInterval) об'єктів PHP . Кожна дата інкапсульована в DateTimeоб’єкт, і тоді можна зробити різницю між цими двома:

$first_date = new DateTime("2012-11-30 17:03:30");
$second_date = new DateTime("2012-12-21 00:00:00");

DateTimeОб'єкт буде приймати будь-який формат strtotime()буде. Якщо потрібен ще більш конкретний формат дати, DateTime::createFromFormat()його можна використовувати для створення DateTimeоб'єкта.

Після того, як обидва об'єкти були створені, ви підкреслите один з іншого за допомогою DateTime::diff().

$difference = $first_date->diff($second_date);

$differenceтепер зберігає DateIntervalоб'єкт із різницевою інформацією. А var_dump()виглядає наступним чином :

object(DateInterval)
  public 'y' => int 0
  public 'm' => int 0
  public 'd' => int 20
  public 'h' => int 6
  public 'i' => int 56
  public 's' => int 30
  public 'invert' => int 0
  public 'days' => int 20

Для форматування DateIntervalоб'єкта нам потрібно перевірити кожне значення та виключити його, якщо воно 0:

/**
 * Format an interval to show all existing components.
 * If the interval doesn't have a time component (years, months, etc)
 * That component won't be displayed.
 *
 * @param DateInterval $interval The interval
 *
 * @return string Formatted interval string.
 */
function format_interval(DateInterval $interval) {
    $result = "";
    if ($interval->y) { $result .= $interval->format("%y years "); }
    if ($interval->m) { $result .= $interval->format("%m months "); }
    if ($interval->d) { $result .= $interval->format("%d days "); }
    if ($interval->h) { $result .= $interval->format("%h hours "); }
    if ($interval->i) { $result .= $interval->format("%i minutes "); }
    if ($interval->s) { $result .= $interval->format("%s seconds "); }

    return $result;
}

Все, що залишилося зараз - це викликати нашу функцію на $difference DateIntervalоб’єкті:

echo format_interval($difference);

І ми отримуємо правильний результат:

20 днів 6 годин 56 хвилин 30 секунд

Повний код, який використовується для досягнення мети:

/**
 * Format an interval to show all existing components.
 * If the interval doesn't have a time component (years, months, etc)
 * That component won't be displayed.
 *
 * @param DateInterval $interval The interval
 *
 * @return string Formatted interval string.
 */
function format_interval(DateInterval $interval) {
    $result = "";
    if ($interval->y) { $result .= $interval->format("%y years "); }
    if ($interval->m) { $result .= $interval->format("%m months "); }
    if ($interval->d) { $result .= $interval->format("%d days "); }
    if ($interval->h) { $result .= $interval->format("%h hours "); }
    if ($interval->i) { $result .= $interval->format("%i minutes "); }
    if ($interval->s) { $result .= $interval->format("%s seconds "); }

    return $result;
}

$first_date = new DateTime("2012-11-30 17:03:30");
$second_date = new DateTime("2012-12-21 00:00:00");

$difference = $first_date->diff($second_date);

echo format_interval($difference);

DateTime()це не функція, це об'єкт, і він існує з PHP 5.2. Переконайтеся, що ваш сервер підтримує його.
Привид

2
@SecondRikudo DateTime :: Diff need PHP 5.3.0
PhoneixS

У нас проблема, обміняти first_date на second_date і ми отримуємо такий же результат? Чому б не сказати 0 днів 0 годин 0 хвилин 0 секунд або лише 0. Приклад: 2012-11-30 17:03:30 - 2012-12-21 00:00:00 та 2012-12-21 00:00:00 - 2012-11-30 17:03:30 отримайте такий же результат.
EgoistDeveloper

Тому що diff дає вам різницю між двома разів. Різниця не дорівнює 0, незалежно від того, яка дата настає пізніше.
Привид

1
Це дійсно гарна відповідь, оскільки вона забезпечує чітку функцію, яку можна викликати з будь-якої точки кодової бази без великої кількості часу. Інші відповіді дозволяють вам викинути лунали лунки, які стосуються симптомів, а не вирішують проблему ... Єдиний доданий я елемент (і майже всі інші публікації цього не охоплюють) - це плюралізація елементів інтервалу $ якщо більше 1.
nickhar

33

Переглянути години та хвилини та секунди ..

$date1 = "2008-11-01 22:45:00"; 

$date2 = "2009-12-04 13:44:01"; 

$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));

$hours   = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24)/ (60*60)); 

$minuts  = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24 - $hours*60*60)/ 60); 

$seconds = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24 - $days*60*60*24 - $hours*60*60 - $minuts*60)); 

printf("%d years, %d months, %d days, %d hours, %d minuts\n, %d seconds\n", $years, $months, $days, $hours, $minuts, $seconds); 

7
Ймовірно, це не дасть точного результату.
Дельфін

8
І це жахливе рішення, якщо ви не змушені використовувати жахливо застарілу версію PHP ...
rdlowrey

2
Не так сухий . Наприклад, 60 * 60 * 24 повторюється 15 разів. Довге повторне використання копіювальної пасти!
Пітер Мортенсен

Що про високосні роки? Рік в середньому не становить 365 днів.
Пітер Мортенсен

Цей код передбачає, що в середньому місяць становить 30 днів. Навіть якщо припустити 365 днів протягом року, середній місяць становить 365/12 = 30,42 дня (приблизно).
Пітер Мортенсен

18

Подивіться за наступним посиланням. Це найкраща відповідь, яку я знайшов поки що .. :)

function dateDiff ($d1, $d2) {

    // Return the number of days between the two dates:    
    return round(abs(strtotime($d1) - strtotime($d2))/86400);

} // end function dateDiff

Не має значення, яка дата є раніше чи пізніше, коли ви переходите в параметри дати. Функція використовує абсолютне значення PHP ABS () для того, щоб завжди повертати позитивне число як кількість днів між двома датами.

Майте на увазі, що кількість днів між двома датами НЕ враховує обох дат. Отже, якщо ви шукаєте кількість днів, представлених усіма датами між ними, включаючи введені дати, вам потрібно буде додати один (1) до результату цієї функції.

Наприклад, різниця (повернена вищевказаною функцією) між 2013-02-09 та 2013-02-14 становить 5. Але кількість днів або дати, представлені діапазоном дат 2013-02-09 - 2013-02- 14 - 6.

http://www.bizinfosys.com/php/date-difference.html


Питання задало різницю як кількість років, місяців і днів, а не загальну кількість днів.
Пітер Мортенсен

14

Я голосував за Jurka «s відповідь , як це мій улюблений, але у мене є пре-php.5.3 ...

Я виявив, що працюю над подібною проблемою - саме так я і дійшов до цього питання в першу чергу - але мені просто потрібна різниця в годинах. Але моя функція також дуже добре вирішила цю функцію, і я не маю ніде своєї власної бібліотеки, щоб зберігати її там, де вона не загубиться і не забудеться, тому ... сподіваюся, це комусь корисно.

/**
 *
 * @param DateTime $oDate1
 * @param DateTime $oDate2
 * @return array 
 */
function date_diff_array(DateTime $oDate1, DateTime $oDate2) {
    $aIntervals = array(
        'year'   => 0,
        'month'  => 0,
        'week'   => 0,
        'day'    => 0,
        'hour'   => 0,
        'minute' => 0,
        'second' => 0,
    );

    foreach($aIntervals as $sInterval => &$iInterval) {
        while($oDate1 <= $oDate2){ 
            $oDate1->modify('+1 ' . $sInterval);
            if ($oDate1 > $oDate2) {
                $oDate1->modify('-1 ' . $sInterval);
                break;
            } else {
                $iInterval++;
            }
        }
    }

    return $aIntervals;
}

І тест:

$oDate = new DateTime();
$oDate->modify('+111402189 seconds');
var_dump($oDate);
var_dump(date_diff_array(new DateTime(), $oDate));

І результат:

object(DateTime)[2]
  public 'date' => string '2014-04-29 18:52:51' (length=19)
  public 'timezone_type' => int 3
  public 'timezone' => string 'America/New_York' (length=16)

array
  'year'   => int 3
  'month'  => int 6
  'week'   => int 1
  'day'    => int 4
  'hour'   => int 9
  'minute' => int 3
  'second' => int 8

Я отримав оригінальну ідею звідси , яку я змінив для своїх цілей (і сподіваюся, що моя модифікація відобразиться і на цій сторінці).

Ви можете дуже легко видалити інтервали, які вам не потрібні (скажімо, "тиждень"), видаливши їх з $aIntervalsмасиву, або, можливо, додавши $aExcludeпараметр, або просто відфільтрувавши їх під час виведення рядка.


На жаль, це не повертає те саме, що і DateInterval через переповнення року / місяця.
Стівен Гарріс

2
@StephenHarris: Я цього не перевіряв, але, читаючи код, я впевнений, що він повинен повернути той же результат - за умови, що ви видалите weekіндекс в $aIntervals(оскільки DateDiffніколи цього не використовуєте).
Алікс Аксель

Це чудове рішення для пошуку дат, які трапляються кожен інтервал між двома датами.
між мозком

14
<?php
    $today = strtotime("2011-02-03 00:00:00");
    $myBirthDate = strtotime("1964-10-30 00:00:00");
    printf("Days since my birthday: ", ($today - $myBirthDate)/60/60/24);
?>

Питання задало різницю як кількість років , місяців та днів . Це виводить різницю як загальну кількість днів.
Пітер Мортенсен

11

Я не знаю, використовуєте ви рамку PHP чи ні, але багато PHP-фреймів мають бібліотеки дат / часу та помічники, які допоможуть уберегти вас від винаходи колеса.

Наприклад, CodeIgniter має timespan()функцію. Просто введіть дві часові позначки Unix, і вони автоматично генерують такий результат:

1 Year, 10 Months, 2 Weeks, 5 Days, 10 Hours, 16 Minutes

http://codeigniter.com/user_guide/helpers/date_helper.html


8

Приклад використання:

echo time_diff_string('2013-05-01 00:22:35', 'now');
echo time_diff_string('2013-05-01 00:22:35', 'now', true);

Вихід:

4 months ago
4 months, 2 weeks, 3 days, 1 hour, 49 minutes, 15 seconds ago

Функція:

function time_diff_string($from, $to, $full = false) {
    $from = new DateTime($from);
    $to = new DateTime($to);
    $diff = $to->diff($from);

    $diff->w = floor($diff->d / 7);
    $diff->d -= $diff->w * 7;

    $string = array(
        'y' => 'year',
        'm' => 'month',
        'w' => 'week',
        'd' => 'day',
        'h' => 'hour',
        'i' => 'minute',
        's' => 'second',
    );
    foreach ($string as $k => &$v) {
        if ($diff->$k) {
            $v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
        } else {
            unset($string[$k]);
        }
    }

    if (!$full) $string = array_slice($string, 0, 1);
    return $string ? implode(', ', $string) . ' ago' : 'just now';
}

якщо я хочу визначити, чи різниця більша за 30 хвилин, що мені робити?
Ofir Attia

@OfirAttia: у вас є маса таких запитань тут, так, просто використовуйте пошук. Проста демонстрація
Главич

7

Я маю для цього просту логіку:

<?php
    per_days_diff('2011-12-12','2011-12-29')
    function per_days_diff($start_date, $end_date) {
        $per_days = 0;
        $noOfWeek = 0;
        $noOfWeekEnd = 0;
        $highSeason=array("7", "8");

        $current_date = strtotime($start_date);
        $current_date += (24 * 3600);
        $end_date = strtotime($end_date);

        $seassion = (in_array(date('m', $current_date), $highSeason))?"2":"1";

        $noOfdays = array('');

        while ($current_date <= $end_date) {
            if ($current_date <= $end_date) {
                $date = date('N', $current_date);
                array_push($noOfdays,$date);
                $current_date = strtotime('+1 day', $current_date);
            }
        }

        $finalDays = array_shift($noOfdays);
        //print_r($noOfdays);
        $weekFirst = array("week"=>array(),"weekEnd"=>array());
        for($i = 0; $i < count($noOfdays); $i++)
        {
            if ($noOfdays[$i] == 1)
            {
                //echo "This is week";
                //echo "<br/>";
                if($noOfdays[$i+6]==7)
                {
                    $noOfWeek++;
                    $i=$i+6;
                }
                else
                {
                    $per_days++;
                }
                //array_push($weekFirst["week"],$day);
            }
            else if($noOfdays[$i]==5)
            {
                //echo "This is weekend";
                //echo "<br/>";
                if($noOfdays[$i+2] ==7)
                {
                    $noOfWeekEnd++;
                    $i = $i+2;
                }
                else
                {
                    $per_days++;
                }
                //echo "After weekend value:- ".$i;
                //echo "<br/>";
            }
            else
            {
                $per_days++;
            }
        }

        /*echo $noOfWeek;
          echo "<br/>";
          echo $noOfWeekEnd;
          echo "<br/>";
          print_r($per_days);
          echo "<br/>";
          print_r($weekFirst);
        */

        $duration = array("weeks"=>$noOfWeek, "weekends"=>$noOfWeekEnd, "perDay"=>$per_days, "seassion"=>$seassion);
        return $duration;
      ?>

Здається, що в кінці зразка коду щось не вистачає (кінцева дужка та " ?> "?).
Пітер Мортенсен

"проста" логіка. Це щонайменше 40 рядків чистого коду.
Маджош

6

Ви можете використовувати

getdate()

функція, яка повертає масив, що містить усі елементи наданої дати / часу:

$diff = abs($endDate - $startDate);
$my_t=getdate($diff);
print("$my_t[year] years, $my_t[month] months and $my_t[mday] days");

Якщо дати початку та закінчення у строковому форматі, тоді використовуйте

$startDate = strtotime($startDateStr);
$endDate = strtotime($endDateStr);

перед вищевказаним кодом


Схоже, не працює. Я отримую дату на початку епохи часу.
Сірбер

Важливо розуміти, що вам потрібно зробити, $my_t["year"] -= 1970щоб отримати правильну кількість років. Крім того, необхідно відняти ваш час різниця за Гринвічем , щоб отримати годинник правильно. Вам також потрібно відняти 1 за місяцем і датою.
Салман

6
// If you just want to see the year difference then use this function.
// Using the logic I've created you may also create month and day difference
// which I did not provide here so you may have the efforts to use your brain.
// :)
$date1='2009-01-01';
$date2='2010-01-01';
echo getYearDifference ($date1,$date2);
function getYearDifference($date1=strtotime($date1),$date2=strtotime($date2)){
    $year = 0;
    while($date2 > $date1 = strtotime('+1 year', $date1)){
        ++$year;
    }
    return $year;
}

Чи враховує "strtotime (" + 1 рік ", $ date1)" високосні роки?
Пітер Мортенсен

6

Це моя функція. Потрібна PHP> = 5.3.4. Він використовує клас DateTime. Дуже швидко, швидко і може зробити різницю між двома датами або навіть так званим "часом з моменту".

if(function_exists('grk_Datetime_Since') === FALSE){
    function grk_Datetime_Since($From, $To='', $Prefix='', $Suffix=' ago', $Words=array()){
        #   Est-ce qu'on calcul jusqu'à un moment précis ? Probablement pas, on utilise maintenant
        if(empty($To) === TRUE){
            $To = time();
        }

        #   On va s'assurer que $From est numérique
        if(is_int($From) === FALSE){
            $From = strtotime($From);
        };

        #   On va s'assurer que $To est numérique
        if(is_int($To) === FALSE){
            $To = strtotime($To);
        }

        #   On a une erreur ?
        if($From === FALSE OR $From === -1 OR $To === FALSE OR $To === -1){
            return FALSE;
        }

        #   On va créer deux objets de date
        $From = new DateTime(@date('Y-m-d H:i:s', $From), new DateTimeZone('GMT'));
        $To   = new DateTime(@date('Y-m-d H:i:s', $To), new DateTimeZone('GMT'));

        #   On va calculer la différence entre $From et $To
        if(($Diff = $From->diff($To)) === FALSE){
            return FALSE;
        }

        #   On va merger le tableau des noms (par défaut, anglais)
        $Words = array_merge(array(
            'year'      => 'year',
            'years'     => 'years',
            'month'     => 'month',
            'months'    => 'months',
            'week'      => 'week',
            'weeks'     => 'weeks',
            'day'       => 'day',
            'days'      => 'days',
            'hour'      => 'hour',
            'hours'     => 'hours',
            'minute'    => 'minute',
            'minutes'   => 'minutes',
            'second'    => 'second',
            'seconds'   => 'seconds'
        ), $Words);

        #   On va créer la chaîne maintenant
        if($Diff->y > 1){
            $Text = $Diff->y.' '.$Words['years'];
        } elseif($Diff->y == 1){
            $Text = '1 '.$Words['year'];
        } elseif($Diff->m > 1){
            $Text = $Diff->m.' '.$Words['months'];
        } elseif($Diff->m == 1){
            $Text = '1 '.$Words['month'];
        } elseif($Diff->d > 7){
            $Text = ceil($Diff->d/7).' '.$Words['weeks'];
        } elseif($Diff->d == 7){
            $Text = '1 '.$Words['week'];
        } elseif($Diff->d > 1){
            $Text = $Diff->d.' '.$Words['days'];
        } elseif($Diff->d == 1){
            $Text = '1 '.$Words['day'];
        } elseif($Diff->h > 1){
            $Text = $Diff->h.' '.$Words['hours'];
        } elseif($Diff->h == 1){
            $Text = '1 '.$Words['hour'];
        } elseif($Diff->i > 1){
            $Text = $Diff->i.' '.$Words['minutes'];
        } elseif($Diff->i == 1){
            $Text = '1 '.$Words['minute'];
        } elseif($Diff->s > 1){
            $Text = $Diff->s.' '.$Words['seconds'];
        } else {
            $Text = '1 '.$Words['second'];
        }

        return $Prefix.$Text.$Suffix;
    }
}

6

Я б волів використовувати date_createіdate_diff предмети.

Код:

$date1 = date_create("2007-03-24");
$date2 = date_create("2009-06-26");

$dateDifference = date_diff($date1, $date2)->format('%y years, %m months and %d days');

echo $dateDifference;

Вихід:

2 years, 3 months and 2 days

Для отримання додаткової інформації прочитайте посібник із PHPdate_diff

Відповідно до посібника date_diff- псевдонім DateTime :: diff ()


5

Це спробує визначити, була вказана часова марка чи ні, а також поверне майбутні дати / часи як негативні значення:

<?php

function time_diff($start, $end = NULL, $convert_to_timestamp = FALSE) {
  // If $convert_to_timestamp is not explicitly set to TRUE,
  // check to see if it was accidental:
  if ($convert_to_timestamp || !is_numeric($start)) {
    // If $convert_to_timestamp is TRUE, convert to timestamp:
    $timestamp_start = strtotime($start);
  }
  else {
    // Otherwise, leave it as a timestamp:
    $timestamp_start = $start;
  }
  // Same as above, but make sure $end has actually been overridden with a non-null,
  // non-empty, non-numeric value:
  if (!is_null($end) && (!empty($end) && !is_numeric($end))) {
    $timestamp_end = strtotime($end);
  }
  else {
    // If $end is NULL or empty and non-numeric value, assume the end time desired
    // is the current time (useful for age, etc):
    $timestamp_end = time();
  }
  // Regardless, set the start and end times to an integer:
  $start_time = (int) $timestamp_start;
  $end_time = (int) $timestamp_end;

  // Assign these values as the params for $then and $now:
  $start_time_var = 'start_time';
  $end_time_var = 'end_time';
  // Use this to determine if the output is positive (time passed) or negative (future):
  $pos_neg = 1;

  // If the end time is at a later time than the start time, do the opposite:
  if ($end_time <= $start_time) {
    $start_time_var = 'end_time';
    $end_time_var = 'start_time';
    $pos_neg = -1;
  }

  // Convert everything to the proper format, and do some math:
  $then = new DateTime(date('Y-m-d H:i:s', $$start_time_var));
  $now = new DateTime(date('Y-m-d H:i:s', $$end_time_var));

  $years_then = $then->format('Y');
  $years_now = $now->format('Y');
  $years = $years_now - $years_then;

  $months_then = $then->format('m');
  $months_now = $now->format('m');
  $months = $months_now - $months_then;

  $days_then = $then->format('d');
  $days_now = $now->format('d');
  $days = $days_now - $days_then;

  $hours_then = $then->format('H');
  $hours_now = $now->format('H');
  $hours = $hours_now - $hours_then;

  $minutes_then = $then->format('i');
  $minutes_now = $now->format('i');
  $minutes = $minutes_now - $minutes_then;

  $seconds_then = $then->format('s');
  $seconds_now = $now->format('s');
  $seconds = $seconds_now - $seconds_then;

  if ($seconds < 0) {
    $minutes -= 1;
    $seconds += 60;
  }
  if ($minutes < 0) {
    $hours -= 1;
    $minutes += 60;
  }
  if ($hours < 0) {
    $days -= 1;
    $hours += 24;
  }
  $months_last = $months_now - 1;
  if ($months_now == 1) {
    $years_now -= 1;
    $months_last = 12;
  }

  // "Thirty days hath September, April, June, and November" ;)
  if ($months_last == 9 || $months_last == 4 || $months_last == 6 || $months_last == 11) {
    $days_last_month = 30;
  }
  else if ($months_last == 2) {
    // Factor in leap years:
    if (($years_now % 4) == 0) {
      $days_last_month = 29;
    }
    else {
      $days_last_month = 28;
    }
  }
  else {
    $days_last_month = 31;
  }
  if ($days < 0) {
    $months -= 1;
    $days += $days_last_month;
  }
  if ($months < 0) {
    $years -= 1;
    $months += 12;
  }

  // Finally, multiply each value by either 1 (in which case it will stay the same),
  // or by -1 (in which case it will become negative, for future dates).
  // Note: 0 * 1 == 0 * -1 == 0
  $out = new stdClass;
  $out->years = (int) $years * $pos_neg;
  $out->months = (int) $months * $pos_neg;
  $out->days = (int) $days * $pos_neg;
  $out->hours = (int) $hours * $pos_neg;
  $out->minutes = (int) $minutes * $pos_neg;
  $out->seconds = (int) $seconds * $pos_neg;
  return $out;
}

Приклад використання:

<?php
  $birthday = 'June 2, 1971';
  $check_age_for_this_date = 'June 3, 1999 8:53pm';
  $age = time_diff($birthday, $check_age_for_this_date)->years;
  print $age;// 28

Або:

<?php
  $christmas_2020 = 'December 25, 2020';
  $countdown = time_diff($christmas_2020);
  print_r($countdown);

5

"якщо" дата зберігається в MySQL, мені простіше зробити обчислення різниці на рівні бази даних ... Тоді виходячи з результатів Дня, Години, Мін, Секу, проаналізувати та відобразити результати відповідно до ...

mysql> select firstName, convert_tz(loginDate, '+00:00', '-04:00') as loginDate, TIMESTAMPDIFF(DAY, loginDate, now()) as 'Day', TIMESTAMPDIFF(HOUR, loginDate, now())+4 as 'Hour', TIMESTAMPDIFF(MINUTE, loginDate, now())+(60*4) as 'Min', TIMESTAMPDIFF(SECOND, loginDate, now())+(60*60*4) as 'Sec' from User_ where userId != '10158' AND userId != '10198' group by emailAddress order by loginDate desc;
 +-----------+---------------------+------+------+------+--------+
 | firstName | loginDate           | Day  | Hour | Min  | Sec    |
 +-----------+---------------------+------+------+------+--------+
 | Peter     | 2014-03-30 18:54:40 |    0 |    4 |  244 |  14644 |
 | Keith     | 2014-03-30 18:54:11 |    0 |    4 |  244 |  14673 |
 | Andres    | 2014-03-28 09:20:10 |    2 |   61 | 3698 | 221914 |
 | Nadeem    | 2014-03-26 09:33:43 |    4 |  109 | 6565 | 393901 |
 +-----------+---------------------+------+------+------+--------+
 4 rows in set (0.00 sec)

5

Я знайшов вашу статтю на наступній сторінці, яка містить низку посилань на PHP обчислення часу датою .

Обчисліть різницю між двома датами (та часом) за допомогою PHP. На наступній сторінці представлено низку різних методів (всього 7) для виконання розрахунків дати / часу за допомогою PHP, щоб визначити різницю в часі (години, муніти), днях, місяцях або роках між двома датами.

Див. Час дати PHP - 7 методів розрахунку різниці між двома датами .


4

Ви також можете використовувати наступний код, щоб повернути дату, відмінну від круглих дробів до $ date1 = $ duedate; // присвоїти дату echo $ date2 = date ("Ymd"); // поточна дата $ ts1 = strtotime ($ date1); $ ts2 = strtotime ($ date2); $ seconds_diff = $ ts1 - $ ts2; echo $ dateiff = ceil (($ секунд_diff / 3600) / 24); // повернення в днях

Якщо ви використовуєте підлогу методом php замість стелі, він поверне вам круглу фракцію вниз. Будь ласка, перевірте різницю тут, якщо часом часовий пояс ваших серверів постановки відрізняється, то часовий пояс веб-сайту в реальному часі ви можете отримати різні результати, тому змініть умови відповідно.


4
$date1 = date_create('2007-03-24');
$date2 = date_create('2009-06-26');
$interval = date_diff($date1, $date2);
echo "difference : " . $interval->y . " years, " . $interval->m." months, ".$interval->d." days ";

4

Ви завжди можете використовувати таку функцію, яка може повернути вік у роках та місяцях (тобто 1 рік 4 місяці)

function getAge($dob, $age_at_date)
{  
    $d1 = new DateTime($dob);
    $d2 = new DateTime($age_at_date);
    $age = $d2->diff($d1);
    $years = $age->y;
    $months = $age->m;

    return $years.'.'.months;
}

або якщо ви хочете, щоб вік був обчислений на поточну дату, ви можете використовувати

function getAge($dob)
{  
    $d1 = new DateTime($dob);
    $d2 = new DateTime(date());
    $age = $d2->diff($d1);
    $years = $age->y;
    $months = $age->m;

    return $years.'.'.months;
}

4

Для версії php> = 5.3: Створіть два об'єкти дати та використовуйте date_diff()функцію. Він поверне об'єкт php DateInterval . див. документацію

$date1=date_create("2007-03-24");
$date2=date_create("2009-06-26");
$diff=date_diff($date1,$date2);
echo $diff->format("%R%a days");

4

Ось код, який можна виконати

$date1 = date_create('2007-03-24');
$date2 = date_create('2009-06-26');
$diff1 = date_diff($date1,$date2);
$daysdiff = $diff1->format("%R%a");
$daysdiff = abs($daysdiff);

3

У мене була така ж проблема з PHP 5.2 і вирішено її з MySQL. Може бути не саме те, що ви шукаєте, але це зробить трюк і поверне кількість днів:

$datediff_q = $dbh->prepare("SELECT DATEDIFF(:date2, :date1)");
$datediff_q->bindValue(':date1', '2007-03-24', PDO::PARAM_STR);
$datediff_q->bindValue(':date2', '2009-06-26', PDO::PARAM_STR);
$datediff = ($datediff_q->execute()) ? $datediff_q->fetchColumn(0) : false;

Більше інформації тут http://dev.mysql.com/doc/refman/5.5/uk/date-and-time-functions.html#function_nadiiff


3

Оскільки всі публікують зразки коду, ось ще одна версія.

Я хотів, щоб функція відображала відмінності від секунд до років (всього одна одиниця). Для періодів, що перевищують 1 день, я хотів, щоб він перевертався опівночі (10:00 понеділка, що бачиться з 9 ранку, середа - 2 дні тому, а не 1). І протягом періодів, що перевищували місяць, я хотів, щоб перехід був у той самий день місяця (включаючи 30/31 денні місяці та високосні роки).

Ось що я придумав:

/**
 * Returns how long ago something happened in the past, showing it
 * as n seconds / minutes / hours / days / weeks / months / years ago.
 *
 * For periods over a day, it rolls over at midnight (so doesn't depend
 * on current time of day), and it correctly accounts for month-lengths
 * and leap-years (months and years rollover on current day of month).
 *
 * $param string $timestamp in DateTime format
 * $return string description of interval
 */
function ago($timestamp)
{
    $then = date_create($timestamp);

    // for anything over 1 day, make it rollover on midnight
    $today = date_create('tomorrow'); // ie end of today
    $diff = date_diff($then, $today);

    if ($diff->y > 0) return $diff->y.' year'.($diff->y>1?'s':'').' ago';
    if ($diff->m > 0) return $diff->m.' month'.($diff->m>1?'s':'').' ago';
    $diffW = floor($diff->d / 7);
    if ($diffW > 0) return $diffW.' week'.($diffW>1?'s':'').' ago';
    if ($diff->d > 1) return $diff->d.' day'.($diff->d>1?'s':'').' ago';

    // for anything less than 1 day, base it off 'now'
    $now = date_create();
    $diff = date_diff($then, $now);

    if ($diff->d > 0) return 'yesterday';
    if ($diff->h > 0) return $diff->h.' hour'.($diff->h>1?'s':'').' ago';
    if ($diff->i > 0) return $diff->i.' minute'.($diff->i>1?'s':'').' ago';
    return $diff->s.' second'.($diff->s==1?'':'s').' ago';
}

3

Деякий час тому я написав format_dateфункцію, оскільки це дає багато варіантів того, як ви хочете побачити :

function format_date($date, $type, $seperator="-")
{
    if($date)
    {
        $day = date("j", strtotime($date));
        $month = date("n", strtotime($date));
        $year = date("Y", strtotime($date));
        $hour = date("H", strtotime($date));
        $min = date("i", strtotime($date));
        $sec = date("s", strtotime($date));

        switch($type)
        {
            case 0:  $date = date("Y".$seperator."m".$seperator."d",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 1:  $date = date("D, F j, Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 2:  $date = date("d".$seperator."m".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 3:  $date = date("d".$seperator."M".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 4:  $date = date("d".$seperator."M".$seperator."Y h:i A",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 5:  $date = date("m".$seperator."d".$seperator."Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 6:  $date = date("M",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 7:  $date = date("Y",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 8:  $date = date("j",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 9:  $date = date("n",mktime($hour, $min, $sec, $month, $day, $year)); break;
            case 10: 
                     $diff = abs(strtotime($date) - strtotime(date("Y-m-d h:i:s"))); 
                     $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));
                     $date = $years . " years, " . $months . " months, " . $days . "days";
        }
    }
    return($date);
}    

2
Ця відповідь так само помилкова, як і відповідь Халдонно. Він передбачає (випадок 10), що рік має 365 днів (кожен четвертий рік має 366 днів (крім правил 100-річного / 400-річного періоду за григоріанським календарем)), і що місяць має 30 днів (це приблизно 30,42 дня у нестримні роки). Навіть з кращими константами це правильно лише в середньому, не обов'язково правильне для будь-яких двох конкретних дат.
Пітер Мортенсен

3

Дуже просто:

    <?php
        $date1 = date_create("2007-03-24");
        echo "Start date: ".$date1->format("Y-m-d")."<br>";
        $date2 = date_create("2009-06-26");
        echo "End date: ".$date2->format("Y-m-d")."<br>";
        $diff = date_diff($date1,$date2);
        echo "Difference between start date and end date: ".$diff->format("%y years, %m months and %d days")."<br>";
    ?>

Будь ласка, перегляньте наступне посилання для детальної інформації:

PHP: date_diff - Посібник

Зауважте, що це для PHP 5.3.0 або вище.


3

Проста функція

function time_difference($time_1, $time_2, $limit = null)
{

    $val_1 = new DateTime($time_1);
    $val_2 = new DateTime($time_2);

    $interval = $val_1->diff($val_2);

    $output = array(
        "year" => $interval->y,
        "month" => $interval->m,
        "day" => $interval->d,
        "hour" => $interval->h,
        "minute" => $interval->i,
        "second" => $interval->s
    );

    $return = "";
    foreach ($output AS $key => $value) {

        if ($value == 1)
            $return .= $value . " " . $key . " ";
        elseif ($value >= 1)
            $return .= $value . " " . $key . "s ";

        if ($key == $limit)
            return trim($return);
    }
    return trim($return);
}

Використовуйте як

echo time_difference ($time_1, $time_2, "day");

Повернеться як 2 years 8 months 2 days


3

Спробуйте цю дуже просту відповідь, використовуючи date_diff () , це перевірено.

$date1 = date_create("2017-11-27");
$date2 = date_create("2018-12-29");
$diff=date_diff($date1,$date2);
$months = $diff->format("%m months");
$years = $diff->format("%y years");
$days = $diff->format("%d days");

echo $years .' '.$months.' '.$days;

вихід:

1 years 1 months 2 days

2

Я використовую таку функцію, яку я написав, коли PHP 5.3 (відповідно date_diff ()) недоступний:

        function dateDifference($startDate, $endDate)
        {
            $startDate = strtotime($startDate);
            $endDate = strtotime($endDate);
            if ($startDate === false || $startDate < 0 || $endDate === false || $endDate < 0 || $startDate > $endDate)
                return false;

            $years = date('Y', $endDate) - date('Y', $startDate);

            $endMonth = date('m', $endDate);
            $startMonth = date('m', $startDate);

            // Calculate months
            $months = $endMonth - $startMonth;
            if ($months <= 0)  {
                $months += 12;
                $years--;
            }
            if ($years < 0)
                return false;

            // Calculate the days
            $measure = ($months == 1) ? 'month' : 'months';
            $days = $endDate - strtotime('+' . $months . ' ' . $measure, $startDate);
            $days = date('z', $days);   

            return array($years, $months, $days);
        }

2

DateInterval чудово, але в ньому є кілька застережень:

  1. лише для PHP 5.3+ ( але це вже справді не хороший привід )
  2. підтримує лише роки, місяці, дні, години, хвилини та секунди (без тижнів)
  3. він обчислює різницю за всіма переліченими вище + днями (різницю ви не можете отримати лише в місяцях)

Щоб подолати це, я зашифрував таке (покращено з відповіді @enobrev ):

function date_dif($since, $until, $keys = 'year|month|week|day|hour|minute|second')
{
    $date = array_map('strtotime', array($since, $until));

    if ((count($date = array_filter($date, 'is_int')) == 2) && (sort($date) === true))
    {
        $result = array_fill_keys(explode('|', $keys), 0);

        foreach (preg_grep('~^(?:year|month)~i', $result) as $key => $value)
        {
            while ($date[1] >= strtotime(sprintf('+%u %s', $value + 1, $key), $date[0]))
            {
                ++$value;
            }

            $date[0] = strtotime(sprintf('+%u %s', $result[$key] = $value, $key), $date[0]);
        }

        foreach (preg_grep('~^(?:year|month)~i', $result, PREG_GREP_INVERT) as $key => $value)
        {
            if (($value = intval(abs($date[0] - $date[1]) / strtotime(sprintf('%u %s', 1, $key), 0))) > 0)
            {
                $date[0] = strtotime(sprintf('+%u %s', $result[$key] = $value, $key), $date[0]);
            }
        }

        return $result;
    }

    return false;
}

Проходить дві петлі; перший розглядає відносні інтервали (роки та місяці) за допомогою грубого форсування, а другий обчислює додаткові абсолютні інтервали з простою арифметикою (так це швидше):

echo humanize(date_dif('2007-03-24', '2009-07-31', 'second')); // 74300400 seconds
echo humanize(date_dif('2007-03-24', '2009-07-31', 'minute|second')); // 1238400 minutes, 0 seconds
echo humanize(date_dif('2007-03-24', '2009-07-31', 'hour|minute|second')); // 20640 hours, 0 minutes, 0 seconds
echo humanize(date_dif('2007-03-24', '2009-07-31', 'year|day')); // 2 years, 129 days
echo humanize(date_dif('2007-03-24', '2009-07-31', 'year|week')); // 2 years, 18 weeks
echo humanize(date_dif('2007-03-24', '2009-07-31', 'year|week|day')); // 2 years, 18 weeks, 3 days
echo humanize(date_dif('2007-03-24', '2009-07-31')); // 2 years, 4 months, 1 week, 0 days, 0 hours, 0 minutes, 0 seconds

function humanize($array)
{
    $result = array();

    foreach ($array as $key => $value)
    {
        $result[$key] = $value . ' ' . $key;

        if ($value != 1)
        {
            $result[$key] .= 's';
        }
    }

    return implode(', ', $result);
}

@PeterMortensen: Це має працювати, але я не даю жодних гарантій. Встановіть свій часовий пояс і дайте йому піти.
Алікс Аксель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.