Ich denke, die Rückgabe einer negativen Anzahl von Tagen liefert relevante Informationen. Und Sie sollten verwenden $your_date-$now, wenn Sie möchten, dass ein zukünftiges Datum eine positive Ganzzahl zurückgibt.
Tim
23
Was ist mit Schaltsekunden? Nicht alle Tage haben genau 24 * 60 * 60 Sekunden. Dieser Code mag für praktische Zwecke ausreichend sein, ist jedoch in einigen extrem seltenen Randfällen nicht genau.
Benjamin Brizzi
49
Vergessen Sie Schaltsekunden (nein, berücksichtigen Sie diese auch), aber dies berücksichtigt NICHT die Änderungen der Sommerzeit! Es kann jedes Jahr um einen ganzen Tag über diese Grenzen hinausgehen. Sie müssen die DateTime-Klassen verwenden.
Levi
6
@billynoah Entschuldigung, ich bin nie zurückgekommen, um meinen Kommentar zu aktualisieren. Sie müssen mit Sommerzeitzonen vorsichtig sein. Wenn Sie ein Datum mit der Sommerzeit vergleichen, wird ein Datum ohne dieses Datum angezeigt. Statt beispielsweise 7 Tage zurückzugeben, werden 6,9 Tage zurückgegeben. Das Wort zu ergreifen gibt 6 statt 7 zurück.
Alex Angelico
4
Strtotime () schlägt nicht nur in 20 Jahren fehl, es ist auch momentan unbrauchbar. Das OP gab Daten an, nicht die Zeit. Termine können ziemlich alt sein. Hier ist eine einfachere Antwort: $ NumberDays = gregoriantojd ($ EndM, $ EndD, $ EndY) - gregoriantojd ($ StartM, $ StartD, $ StartY); (für einen inklusive Bereich). Im Gegensatz zur Datetime-Klasse ist Gregorian to Julian ab Version 4 verfügbar. Gültiger Bereich ist 4714 v. Chr. Bis 9999 n. Chr. Achten Sie auf die funky Parameterreihenfolge (wie Sie diese Warnung für PHP benötigen).
Guy Gordon
524
Wenn Sie verwenden PHP 5.3 >, ist dies bei weitem die genaueste Methode zur Berechnung der Differenz:
Beachten Sie, dass sich die Formatsyntax von der Syntax date () und strftime () unterscheidet, da es sich um Zeitintervalle handelt, die nicht zu bestimmten Zeitpunkten vorliegen. Die Zeitintervallsyntax finden Sie hier: php.net/manual/en/dateinterval.format.php
Andrew
1
oder in meinem Fall ist die Anzahl der Tage zwischen $ date2-> diff ($ date1) -> format ("% a") - 1
xeo
13
Denken Sie daran, dass dies nicht wie erwartet funktioniert, wenn Sie Zeiten in Ihren Daten haben. Wenn Sie beispielsweise ein Intervall von 23:30 Stunden haben ... und diese an verschiedenen Tagen liegen,
beträgt
20
Wenn Sie eine relative Anzahl von Tagen benötigen (negativ, wenn $date1vor $date2), verwenden Sie $diff = $date2->diff($date1)->format("%r%a");stattdessen.
Socce
1
Was ist das Format des Datums in DateTime("2010-07-06")?, Ist es Y-m-doder Y-d-m?, Was ist das Format des DateTimeParameters. Welches ist Tag?
Ja, dies scheint besser zu sein als die akzeptierte Antwort, die in einigen Fällen nicht funktioniert. Gefällt mir: $ from = '2014-03-01'; $ to = '2014-03-31';
MBozic
1
Ich stimme zu, so einfach zu folgen und funktioniert super !!! Vergessen Sie nur nicht, die Funktion date_default_timezone_set () zu verwenden, da Sie sonst seltsame Ergebnisse basierend auf der UTC-Zeit erhalten.
Zeckdude
2
Diese Funktion hat 0 von 14603 Tests zwischen 1980 und 2020 nicht bestanden.
LSerni
128
Konvertieren Sie Ihre Daten in Unix-Zeitstempel und subtrahieren Sie sie dann voneinander. Dies gibt Ihnen die Differenz in Sekunden, die Sie durch 86400 (Anzahl der Sekunden pro Tag) dividieren, um eine ungefähre Anzahl von Tagen in diesem Bereich zu erhalten.
Wenn Ihre Daten im Format oder vorliegen 25.1.2010, können Sie die folgende Funktion verwenden:01/25/20102010-01-25strtotime
Mit ceilRunden die Anzahl der Tage bis zum nächsten vollen Tag. Verwenden Sie floorstattdessen, wenn Sie die Anzahl der vollen Tage zwischen diesen beiden Daten abrufen möchten.
Wenn Ihre Daten bereits im Unix-Zeitstempelformat vorliegen, können Sie die Konvertierung überspringen und nur den $days_betweenTeil ausführen . Für exotischere Datumsformate müssen Sie möglicherweise eine benutzerdefinierte Analyse durchführen, um die richtigen Ergebnisse zu erzielen.
@ toon81 - Wir verwenden Unix-Zeitstempel , um solche Probleme zu vermeiden! ;)
Alastair
6
Lassen Sie mich näher darauf eingehen: Nehmen wir an, dass heute Morgen um 3 Uhr morgens fast ganz Europa die Uhr um eine Stunde zurückgestellt hat. Das bedeutet, dass heute zusätzliche 3600 Sekunden zur Verfügung stehen, was sich in den UNIX-Zeitstempeln widerspiegeln sollte. Wenn dies der Fall ist, bedeutet dies, dass der heutige Tag mit der oben beschriebenen Methode zur Berechnung der Anzahl der Tage zwei Tage zählt. Und ich fange noch nicht einmal mit Schaltsekunden an, da weder PHP noch UNIX diese zu erklären scheinen (was IMO eigentlich verständlich ist). TL; DR: Nicht alle Tage sind 86.400 Sekunden lang .
Toon81
2
@ toon81 Es gibt KEINE weiteren 3600 Sekunden für dieses Datum. Mit dem UNIX-Zeitstempel passiert nichts, wenn Sie zur oder von der Sommerzeit gehen.
Nickdnk
1
Wenn mit dem UNIX-Zeitstempel nichts passiert, stimmen Sie mir zu: Der Unterschied zwischen dem UNIX-Zeitstempel um 13:00 Uhr $dayund dem UNIX-Zeitstempel um 13:00 Uhr $day+1beträgt in Zeitzonen, in denen die Sommerzeit eingehalten wird, nicht immer 86400 Sekunden. Es kann Sekunden im Wert von 23 oder 25 Stunden statt 24 Stunden sein.
Toon81
112
TL; DR verwenden keine UNIX-Zeitstempel. Nicht verwendentime() . Wenn Sie dies tun, sollten Sie darauf vorbereitet sein, wenn die Zuverlässigkeit von 98,0825% Sie nicht erfüllt. Verwenden Sie DateTime (oder Carbon).
Die richtige Antwort ist die von Saksham Gupta (andere Antworten sind auch richtig):
/**
* 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');}
Mit einer Einschränkung: Das '% a' scheint die absolute Anzahl von Tagen anzugeben . Wenn Sie es als vorzeichenbehaftete Ganzzahl möchten, dh negativ, wenn das zweite Datum vor dem ersten liegt, müssen Sie das Präfix '% r' (dh format('%r%a')) verwenden.
Wenn Sie wirklich UNIX-Zeitstempel verwenden müssen, stellen Sie die Zeitzone auf GMT ein , um die meisten der unten aufgeführten Fallstricke zu vermeiden .
Lange Antwort: Warum das Teilen durch 24 * 60 * 60 (auch bekannt als 86400) unsicher ist
Die meisten Antworten, die UNIX-Zeitstempel verwenden (und 86400, um diese in Tage umzuwandeln), gehen von zwei Annahmen aus, die zusammengenommen zu Szenarien mit falschen Ergebnissen und subtilen Fehlern führen können , die möglicherweise schwer zu verfolgen sind und sogar Tage, Wochen oder Monate später auftreten eine erfolgreiche Bereitstellung. Es ist nicht so, dass die Lösung nicht funktioniert - es funktioniert. Heute. Aber es könnte morgen aufhören zu arbeiten.
Der erste Fehler besteht nicht darin, dass ein Computer bei der Frage "Wie viele Tage sind seit gestern vergangen?" Wahrhaftig mit Null antworten kann, wenn zwischen der Gegenwart und dem durch "gestern" angegebenen Moment weniger als ein ganzer Tag vergangen ist.
Wenn Sie einen "Tag" in einen UNIX-Zeitstempel konvertieren, erhalten Sie normalerweise den Zeitstempel für die Mitternacht dieses bestimmten Tages.
Zwischen der Mitte des 1. und 15. Oktober sind also fünfzehn Tage vergangen. Zwischen 13:00 Uhr am 1. Oktober und 14:55 Uhr am 15. Oktober sind jedoch fünfzehn Tage minus 5 Minuten vergangen, und die meisten Lösungen, floor()die eine implizite Ganzzahlkonvertierung verwenden oder durchführen, melden einen Tag weniger als erwartet .
Also, "vor wie vielen Tagen war Ymd H: i: s"? wird die falsche Antwort geben .
Der zweite Fehler entspricht einem Tag 86400 Sekunden. Dies ist fast immer der Fall - es passiert oft genug, um die Zeiten zu übersehen, in denen dies nicht der Fall ist. Aber der Abstand in Sekunden zwischen zwei aufeinanderfolgenden Mitternächten beträgt sicherlich nicht mindestens zweimal im Jahr 86400, wenn die Sommerzeit ins Spiel kommt. Wenn Sie zwei Daten über eine Sommerzeitgrenze hinweg vergleichen, erhalten Sie die falsche Antwort.
Selbst wenn Sie den "Hack" verwenden, um alle Datumszeitstempel auf eine feste Stunde zu zwingen, z. B. Mitternacht (dies geschieht implizit auch durch verschiedene Sprachen und Frameworks, wenn Sie nur Tag-Monat-Jahr und nicht auch Stunde-Minute-Sekunde angeben. Gleiches gilt für den DATE-Typ in Datenbanken wie MySQL, der weit verbreiteten Formel
wird beispielsweise 17 zurückgeben, wenn sich DATE1 und DATE2 im selben DST-Segment des Jahres befinden; aber es kann 17.042 und noch schlimmer 16.958 zurückgeben. Die Verwendung von floor () oder einer impliziten Kürzung in eine Ganzzahl konvertiert dann eine 17 in eine 16. Unter anderen Umständen werden Ausdrücke wie "$ days> 17" truefür 17.042 zurückgegeben, selbst wenn dies anzeigt, dass der verstrichene Tag zählt ist 18.
Und die Dinge werden noch hässlicher, da ein solcher Code nicht plattformübergreifend portierbar ist, da einige von ihnen möglicherweise Schaltsekunden anwenden und andere nicht . Auf diesen Plattformen , die nicht die Differenz zwischen zwei Daten, nicht aber 86400 86401, oder vielleicht 86399. sein So - Code, der im Juni nächsten Jahres bricht im Mai und bestanden tatsächlich alle Tests gearbeitet , als 12,99999 Tage 12 Tage statt 13. Zwei Tage , in Betracht gezogen werden dass im Jahr 2015 gearbeitet wird nicht funktionieren , im Jahr 2017 - die gleichen Daten und weder Jahr ein Schaltjahr ist . Aber zwischen dem 01.03.2018 und dem 01.03.2017 sind auf den Plattformen, die sich darum kümmern, 366 Tage statt 365 vergangen, was 2018 zu einem Schaltjahr macht (was es nicht ist).
Wenn Sie also wirklich UNIX-Zeitstempel verwenden möchten:
Verwenden Sie die round()Funktion mit Bedacht, nicht floor().
Berechnen Sie alternativ keine Unterschiede zwischen D1-M1-YYY1 und D2-M2-YYY2. Diese Daten werden wirklich als D1-M1-YYY1 00:00:00 und D2-M2-YYY2 00:00:00 betrachtet. Konvertieren Sie stattdessen zwischen D1-M1-YYY1 22:30:00 und D2-M2-YYY2 04:30:00. Sie erhalten immer einen Rest von etwa zwanzig Stunden. Dies kann einundzwanzig Stunden oder neunzehn und vielleicht achtzehn Stunden, neunundfünfzig Minuten und sechsunddreißig Sekunden werden. Ganz gleich. Es ist eine große Marge, die dort bleiben und auf absehbare Zeit positiv bleiben wird. Jetzt können Sie es mit gestutzt floor()in Sicherheit.
Die richtige Lösung, um magische Konstanten, Rundungen und Wartungsschulden zu vermeiden, ist jedoch
Verwenden Sie eine Zeitbibliothek (Datetime, Carbon, was auch immer). roll nicht deine eigenen
Schreiben Sie umfassende Testfälle mit wirklich schlechten Datumsentscheidungen - über Sommerzeitgrenzen hinweg, über Schaltjahre, über Schaltsekunden usw. hinweg sowie über alltägliche Daten. Im Idealfall (Aufrufe von datetime sind schnell !) Generieren Sie Daten im Wert von vier ganzen Jahren (und einem Tag) , indem Sie sie nacheinander aus Zeichenfolgen zusammensetzen, und stellen Sie sicher, dass der Unterschied zwischen dem ersten Tag und dem getesteten Tag stetig um eins zunimmt. Auf diese Weise wird sichergestellt, dass Sie zumindest wissen , ob sich Änderungen an den Routinen auf niedriger Ebene und an Korrekturen in Schaltsekunden ergeben, die Chaos anrichten .
Führen Sie diese Tests regelmäßig zusammen mit dem Rest der Testsuite aus. Sie sind eine Frage von Millisekunden und können Ihnen buchstäblich Stunden des Kopfkratzens ersparen .
Was auch immer Ihre Lösung ist, testen Sie sie!
Die folgende Funktion funcdiffimplementiert eine der Lösungen (zufällig die akzeptierte) in einem realen Szenario.
<?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 September...");
$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";
Das Ergebnis ist,
Thisfunction failed 280of its 14603 tests
Horror Story: Die Kosten für "Zeit sparen"
Dies geschah tatsächlich vor einigen Monaten. Ein genialer Programmierer beschloss, einige Mikrosekunden bei einer Berechnung zu sparen, die höchstens 30 Sekunden dauerte, indem er den berüchtigten Code "(MidnightOfDateB-MidnightOfDateA) / 86400" an mehreren Stellen einfügte. Es war eine so offensichtliche Optimierung, dass er sie nicht einmal dokumentierte, und die Optimierung bestand die Integrationstests und lauerte mehrere Monate lang unbemerkt im Code.
Dies geschah in einem Programm, das die Löhne für mehrere meistverkaufte Verkäufer berechnet, von denen der geringste viel mehr Einfluss hat als ein ganzes bescheidenes fünfköpfiges Programmierteam zusammen. Eines Tages vor einigen Monaten schlug der Fehler aus unerheblichen Gründen zu - und einige dieser Leute hatten einen ganzen Tag lang einen Mangel an fetten Provisionen. Sie waren definitiv nicht amüsiert.
Unendlich schlimmer, sie verloren das (bereits sehr geringe) Vertrauen in das Programm, das nicht dazu gedacht war, sie heimlich zu beschützen, und gaben vor - und erhielten - eine vollständige, detaillierte Codeüberprüfung mit Testfällen, die in Laienbegriffen ausgeführt und kommentiert wurden (plus viel) der Behandlung auf dem roten Teppich in den folgenden Wochen).
Was kann ich sagen: Auf der positiven Seite haben wir eine Menge technischer Schulden beseitigt und konnten mehrere Teile eines Spaghetti-Chaos umschreiben und umgestalten, das auf einen COBOL-Befall in den schwingenden 90ern zurückging. Das Programm läuft jetzt zweifellos besser und es gibt viel mehr Debugging-Informationen, die Sie schnell finden können, wenn etwas faul aussieht. Ich schätze, dass nur diese letzte Sache auf absehbare Zeit vielleicht ein oder zwei Manntage pro Monat einsparen wird.
Auf der negativen Seite kostete das ganze Brouhaha das Unternehmen im Voraus etwa 200.000 Euro - plus Gesicht plus zweifellos etwas Verhandlungsmacht (und damit noch mehr Geld).
Der für die "Optimierung" verantwortliche Mann hatte vor einem Jahr vor der Katastrophe den Job gewechselt, aber es war immer noch die Rede davon, ihn auf Schadensersatz zu verklagen. Und es passte nicht gut zu den oberen Rängen, dass es "die Schuld des letzten Mannes" war - es sah nach einer Vorbereitung für uns aus, um die Angelegenheit zu klären, und am Ende sind wir immer noch in der Hundehütte und einer aus dem Team plant aufzuhören.
Neunundneunzig von einhundert Mal funktioniert der "86400-Hack" einwandfrei. ( strtotime()Ignoriert beispielsweise in PHP die Sommerzeit und meldet, dass zwischen der Nacht des letzten Samstags im Oktober und der des folgenden Montags genau 2 * 24 * 60 * 60 Sekunden vergangen sind, auch wenn dies eindeutig nicht zutrifft ... und zwei Fehler machen glücklich einen richtig).
Dies, meine Damen und Herren, war ein Fall, in dem dies nicht der Fall war. Wie bei Airbags und Sicherheitsgurten werden Sie die Komplexität (und Benutzerfreundlichkeit) von oder vielleicht nie wirklich brauchen . Aber der Tag, an dem Sie könnten (oder der Tag, an dem Sie beweisen müssen, dass Sie darüber nachgedacht haben), wird in der Nacht als Dieb kommen. Sei vorbereitet.DateTimeCarbon
Als ich diese Antworten sah, dachte ich, ich sei dumm und verrückt, weil ich immer DateTime verwende, aber Sie haben mir klar gemacht, dass die Verwendung von DateTime der richtige Weg ist. Vielen Dank
Syncro
Hey, alle hier auf SO sind hierher gekommen, indem sie in Google days between two days in phpoder ähnlichem gesucht haben , nur weil das Leben zu kurz ist, um alles selbst zu schreiben.
Denis Matafonov
1
detaillierte Erklärung. + 1
Anant Singh --- Lebendig zu sterben
1
Manchmal wünschte ich, wir könnten die Antworten anstelle der Frage favorisieren.
Dies ist eine gute prozedurale Methode, um dies mit der DateTime-Klasse zu tun. Es fehlt nur eine eindeutige Verwendung des Intervallobjekts ( $diffin diesem Fall variabel). So etwas wie if ($diff->days > 30) { [doyourstuff]; }
Sehr alter Kommentar oben, aber er ist falsch. Stackoverflow nicht ermöglicht es Ihnen , Ihre eigene Frage zu beantworten (auch wenn Sie fragen Ihre Frage). Die Beantwortung der Frage selbst, nachdem bereits jemand dieselbe Lösung veröffentlicht hat, wird jedoch als unhöflich angesehen.
Maarten Bodewes
Diese Funktion hat 560 seiner 14603 Tests zwischen 1980 und 2020 nicht bestanden.
LSerni
10
Nun, die ausgewählte Antwort ist nicht die richtigste, da sie außerhalb von UTC fehlschlägt. Abhängig von der Zeitzone ( Liste ) kann es zu Zeitanpassungen kommen, die Tage "ohne" 24 Stunden erzeugen. Dadurch schlägt die Berechnung (60 * 60 * 24) fehl.
Hier ist es ein Beispiel dafür:
date_default_timezone_set('europe/lisbon');
$time1 = strtotime('2016-03-27');
$time2 = strtotime('2016-03-29');
echo floor(($time2-$time1)/(60*60*24));^-- the output will be **1**
Die richtige Lösung wird also DateTime verwenden
date_default_timezone_set('europe/lisbon');
$date1 =newDateTime("2016-03-27");
$date2 =newDateTime("2016-03-29");
echo $date2->diff($date1)->format("%a");^-- the output will be **2**
function dateDiff($date1, $date2)//days find function{
$diff = strtotime($date2)- strtotime($date1);return abs(round($diff /86400));}//start day
$date1 ="11-10-2018";// end day
$date2 ="31-10-2018";// call the days find fun store to variable
$dateDiff = dateDiff($date1, $date2);
echo "Difference between two dates: ". $dateDiff ." Days ";
Bei älteren Fragen mit vorhandenen Antworten ist es hilfreich zu erklären, welchen neuen Aspekt Ihre Antwort auf die Frage bringt. Falls relevant, ist es auch nützlich, Änderungen zu bestätigen, die möglicherweise seit dem Stellen der Frage aufgetreten sind.
// Change this to the day in the future
$day =15;// Change this to the month in the future
$month =11;// Change this to the year in the future
$year =2012;// $days is the number of days between now and the date in the future
$days =(int)((mktime (0,0,0,$month,$day,$year)- time(void))/86400);
echo "There are $days days until $day/$month/$year";
Willkommen bei SO! Wenn Sie auf einen Beitrag nur mit Code antworten, erklären Sie ihn bitte ein wenig. Der Code, den Sie mitbringen, wird zwischen 2019-11-10 und 2019-11-25 berechnet. Es wird also nicht auf die Frage geantwortet. Deshalb ist es gut, deine POV besser zu erklären, als herabgestimmt zu werden.
David García Bodego
0
Wenn Sie MySQL verwenden
function daysSince($date, $date2){
$q ="SELECT DATEDIFF('$date','$date2') AS days;";
$result = execQ($q);
$row = mysql_fetch_array($result,MYSQL_BOTH);return($row[0]);
Im Allgemeinen verwende ich 'DateTime', um Tage zwischen zwei Daten zu finden. Wenn jedoch auf einem Server-Setup aus irgendeinem Grund 'DateTime' nicht aktiviert ist, wird eine einfache (aber nicht sichere) Berechnung mit 'strtotime ()' verwendet.
(new DateTime("2010-01-11"))->diff(new DateTime("2019-08-19"))->days;
Antworten:
quelle
$your_date-$now
, wenn Sie möchten, dass ein zukünftiges Datum eine positive Ganzzahl zurückgibt.Wenn Sie verwenden
PHP 5.3 >
, ist dies bei weitem die genaueste Methode zur Berechnung der Differenz:quelle
$date1
vor$date2
), verwenden Sie$diff = $date2->diff($date1)->format("%r%a");
stattdessen.DateTime("2010-07-06")
?, Ist esY-m-d
oderY-d-m
?, Was ist das Format desDateTime
Parameters. Welches ist Tag?Ab PHP Version 5.3 wurden neue Datums- / Uhrzeitfunktionen hinzugefügt, um Unterschiede zu erzielen:
Ergebnis wie folgt:
Ich hoffe es hilft !
quelle
Konvertieren Sie Ihre Daten in Unix-Zeitstempel und subtrahieren Sie sie dann voneinander. Dies gibt Ihnen die Differenz in Sekunden, die Sie durch 86400 (Anzahl der Sekunden pro Tag) dividieren, um eine ungefähre Anzahl von Tagen in diesem Bereich zu erhalten.
Wenn Ihre Daten im Format oder vorliegen
25.1.2010
, können Sie die folgende Funktion verwenden:01/25/2010
2010-01-25
strtotime
Mit
ceil
Runden die Anzahl der Tage bis zum nächsten vollen Tag. Verwenden Siefloor
stattdessen, wenn Sie die Anzahl der vollen Tage zwischen diesen beiden Daten abrufen möchten.Wenn Ihre Daten bereits im Unix-Zeitstempelformat vorliegen, können Sie die Konvertierung überspringen und nur den
$days_between
Teil ausführen . Für exotischere Datumsformate müssen Sie möglicherweise eine benutzerdefinierte Analyse durchführen, um die richtigen Ergebnisse zu erzielen.quelle
$day
und dem UNIX-Zeitstempel um 13:00 Uhr$day+1
beträgt in Zeitzonen, in denen die Sommerzeit eingehalten wird, nicht immer 86400 Sekunden. Es kann Sekunden im Wert von 23 oder 25 Stunden statt 24 Stunden sein.TL; DR verwenden keine UNIX-Zeitstempel. Nicht verwenden
time()
. Wenn Sie dies tun, sollten Sie darauf vorbereitet sein, wenn die Zuverlässigkeit von 98,0825% Sie nicht erfüllt. Verwenden Sie DateTime (oder Carbon).Die richtige Antwort ist die von Saksham Gupta (andere Antworten sind auch richtig):
Oder prozedural als Einzeiler:
Mit einer Einschränkung: Das '% a' scheint die absolute Anzahl von Tagen anzugeben . Wenn Sie es als vorzeichenbehaftete Ganzzahl möchten, dh negativ, wenn das zweite Datum vor dem ersten liegt, müssen Sie das Präfix '% r' (dh
format('%r%a')
) verwenden.Wenn Sie wirklich UNIX-Zeitstempel verwenden müssen, stellen Sie die Zeitzone auf GMT ein , um die meisten der unten aufgeführten Fallstricke zu vermeiden .
Lange Antwort: Warum das Teilen durch 24 * 60 * 60 (auch bekannt als 86400) unsicher ist
Die meisten Antworten, die UNIX-Zeitstempel verwenden (und 86400, um diese in Tage umzuwandeln), gehen von zwei Annahmen aus, die zusammengenommen zu Szenarien mit falschen Ergebnissen und subtilen Fehlern führen können , die möglicherweise schwer zu verfolgen sind und sogar Tage, Wochen oder Monate später auftreten eine erfolgreiche Bereitstellung. Es ist nicht so, dass die Lösung nicht funktioniert - es funktioniert. Heute. Aber es könnte morgen aufhören zu arbeiten.
Der erste Fehler besteht nicht darin, dass ein Computer bei der Frage "Wie viele Tage sind seit gestern vergangen?" Wahrhaftig mit Null antworten kann, wenn zwischen der Gegenwart und dem durch "gestern" angegebenen Moment weniger als ein ganzer Tag vergangen ist.
Wenn Sie einen "Tag" in einen UNIX-Zeitstempel konvertieren, erhalten Sie normalerweise den Zeitstempel für die Mitternacht dieses bestimmten Tages.
Zwischen der Mitte des 1. und 15. Oktober sind also fünfzehn Tage vergangen. Zwischen 13:00 Uhr am 1. Oktober und 14:55 Uhr am 15. Oktober sind jedoch fünfzehn Tage minus 5 Minuten vergangen, und die meisten Lösungen,
floor()
die eine implizite Ganzzahlkonvertierung verwenden oder durchführen, melden einen Tag weniger als erwartet .Also, "vor wie vielen Tagen war Ymd H: i: s"? wird die falsche Antwort geben .
Der zweite Fehler entspricht einem Tag 86400 Sekunden. Dies ist fast immer der Fall - es passiert oft genug, um die Zeiten zu übersehen, in denen dies nicht der Fall ist. Aber der Abstand in Sekunden zwischen zwei aufeinanderfolgenden Mitternächten beträgt sicherlich nicht mindestens zweimal im Jahr 86400, wenn die Sommerzeit ins Spiel kommt. Wenn Sie zwei Daten über eine Sommerzeitgrenze hinweg vergleichen, erhalten Sie die falsche Antwort.
Selbst wenn Sie den "Hack" verwenden, um alle Datumszeitstempel auf eine feste Stunde zu zwingen, z. B. Mitternacht (dies geschieht implizit auch durch verschiedene Sprachen und Frameworks, wenn Sie nur Tag-Monat-Jahr und nicht auch Stunde-Minute-Sekunde angeben. Gleiches gilt für den DATE-Typ in Datenbanken wie MySQL, der weit verbreiteten Formel
oder
wird beispielsweise 17 zurückgeben, wenn sich DATE1 und DATE2 im selben DST-Segment des Jahres befinden; aber es kann 17.042 und noch schlimmer 16.958 zurückgeben. Die Verwendung von floor () oder einer impliziten Kürzung in eine Ganzzahl konvertiert dann eine 17 in eine 16. Unter anderen Umständen werden Ausdrücke wie "$ days> 17"
true
für 17.042 zurückgegeben, selbst wenn dies anzeigt, dass der verstrichene Tag zählt ist 18.Und die Dinge werden noch hässlicher, da ein solcher Code nicht plattformübergreifend portierbar ist, da einige von ihnen möglicherweise Schaltsekunden anwenden und andere nicht . Auf diesen Plattformen , die nicht die Differenz zwischen zwei Daten, nicht aber 86400 86401, oder vielleicht 86399. sein So - Code, der im Juni nächsten Jahres bricht im Mai und bestanden tatsächlich alle Tests gearbeitet , als 12,99999 Tage 12 Tage statt 13. Zwei Tage , in Betracht gezogen werden dass im Jahr 2015 gearbeitet wird nicht funktionieren , im Jahr 2017 - die gleichen Daten und weder Jahr ein Schaltjahr ist . Aber zwischen dem 01.03.2018 und dem 01.03.2017 sind auf den Plattformen, die sich darum kümmern, 366 Tage statt 365 vergangen, was 2018 zu einem Schaltjahr macht (was es nicht ist).
Wenn Sie also wirklich UNIX-Zeitstempel verwenden möchten:
Verwenden Sie die
round()
Funktion mit Bedacht, nichtfloor()
.Berechnen Sie alternativ keine Unterschiede zwischen D1-M1-YYY1 und D2-M2-YYY2. Diese Daten werden wirklich als D1-M1-YYY1 00:00:00 und D2-M2-YYY2 00:00:00 betrachtet. Konvertieren Sie stattdessen zwischen D1-M1-YYY1 22:30:00 und D2-M2-YYY2 04:30:00. Sie erhalten immer einen Rest von etwa zwanzig Stunden. Dies kann einundzwanzig Stunden oder neunzehn und vielleicht achtzehn Stunden, neunundfünfzig Minuten und sechsunddreißig Sekunden werden. Ganz gleich. Es ist eine große Marge, die dort bleiben und auf absehbare Zeit positiv bleiben wird. Jetzt können Sie es mit gestutzt
floor()
in Sicherheit.Die richtige Lösung, um magische Konstanten, Rundungen und Wartungsschulden zu vermeiden, ist jedoch
Verwenden Sie eine Zeitbibliothek (Datetime, Carbon, was auch immer). roll nicht deine eigenen
Schreiben Sie umfassende Testfälle mit wirklich schlechten Datumsentscheidungen - über Sommerzeitgrenzen hinweg, über Schaltjahre, über Schaltsekunden usw. hinweg sowie über alltägliche Daten. Im Idealfall (Aufrufe von datetime sind schnell !) Generieren Sie Daten im Wert von vier ganzen Jahren (und einem Tag) , indem Sie sie nacheinander aus Zeichenfolgen zusammensetzen, und stellen Sie sicher, dass der Unterschied zwischen dem ersten Tag und dem getesteten Tag stetig um eins zunimmt. Auf diese Weise wird sichergestellt, dass Sie zumindest wissen , ob sich Änderungen an den Routinen auf niedriger Ebene und an Korrekturen in Schaltsekunden ergeben, die Chaos anrichten .
Führen Sie diese Tests regelmäßig zusammen mit dem Rest der Testsuite aus. Sie sind eine Frage von Millisekunden und können Ihnen buchstäblich Stunden des Kopfkratzens ersparen .
Was auch immer Ihre Lösung ist, testen Sie sie!
Die folgende Funktion
funcdiff
implementiert eine der Lösungen (zufällig die akzeptierte) in einem realen Szenario.Das Ergebnis ist,
Horror Story: Die Kosten für "Zeit sparen"
Dies geschah tatsächlich vor einigen Monaten. Ein genialer Programmierer beschloss, einige Mikrosekunden bei einer Berechnung zu sparen, die höchstens 30 Sekunden dauerte, indem er den berüchtigten Code "(MidnightOfDateB-MidnightOfDateA) / 86400" an mehreren Stellen einfügte. Es war eine so offensichtliche Optimierung, dass er sie nicht einmal dokumentierte, und die Optimierung bestand die Integrationstests und lauerte mehrere Monate lang unbemerkt im Code.
Dies geschah in einem Programm, das die Löhne für mehrere meistverkaufte Verkäufer berechnet, von denen der geringste viel mehr Einfluss hat als ein ganzes bescheidenes fünfköpfiges Programmierteam zusammen. Eines Tages vor einigen Monaten schlug der Fehler aus unerheblichen Gründen zu - und einige dieser Leute hatten einen ganzen Tag lang einen Mangel an fetten Provisionen. Sie waren definitiv nicht amüsiert.
Unendlich schlimmer, sie verloren das (bereits sehr geringe) Vertrauen in das Programm, das nicht dazu gedacht war, sie heimlich zu beschützen, und gaben vor - und erhielten - eine vollständige, detaillierte Codeüberprüfung mit Testfällen, die in Laienbegriffen ausgeführt und kommentiert wurden (plus viel) der Behandlung auf dem roten Teppich in den folgenden Wochen).
Was kann ich sagen: Auf der positiven Seite haben wir eine Menge technischer Schulden beseitigt und konnten mehrere Teile eines Spaghetti-Chaos umschreiben und umgestalten, das auf einen COBOL-Befall in den schwingenden 90ern zurückging. Das Programm läuft jetzt zweifellos besser und es gibt viel mehr Debugging-Informationen, die Sie schnell finden können, wenn etwas faul aussieht. Ich schätze, dass nur diese letzte Sache auf absehbare Zeit vielleicht ein oder zwei Manntage pro Monat einsparen wird.
Auf der negativen Seite kostete das ganze Brouhaha das Unternehmen im Voraus etwa 200.000 Euro - plus Gesicht plus zweifellos etwas Verhandlungsmacht (und damit noch mehr Geld).
Der für die "Optimierung" verantwortliche Mann hatte vor einem Jahr vor der Katastrophe den Job gewechselt, aber es war immer noch die Rede davon, ihn auf Schadensersatz zu verklagen. Und es passte nicht gut zu den oberen Rängen, dass es "die Schuld des letzten Mannes" war - es sah nach einer Vorbereitung für uns aus, um die Angelegenheit zu klären, und am Ende sind wir immer noch in der Hundehütte und einer aus dem Team plant aufzuhören.
Neunundneunzig von einhundert Mal funktioniert der "86400-Hack" einwandfrei. (
strtotime()
Ignoriert beispielsweise in PHP die Sommerzeit und meldet, dass zwischen der Nacht des letzten Samstags im Oktober und der des folgenden Montags genau 2 * 24 * 60 * 60 Sekunden vergangen sind, auch wenn dies eindeutig nicht zutrifft ... und zwei Fehler machen glücklich einen richtig).Dies, meine Damen und Herren, war ein Fall, in dem dies nicht der Fall war. Wie bei Airbags und Sicherheitsgurten werden Sie die Komplexität (und Benutzerfreundlichkeit) von oder vielleicht nie wirklich brauchen . Aber der Tag, an dem Sie könnten (oder der Tag, an dem Sie beweisen müssen, dass Sie darüber nachgedacht haben), wird in der Nacht als Dieb kommen. Sei vorbereitet.
DateTime
Carbon
quelle
days between two days in php
oder ähnlichem gesucht haben , nur weil das Leben zu kurz ist, um alles selbst zu schreiben.Einfach zu verwenden date_diff
quelle
$diff
in diesem Fall variabel). So etwas wieif ($diff->days > 30) { [doyourstuff]; }
Objektorientierter Stil:
Verfahrensstil:
quelle
Benutzte dies :)
Jetzt funktioniert es
quelle
Nun, die ausgewählte Antwort ist nicht die richtigste, da sie außerhalb von UTC fehlschlägt. Abhängig von der Zeitzone ( Liste ) kann es zu Zeitanpassungen kommen, die Tage "ohne" 24 Stunden erzeugen. Dadurch schlägt die Berechnung (60 * 60 * 24) fehl.
Hier ist es ein Beispiel dafür:
Die richtige Lösung wird also DateTime verwenden
quelle
Berechnen Sie die Differenz zwischen zwei Daten:
Ausgabe: +272 Tage
Die Funktion date_diff () gibt die Differenz zwischen zwei DateTime-Objekten zurück.
quelle
quelle
Ich verwende Carbon in meinen Komponistenprojekten für diesen und ähnliche Zwecke.
So einfach wäre das:
quelle
Sie können Daten einfach von finden
quelle
und bei Bedarf:
quelle
Wenn Sie die Zeiten in Sekunden haben (IE-Unix-Zeitstempel), können Sie die Zeiten einfach subtrahieren und durch 86400 (Sekunden pro Tag) dividieren.
quelle
quelle
Sie können den folgenden Code ausprobieren:
quelle
quelle
Wenn Sie alle Tage zwischen dem Start- und Enddatum wiedergeben möchten, habe ich Folgendes gefunden:
quelle
Der einfachste Weg, um die Tagesdifferenz zwischen zwei Daten zu ermitteln
quelle
quelle
Hier ist meine verbesserte Version, die 1 Jahr (e) 2 Monat (e) 25 Tag (e) anzeigt, wenn der 2. Parameter übergeben wird.
quelle
quelle
benutzte den obigen Code sehr einfach. Vielen Dank.
quelle
quelle
Mit dieser einfachen Funktion. Funktion deklarieren
und rufen Sie diese Funktion so auf, wie Sie möchten
quelle
quelle
Wenn Sie MySQL verwenden
}}
}}
quelle
Versuchen Sie es mit Carbon
Auch können Sie verwenden
um ein Objekt mit Carbon-Datum unter Verwendung einer bestimmten Zeitstempelzeichenfolge zu erstellen.
quelle
Alle Antworten suchen Ich komponiere universelle Funktion, was auf allen PHP-Versionen funktioniert.
Im Allgemeinen verwende ich 'DateTime', um Tage zwischen zwei Daten zu finden. Wenn jedoch auf einem Server-Setup aus irgendeinem Grund 'DateTime' nicht aktiviert ist, wird eine einfache (aber nicht sichere) Berechnung mit 'strtotime ()' verwendet.
quelle