Wie bekomme ich bei einem Unix-Zeitstempel den Beginn und das Ende dieses Tages?
Lesezeit: 8 Minuten
Kralle
Ich habe einen Unix-Zeitstempel wie folgt:
$timestamp=1330581600
Wie bekomme ich den Beginn des Tages und das Ende des Tages für diesen Zeitstempel?
e.g.
$beginOfDay = Start of Timestamp's Day
$endOfDay = End of Timestamp's Day
Ich habe das versucht:
$endOfDay = $timestamp + (60 * 60 * 23);
Aber ich glaube nicht, dass es funktionieren wird, weil der Zeitstempel selbst nicht der genaue Beginn des Tages ist.
Wenn es GMT ist, wahrscheinlich: $boundary = floor/ceil($timestamp / (60 * 60 * 24)) * (60 * 60 * 24);
– hakre
17. April 2012 um 19:36 Uhr
Wenn Ihre erwartete Ausgabe ein Zeitstempel als Ganzzahl ist, gibt es einen einfachen Einzeiler: $beginOfDay = mktime(0, 0, 0, date(‘n’), date(‘j’) – 1); $endOfDay = mktime(0, 0, 0, date(‘n’), date(‘j’));
– Jarederaj
18. Januar 2016 um 18:54 Uhr
rrehbein
strtotime kann verwendet werden, um die Stunden/Minuten/Sekunden schnell abzuschneiden
DateTime kann auch verwendet werden, erfordert jedoch einige zusätzliche Schritte, um einen langen Zeitstempel zu erhalten
$dtNow = new DateTime();
// Set a non-default timezone if needed
$dtNow->setTimezone(new DateTimeZone('Pacific/Chatham'));
$dtNow->setTimestamp($timestamp);
$beginOfDay = clone $dtNow;
$beginOfDay->modify('today');
$endOfDay = clone $beginOfDay;
$endOfDay->modify('tomorrow');
// adjust from the start of next day to the end of the day,
// per original question
// Decremented the second as a long timestamp rather than the
// DateTime object, due to oddities around modifying
// into skipped hours of day-lights-saving.
$endOfDateTimestamp = $endOfDay->getTimestamp();
$endOfDay->setTimestamp($endOfDateTimestamp - 1);
var_dump(
array(
'time ' => $dtNow->format('Y-m-d H:i:s e'),
'start' => $beginOfDay->format('Y-m-d H:i:s e'),
'end ' => $endOfDay->format('Y-m-d H:i:s e'),
)
);
Mit der Hinzufügung der erweiterten Zeit in PHP7 besteht die Möglichkeit, dass bei der Verwendung eine Sekunde verpasst wird $now <= $end damit prüfen. Verwenden $now < $nextStart Das Überprüfen würde diese Lücke vermeiden, zusätzlich zu den Kuriositäten rund um das Subtrahieren von Sekunden und Sommerzeit in der Zeitverwaltung von PHP.
Warum minus 1 Sekunde am Ende?
– Kurt Zhong
28. Januar 2013 um 7:31 Uhr
Ich hatte die ursprüngliche Frage so gelesen, dass sie die letzte Sekunde des Tages bekam, und nicht die erste Sekunde des nächsten Tages. ‘morgen’ gibt die erste Sekunde des Tages an, also ‘-1’, um die Sekunde vor der ersten Sekunde des Tages zu erhalten.
– rrehbein
28. Januar 2013 um 14:24 Uhr
‘today’ gibt auch den Beginn des Tages zurück strtotime('today', $timestamp)
– Semra
23. März 2015 um 17:46 Uhr
Scheint anfällig für Schaltsekundenprobleme zu sein
$beginOfDay = DateTime::createFromFormat('Y-m-d H:i:s', (new DateTime())->setTimestamp($timestamp)->format('Y-m-d 00:00:00'))->getTimestamp();
$endOfDay = DateTime::createFromFormat('Y-m-d H:i:s', (new DateTime())->setTimestamp($timestamp)->format('Y-m-d 23:59:59'))->getTimestamp();
Zuerst wird ein DateTime-Objekt erstellt und der Zeitstempel auf den gewünschten Zeitstempel gesetzt. Dann wird das Objekt als String formatiert, der die Stunde/Minute/Sekunde auf den Beginn oder das Ende des Tages setzt. Schließlich wird aus dieser Zeichenfolge ein neues DateTime-Objekt erstellt und der Zeitstempel abgerufen.
Wir können das Ende des Tages auf alternative Weise mit dieser längeren Version erhalten:
$endOfDayObject = clone $beginOfDayOject(); // Cloning because add() and sub() modify the object
$endOfDayObject->add(new DateInterval('P1D'))->sub(new DateInterval('PT1S'));
$endOfDay = $endOfDayOject->getTimestamp();
Zeitzone
Die Zeitzone kann auch eingestellt werden, indem dem Format ein Zeitstempel-Indikator hinzugefügt wird, z O und Angabe des Zeitstempels nach dem Erstellen des DateTime-Objekts:
$beginOfDay = DateTime::createFromFormat('Y-m-d H:i:s O', (new DateTime())->setTimezone(new DateTimeZone('America/Los_Angeles'))->setTimestamp($timestamp)->format('Y-m-d 00:00:00 O'))->getTimestamp();
Flexibilität von DateTime
Wir können auch andere Informationen wie Anfang/Ende des Monats oder Anfang/Ende der Stunde erhalten, indem wir das zweite angegebene Format ändern. Für Monat: 'Y-m-01 00:00:00' und 'Y-m-t 23:59:59'. Für Stunde: 'Y-m-d H:00:00' und 'Y-m-d H:59:59'
Durch die Verwendung verschiedener Formate in Kombination mit add()/sub()- und DateInterval-Objekten können wir den Anfang oder das Ende jeder Periode erhalten, obwohl einige Vorsicht geboten ist, um Schaltjahre korrekt zu behandeln.
Was Sie erstellt haben, ist prägnant und lesbar. Leider scheitert es an Schaltsekunden. Manche Tage enden um 23:59:58, andere um 23:59:60. Dies führt insbesondere zu Problemen, wenn versucht wird, ein Datum für eine nicht vorhandene Datumszeit zu erstellen, z. B. 23:59:59 an einem Tag, der theoretisch eine Sekunde vorher enden könnte. Die akzeptierte Antwort, die die \DateTime::modify-Methode von PHP verwendet, würde dies vermeiden. Die in PHP eingebaute Bibliothek ist intelligent genug, um alle Kuriositäten zu berücksichtigen, die Datums- und Zeitangaben umgeben, einschließlich Schaltsekunden.
– Elimin
8. Juni 2017 um 9:33 Uhr
@Elimm, mir war nicht bewusst, dass einige Tage wegen des Schalttages eine Sekunde früher oder später endeten. Ich dachte, dieser Sprung fügte in Schaltjahren nur einen Tag hinzu und sonst nichts war betroffen. Können Sie ein Beispiel im Code dafür geben, wie dies fehlschlägt (oder können Sie einen Tag mit einer Sekunde mehr oder einer Sekunde weniger teilen)? Gibt es auch einen Artikel, den Sie teilen können, der mehr darüber sagt? Danke für den Hinweis modify. Das wusste ich vorher nicht.
– Robert Hickmann
8. Juni 2017 um 16:24 Uhr
Mit Sicherheit. Diese werden Sprung genannt Sekunden nicht springen Tage oder Jahre. Sie erklären, dass die Rotation der Erde keine konstante Geschwindigkeit ist. Ich glaube, der 30. Juni 2016 war unsere letzte Schaltsekunde. Das Wikipedia-Seite taucht in die groben Details ein.
– Elimin
13. Juni 2017 um 19:37 Uhr
Sie können eine Kombination aus verwenden date() und mktime():
mktime() ist intelligent genug, um Monate/Jahre zu umbrechen, wenn ein Tag außerhalb des angegebenen Monats angegeben wird (der 32. Januar wird der 1. Februar usw.)
Sie könnten die Zeit in die aktuellen Daten konvertieren und dann die strtotime-Funktion verwenden, um den Beginn des Tages zu finden, und einfach 24 Stunden dazu addieren, um das Ende des Tages zu finden.
Sie können auch den Restoperator (%) verwenden, um den nächsten Tag zu finden. Zum Beispiel:
Die akzeptierte Antwort bricht leider aufgrund eines PHP-Fehlers, der in ganz bestimmten Szenarien auftritt. Ich werde diese Szenarien besprechen, aber zuerst die Antwort mit DateTime. Der einzige Unterschied zwischen dieser und der akzeptierten Antwort tritt nach dem auf // IMPORTANT Linie:
$dtNow = new DateTime();
// Set a non-default timezone if needed
$dtNow->setTimezone(new DateTimeZone('America/Havana'));
$dtNow->setTimestamp($timestamp);
$beginOfDay = clone $dtNow;
// Go to midnight. ->modify('midnight') does not do this for some reason
$beginOfDay->modify('today');
// now get the beginning of the next day
$endOfDay = clone $beginOfDay;
$endOfDay->modify('tomorrow');
// IMPORTANT
// get the timestamp
$ts = $endOfDay->getTimestamp();
// subtract one from that timestamp
$tsEndOfDay = $ts - 1;
// we now have the timestamp at the end of the day. we can now use that timestamp
// to set our end of day DateTime
$endOfDay->setTimestamp($tsEndOfDay);
Sie werden das also notieren, anstatt zu verwenden ->modify('1 second ago'); wir erhalten stattdessen den Zeitstempel und subtrahieren eins. Die akzeptierte Antwort mit modifysollte funktioniert, bricht aber wegen eines PHP-Bugs in ganz bestimmten Szenarien ab. Dieser Fehler tritt in Zeitzonen auf, die die Sommerzeit um Mitternacht ändern, an dem Tag des Jahres, an dem die Uhren “vorgestellt” werden. Hier ist ein Beispiel, mit dem Sie diesen Fehler überprüfen können.
Beispielcode für Fehler
// a time zone, Cuba, that changes their clocks forward exactly at midnight. on
// the day before they make that change. there are other time zones which do this
$timezone="America/Santiago";
$dateString = "2020-09-05";
echo 'the start of the day:<br>';
$dtStartOfDay = clone $dtToday;
$dtStartOfDay->modify('today');
echo $dtStartOfDay->format('Y-m-d H:i:s');
echo ', '.$dtStartOfDay->getTimestamp();
echo '<br><br>the start of the *next* day:<br>';
$dtEndOfDay = clone $dtToday;
$dtEndOfDay->modify('tomorrow');
echo $dtEndOfDay->format('Y-m-d H:i:s');
echo ', '.$dtEndOfDay->getTimestamp();
echo '<br><br>the end of the day, this is incorrect. notice that with ->modify("-1 second") the second does not decrement the timestamp by 1:<br>';
$dtEndOfDayMinusOne = clone $dtEndOfDay;
$dtEndOfDayMinusOne->modify('1 second ago');
echo $dtEndOfDayMinusOne->format('Y-m-d H:i:s');
echo ', '.$dtEndOfDayMinusOne->getTimestamp();
echo '<br><br>the end of the day, this is correct:<br>';
$dtx = clone $dtEndOfDay;
$tsx = $dtx->getTimestamp() - 1;
$dty = clone $dtEndOfDay;
$dty->setTimestamp($tsx);
echo $dty->format('Y-m-d H:i:s');
echo ', '.$tsx;
Fehlerbeispielcodeausgabe
the start of the day:
2020-03-26 00:00:00, 1585173600
the start of the *next* day:
2020-03-27 01:00:00, 1585260000
the end of the day, this is incorrect. notice that with ->modify("1 second ago") the
second does not decrement the timestamp by 1:
2020-03-27 01:59:59, 1585263599
the end of the day, this is correct:
2020-03-26 23:59:59, 1585259999
Wenn Sie beide Werte im selben Skript benötigen. Es ist schneller auf +/- 86400 Sekunden zu einer der Variablen, als sowohl den Boden als auch die Decke abzufeuern. Zum Beispiel:
Wenn es GMT ist, wahrscheinlich: $boundary = floor/ceil($timestamp / (60 * 60 * 24)) * (60 * 60 * 24);
– hakre
17. April 2012 um 19:36 Uhr
Wenn Ihre erwartete Ausgabe ein Zeitstempel als Ganzzahl ist, gibt es einen einfachen Einzeiler: $beginOfDay = mktime(0, 0, 0, date(‘n’), date(‘j’) – 1); $endOfDay = mktime(0, 0, 0, date(‘n’), date(‘j’));
– Jarederaj
18. Januar 2016 um 18:54 Uhr