Question Trouver le nombre de jours entre deux dates


Comment trouver le nombre de jours entre deux dates en utilisant PHP?


497
2018-01-11 08:06


origine


Réponses:


$now = time(); // or your date as well
$your_date = strtotime("2010-01-01");
$datediff = $now - $your_date;

echo round($datediff / (60 * 60 * 24));

743
2018-01-11 08:16



Si vous utilisez PHP 5.3 >, c'est de loin la façon la plus précise de calculer la différence:

$earlier = new DateTime("2010-07-06");
$later = new DateTime("2010-07-09");

$diff = $later->diff($earlier)->format("%a");

425
2018-04-23 19:18



À partir de la version 5.3 de PHP, nouvelles fonctions date / heure ont été ajoutés pour obtenir la différence:

$datetime1 = new DateTime("2010-06-20");

$datetime2 = new DateTime("2011-06-22");

$difference = $datetime1->diff($datetime2);

echo 'Difference: '.$difference->y.' years, ' 
                   .$difference->m.' months, ' 
                   .$difference->d.' days';

print_r($difference);

Résultat comme ci-dessous:

Difference: 1 years, 0 months, 2 days

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

J'espère que cela aide !


132
2018-03-24 09:55



Convertissez vos dates en timestamp unix, puis soustrayez-les l'une de l'autre. Cela vous donnera la différence en secondes, que vous divisez par 86400 (nombre de secondes dans une journée) pour vous donner une quantité approximative de jours dans cette fourchette.

Si vos dates sont en format 25.1.2010, 01/25/2010 ou 2010-01-25, vous pouvez utiliser le strtotime fonction:

$start = strtotime('2010-01-25');
$end = strtotime('2010-02-20');

$days_between = ceil(abs($end - $start) / 86400);

En utilisant ceil arrondit le nombre de jours jusqu'à la prochaine journée complète. Utilisation floor si vous voulez obtenir le nombre de jours complets entre ces deux dates.

Si vos dates sont déjà au format timestamp Unix, vous pouvez ignorer la conversion et effectuer le $days_between partie. Pour des formats de date plus exotiques, vous devrez peut-être faire quelques analyses personnalisées pour bien faire les choses.


121
2018-01-11 08:12



TL; DR faire ne pas utilisez les horodatages UNIX. Ne pas utiliser time(). Si tu fais, être préparé Si sa fiabilité à 98,0825% échoue. Utilisez DateTime (ou Carbon).

le bonne réponse est celui donné par Saksham Gupta (d'autres réponses sont également correctes):

$date1 = new DateTime('2010-07-06');
$date2 = new DateTime('2010-07-09');
$days  = $date2->diff($date1)->format('%a');

Ou de manière procédurale en un seul trait:

/**
 * Number of days between two dates.
 *
 * @param date $dt1    First date
 * @param date $dt2    Second date
 * @return int
 */
function daysBetween($dt1, $dt2) {
    return date_diff(
        date_create($dt2),  
        date_create($dt1)
    )->format('%a');
}

Si vous devez vraiment utiliser les horodatages UNIX, définir le fuseau horaire sur GMT éviter plus des pièges détaillés ci-dessous.


Réponse longue: pourquoi diviser par 24 * 60 * 60 (aka 86400) est dangereux

La plupart des réponses utilisant les horodatages UNIX (et 86400 pour convertir cela en jours) font deux hypothèses qui, ensemble, peuvent mener à des scénarios avec mauvais résultats et bugs subtils cela peut être difficile à suivre, et se produire même des jours, des semaines ou des mois après un déploiement réussi. Ce n'est pas que la solution ne fonctionne pas - ça fonctionne. Aujourd'hui. Mais ça pourrait cesser de fonctionner demain.

La première erreur ne tient pas compte du fait que, lorsqu'on lui demande: «Combien de jours se sont-ils écoulés depuis hier?», Un ordinateur peut vraiment répondre zéro si entre le présent et l'instant indiqué par "hier" moins de une journée entière a passé.

Habituellement, lors de la conversion d'un "jour" en un horodatage UNIX, ce qui est obtenu est l'horodatage du minuit de ce jour particulier.

Donc, entre le milieu du soir du 1er octobre et le 15 octobre, quinze jours se sont écoulés. Mais entre 13h00 du 1er octobre et 14h55 du 15 octobre, quinze jours moins 5 minutes ont écoulé, et la plupart des solutions utilisant floor() ou faire une conversion implicite d'entier rapportera un jour de moins que prévu.

Alors, "il y a combien de jours Y-m-d H: i: s"? va donner le mauvaise réponse.

La deuxième erreur équivaut un jour à 86400 secondes. C'est presque toujours C'est vrai - il arrive souvent assez pour ne pas voir les temps. Mais la distance en secondes entre deux midnights consécutifs est sûrement pas 86400 au moins deux fois par an lorsque l'heure d'été entre en jeu. La comparaison de deux dates dans une limite d'heure d'été donnera la mauvaise réponse.

Donc même si vous utilisez le "hack" de forcer tous les horodatages de date à une heure fixe, disons minuit (cela est également implicitement fait par différents langages et frameworks quand vous spécifiez seulement day-month-year et non hour-minute-second; mêmes heurpens avec le type DATE dans les bases de données telles que MySQL), la formule largement utilisée

 (unix_timestamp(DATE2) - unix_timestamp(DATE1)) / 86400

ou

 floor(time() - strtotime($somedate)) / 86400

retournera, disons, 17 lorsque DATE1 et DATE2 seront dans le même segment DST de l’année; mais il peut revenir 17.042, et pire encore, 16.958. L'utilisation de sol() ou toute troncature implicite en entier convertira alors ce qui aurait dû être un 17 en 16. Dans d'autres circonstances, des expressions telles que "$ days> 17" retourneront true pour 17.042 même si cela indique que le nombre de jours écoulés est de 18.

Et les choses deviennent encore plus moche puisque ce code n'est pas portable à travers les plates-formes, car certains d'entre eux peuvent appliquer des secondes intercalaires et certains pourraient ne pas. Sur ces plateformes faire, la différence entre deux dates ne sera pas 86400 mais 86401, ou peut-être 86399. Donc, le code qui a fonctionné en mai et qui a effectivement passé tous les tests se brisera en juin prochain alors que 12.99999 jours sont considérés comme 12 jours au lieu de 13. ne fonctionne pas en 2017 - le même dates, et aucune de ces deux années n'est une année bissextile. Mais entre 2018-03-01 et 2017-03-01, sur les plates-formes qui se soucient, 366 les jours auront passé au lieu de 365, faisant de 2017 une année bissextile.

Donc, si vous voulez vraiment utiliser les horodatages UNIX:

  • utilisation round() fonctionner judicieusement, pas floor().

  • en guise d'alternative, ne calculez pas les différences entre D1-M1-YYY1 et D2-M2-YYY2. Ces dates seront vraiment considérées comme D1-M1-YYY1 00:00:00 et D2-M2-YYY2 00:00:00. Au contraire, convertir entre D1-M1-YYY1 22:30:00 et D2-M2-YYY2 04:30:00. Vous serez toujours obtenir un reste d'environ vingt heures. Cela peut devenir vingt et une heures ou dix-neuf, et peut-être dix-huit heures, cinquante-neuf minutes trente-six secondes. Peu importe. C'est un grande marge qui restera là et restera positif dans un avenir prévisible. À présent vous pouvez le tronquer avec floor() En sécurité.

le correct solution cependant, pour éviter les constantes magiques, arrondir les kludges et une dette de maintenance, est de

  • utiliser une bibliothèque de temps (Datetime, Carbon, peu importe); ne roule pas ton propre

  • écrire cas de test complets en utilisant des choix de date vraiment mauvais - à travers les limites de l'heure d'été, à travers les années bissextiles, à travers les secondes intercalaires, et ainsi de suite, ainsi que des dates banales. Idéalement (les appels à datetime sont vite!) produire quatre années entières (et un jour)valeur des dates en les assemblant à partir de chaînes, séquentiellement, et assurez-vous que la différence entre le premier jour et le jour testé augmente régulièrement d'un. Cela garantira que si quelque chose change dans les routines de bas niveau et les secondes intercalaires correctifs essayer de faire des ravages, au moins vous aurez connaître.

  • exécutez ces tests régulièrement avec le reste de la suite de tests. Ils sont une question de millisecondes et peuvent vous sauver littéralement heures de gratter la tête.


Quelle que soit votre solution, testez-la!

La fonction funcdiff ci-dessous met en œuvre l'une des solutions (en l'occurrence, la solution acceptée) dans un scénario réel.

<?php
$tz         = 'Europe/Rome';
$yearFrom   = 1980;
$yearTo     = 2020;
$verbose    = false;

function funcdiff($date2, $date1) {
    $now        = strtotime($date2);
    $your_date  = strtotime($date1);
    $datediff   = $now - $your_date;
    return floor($datediff / (60 * 60 * 24));
}
########################################

date_default_timezone_set($tz);
$failures   = 0;
$tests      = 0;

$dom = array ( 0, 31, 28, 31, 30,
                  31, 30, 31, 31,
                  30, 31, 30, 31 );
(array_sum($dom) === 365) || die("Thirty days hath November...");
$last   = array();
for ($year = $yearFrom; $year < $yearTo; $year++) {
    $dom[2] = 28;
    // Apply leap year rules.
    if ($year % 4 === 0)   { $dom[2] = 29; }
    if ($year % 100 === 0) { $dom[2] = 28; }
    if ($year % 400 === 0) { $dom[2] = 29; }
    for ($month = 1; $month <= 12; $month ++) {
        for ($day = 1; $day <= $dom[$month]; $day++) {
            $date = sprintf("%04d-%02d-%02d", $year, $month, $day);
            if (count($last) === 7) {
                $tests ++;
                $diff = funcdiff($date, $test = array_shift($last));
                if ((double)$diff !== (double)7) {
                    $failures ++;
                    if ($verbose) {
                        print "There seem to be {$diff} days between {$date} and {$test}\n";
                    }
                }
            }
            $last[] = $date;
        }
    }
}

print "This function failed {$failures} of its {$tests} tests between {$yearFrom} and {$yearTo}.\n";

Le résultat est,

This function failed 280 of its 14603 tests

Histoire d'horreur: le coût de "gagner du temps"

Cela s'est effectivement passé il y a quelques mois. Un ingénieux programmeur a décidé de sauver plusieurs microsecondes d'un calcul qui prenait au maximum une trentaine de secondes, en branchant le tristement célèbre code "(MidnightOfDateB-MidnightOfDateA) / 86400" à plusieurs endroits. C'était une optimisation tellement évidente qu'il ne l'a même pas documentée, et l'optimisation a réussi les tests d'intégration et s'est caché dans le code pendant plusieurs mois, tout cela sans être remarqué.

Cela s'est produit dans un programme qui calcule les salaires de plusieurs vendeurs les plus vendus, dont le moins a un poids beaucoup plus effrayant que l'ensemble d'une humble équipe de programmeurs composée de cinq personnes. Un jour il y a quelques mois, pour des raisons qui importent peu, le bug a frappé - et certains de ces gars-là ont été écourtés une journée entière de grosses commissions. Ils étaient définitivement ne pas amusé.

Infiniment pire, ils ont perdu la foi (déjà très peu) qu'ils avaient dans le programme ne pas étant conçu pour les enfoncer subrepticement, et prétendu - et obtenu - un examen complet et détaillé du code avec des cas de tests exécutés et commentés en termes simples (plus beaucoup de traitement tapis rouge dans les semaines suivantes).

Ce que je peux dire: du côté positif, nous nous sommes débarrassés de beaucoup de dettes techniques, et avons été en mesure de réécrire et de refactoriser plusieurs morceaux d'un gâchis de spaghettis qui rappelait une infestation de COBOL dans les années 1990. Le programme s'exécute sans aucun doute mieux maintenant, et il y a beaucoup plus d'informations de débogage pour se concentrer rapidement quand quelque chose semble louche. J'estime que cette dernière chose sauvera peut-être un ou deux jours-hommes par mois dans un avenir prévisible.

Du côté négatif, tout le brouhaha a coûté à l'entreprise environ 200 000 € d'avance - plus le visage, sans doute un peu de pouvoir de négociation (et, par conséquent, encore plus d'argent).

Le gars responsable de l '«optimisation» avait changé de travail il y a un an, avant la catastrophe, mais il y avait encore des discussions pour le poursuivre en justice pour dommages. Et ça ne s'est pas bien passé avec les échelons supérieurs que c'était "la faute du dernier gars" - cela ressemblait à une mise en place pour que nous puissions régler la question, et à la fin, nous sommes toujours dans la niche et l'un des membres de l'équipe prévoit d'arrêter.

Quatre-vingt-dix-neuf fois sur cent, le "hack 86400" fonctionnera parfaitement. (Par exemple en PHP, strtotime()ignorera l'heure d'été et signalera qu'entre le milieu du deuxième samedi d'octobre et celui du lundi suivant, exactement 2 * 24 * 60 * 60 secondes se sont écoulées, même si c'est clairement pas vrai... et deux torts feront heureusement un droit).

Ceci, mesdames et messieurs, était un par exemple quand ce n'est pas le cas. Comme avec les air-bags et les ceintures de sécurité, vous ne serez peut-être jamais vraiment besoin de la complexité (et de la facilité d'utilisation) de DateTime ou Carbon. Mais le jour où vous pourrait (ou le jour où vous devrez prouver vous avez pensé à cela) viendra comme un voleur dans la nuit. Soyez prêt.


48
2017-07-02 23:40



Facile à utiliser date_diff

$from=date_create(date('Y-m-d'));
$to=date_create("2013-03-15");
$diff=date_diff($to,$from);
print_r($diff);
echo $diff->format('%R%a days');

16
2018-01-09 19:20



Style orienté objet:

$datetime1 = new DateTime('2009-10-11');
$datetime2 = new DateTime('2009-10-13');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%R%a days');

Style procédural:

$datetime1 = date_create('2009-10-11');
$datetime2 = date_create('2009-10-13');
$interval = date_diff($datetime1, $datetime2);
echo $interval->format('%R%a days');

15
2017-12-10 06:43