Question Comment calculer la différence entre deux dates en utilisant PHP?


J'ai deux dates du formulaire:

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

Maintenant, je dois trouver la différence entre ces deux sous la forme suivante:

2 years, 3 months and 2 days

Comment puis-je faire cela en PHP?


637
2018-03-24 10:33


origine


Réponses:


Pour PHP <5.3 sinon voir la réponse de jurka ci-dessous

Vous pouvez utiliser strtotime () pour convertir deux dates en unix puis calculer le nombre de secondes entre elles. De cela, il est plutôt facile de calculer différentes périodes.

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

Modifier: Évidemment, la façon préférée de faire cela est comme décrit par jurka ci-dessous. Mon code n'est généralement recommandé que si vous n'avez pas PHP 5.3 ou mieux.

Plusieurs personnes dans les commentaires ont souligné que le code ci-dessus n'est qu'une approximation. Je crois toujours que, dans la plupart des cas, c'est bien, puisque l'utilisation d'une gamme est plus pour donner une idée du temps qui s'est écoulé ou reste plutôt que de fournir une précision - si vous voulez faire cela, donnez simplement la date.

Malgré tout cela, j'ai décidé de répondre aux plaintes. Si vous avez vraiment besoin d'une gamme exacte mais que vous n'avez pas accès à PHP 5.3, utilisez le code ci-dessous (cela devrait aussi fonctionner en PHP 4). C'est un port direct du code que PHP utilise en interne pour calculer les plages, à l'exception du fait qu'il ne tient pas compte de l'heure d'été. Cela veut dire que c'est au plus une heure, mais à part ça, ça devrait être correct.

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

476
2018-03-24 10:35



Je suggère d'utiliser des objets DateTime et 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 ";

Lire la suite php DateTime :: diff manuel

Du manuel:

Depuis PHP 5.2.2, les objets DateTime peuvent être comparés en utilisant des opérateurs de comparaison.

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

808
2017-10-13 11:43



Le meilleur plan d'action utilise PHP DateTime (et DateInterval) objets. Chaque date est encapsulée dans un DateTime objet, puis une différence entre les deux peut être faite:

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

le DateTime objet acceptera n'importe quel format strtotime() aurait. Si un format de date encore plus spécifique est nécessaire, DateTime::createFromFormat() peut être utilisé pour créer le DateTime objet.

Après que les deux objets ont été instanciés, vous soustrayez l'un à l'autre avec DateTime::diff().

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

$difference maintenant détient un DateInterval objet avec l'information de différence. UNE var_dump() ressemble à ça:

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

Pour formater le DateInterval objet, nous aurons besoin de vérifier chaque valeur et l'exclure si c'est 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;
}

Tout ce qui reste maintenant est d'appeler notre fonction sur le $difference  DateInterval objet:

echo format_interval($difference);

Et nous obtenons le bon résultat:

20 jours 6 heures 56 minutes 30 secondes

Le code complet utilisé pour atteindre l'objectif:

/**
 * 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);

61
2017-11-30 15:25



Voir les heures et les minutes et les secondes.

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

33
2018-03-18 19:07



Jetez un oeil sur le lien suivant. C'est la meilleure réponse que j'ai trouvée jusqu'ici .. :)

function dateDiff ($d1, $d2) {

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

} // end function dateDiff

Peu importe quelle date est plus tôt ou plus tard quand vous passez dans le   paramètres de date. La fonction utilise la valeur absolue PHP ABS () pour   toujours retourner un nombre positif comme le nombre de jours entre les deux   Rendez-vous.

Gardez à l'esprit que le nombre de jours entre les deux dates n'est PAS   inclus les deux dates. Donc, si vous cherchez le nombre de jours   représenté par toutes les dates entre et y compris les dates saisies,   vous devrez ajouter un (1) au résultat de cette fonction.

Par exemple, la différence (telle que renvoyée par la fonction ci-dessus)   entre 2013-02-09 et 2013-02-14 est 5. Mais le nombre de jours ou   dates représentées par la plage de dates 2013-02-09 - 2013-02-14 est 6.

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


15
2017-07-25 14:37



J'ai voté pour jurkade répondre comme c'est mon préféré, mais j'ai une version pré-php.5.3 ...

Je me suis retrouvé à travailler sur un problème similaire - et c'est ainsi que je suis arrivé à cette question en premier lieu - mais j'avais juste besoin d'une différence d'heures. Mais ma fonction a aussi bien résolu celle-ci et je n'ai nulle part dans ma propre bibliothèque pour la garder là où elle ne sera pas perdue et oubliée, alors ... j'espère que cela sera utile à quelqu'un.

/**
 *
 * @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;
}

Et le test:

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

Et le résultat:

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

J'ai eu l'idée originale de ici, que j'ai modifié pour mes usages (et j'espère que ma modification apparaîtra également sur cette page).

Vous pouvez très facilement supprimer les intervalles que vous ne voulez pas (disons "semaine") en les retirant du $aIntervals tableau, ou peut-être ajouter un $aExclude paramètre, ou juste les filtrer lorsque vous produisez la chaîne.


12
2017-10-18 13:52



Je ne sais pas si vous utilisez un framework PHP ou non, mais beaucoup de frameworks PHP ont des bibliothèques de date / heure et des helpers pour vous aider à ne pas réinventer la roue.

Par exemple CodeIgniter a le timespan() fonction. Il suffit d'entrer deux horodatages Unix pour générer automatiquement un résultat comme celui-ci:

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

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


11
2018-02-17 18:29



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

10
2017-09-18 02:41



Utiliser un exemple:

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

Sortie:

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

Fonction :

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';
}

7
2018-03-24 10:41