Wie komme ich mit einem Unix-Zeitstempel zum Anfang und Ende dieses Tages?

79

Ich habe einen Unix-Zeitstempel wie diesen:

$timestamp=1330581600

Wie erhalte ich den Tagesanfang und das Tagesende für diesen Zeitstempel?

e.g.
$beginOfDay = Start of Timestamp's Day
$endOfDay = End of Timestamp's Day

Ich habe es versucht:

$endOfDay = $timestamp + (60 * 60 * 23);

Aber ich denke nicht, dass es funktionieren wird, da der Zeitstempel selbst nicht der genaue Beginn des Tages ist.

Talon
quelle
Wenn es GMT ist, wahrscheinlich: $ border = Etage / Decke ($ Zeitstempel / (60 * 60 * 24)) * (60 * 60 * 24);
hakre
Wenn Ihre erwartete Ausgabe ein Zeitstempel als Ganzzahl ist, gibt es einen einfachen Einzeiler: $ beginOfDay = mktime (0, 0, 0, Datum ('n'), Datum ('j') - 1); $ endOfDay = mktime (0, 0, 0, Datum ('n'), Datum ('j'));
Jarederaj

Antworten:

176

strtotime kann verwendet werden, um die Stunde / Minuten / Sekunden schnell abzuschneiden

$beginOfDay = strtotime("today", $timestamp);
$endOfDay   = strtotime("tomorrow", $beginOfDay) - 1;

DateTime kann ebenfalls 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'),
    )
);

Durch das Hinzufügen einer längeren Zeit in PHP7 besteht die Möglichkeit, dass eine Sekunde verpasst wird, wenn die $now <= $endÜberprüfung mit dieser Option verwendet wird . Die Verwendung der $now < $nextStartÜberprüfung würde diese Lücke vermeiden, zusätzlich zu den Kuriositäten beim Subtrahieren von Sekunden und der Sommerzeit bei der Zeitbehandlung von PHP.

rrehbein
quelle
2
Warum minus 1 Sekunde am Ende?
Kurt Zhong
1
Ich hatte die ursprüngliche Frage so gelesen, dass sie die letzte Sekunde des Tages und nicht die erste Sekunde des nächsten Tages erhielt. 'morgen' gibt die erste Sekunde des Tages an, also '-1', um die Sekunde vor der ersten Sekunde des Tages zu erhalten.
Rrehbein
5
'heute' gibt auch den Anfang des Tages zurückstrtotime('today', $timestamp)
Semra
1
Scheint anfällig für Schaltsekundenprobleme
Brad Kent
4
$endOfDay->modify('tomorrow -1 second');funktioniert auch.
CGodo
11

Nur DateTime

$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. Anschließend wird das Objekt als Zeichenfolge formatiert, die die Stunde / Minute / Sekunde auf den Anfang oder das Ende des Tages setzt. Zuletzt wird aus dieser Zeichenfolge ein neues DateTime-Objekt erstellt und der Zeitstempel abgerufen.

Lesbar

$dateTimeObject = new DateTime();
$dateTimeObject->setTimestamp($timestamp);
$beginOfDayString = $dateTimeObject->format('Y-m-d 00:00:00');
$beginOfDayObject = DateTime::createFromFormat('Y-m-d H:i:s', $beginOfDayString);
$beginOfDay = $beginOfDayObject->getTimestamp();

Mit dieser längeren Version können wir das Ende des Tages auf alternative Weise erreichen:

$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 festgelegt werden, indem dem Format ein Zeitstempel hinzugefügt wird, z. B. Ound der Zeitstempel nach dem Erstellen des DateTime-Objekts angegeben wird:

$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 den Anfang / das Ende des Monats oder den Anfang / das 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'

Wenn wir verschiedene Formate in Kombination mit den Objekten add () / sub () und DateInterval verwenden, können wir den Anfang oder das Ende eines beliebigen Zeitraums ermitteln, obwohl einige Sorgfalt erforderlich ist, um die Schaltjahre korrekt zu handhaben.

Relevante Links

Aus den PHP-Dokumenten:

Robert Hickman
quelle
2
Was Sie erstellt haben, ist prägnant und lesbar. Leider wird es in Schaltsekunden fehlschlagen. Einige Tage enden um 23:59:58 Uhr, andere um 23:59:60 Uhr. 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 PHP-Methode \ DateTime :: modify verwendet, würde dies vermeiden. Die in lib integrierte PHP ist intelligent genug, um alle Kuriositäten zu berücksichtigen, die Datums- und Uhrzeitangaben einschließlich Schaltsekunden betreffen.
Elimn
@ Elimm, mir war nicht bewusst, dass einige Tage eine Sekunde vor oder später wegen des Schalttages endeten. Ich dachte, dass der Sprung nur einen Tag in den Schaltjahren hinzufügte und nichts anderes betroffen war. Können Sie im Code ein Beispiel dafür geben, wie dies fehlschlägt (oder können Sie einen Tag mit einer oder mehreren Sekunden weniger teilen)? Gibt es auch einen Artikel, den Sie teilen können, der mehr darüber erzählt? Vielen Dank für den Hinweis modify. Davon wusste ich vorher nichts.
Robert Hickman
Sicher. Diese wird als Sprung Sekunden nicht springen Tage oder Jahre . Sie erklären, dass die Erdrotation keine konstante Geschwindigkeit ist. Ich glaube, der 30. Juni 2016 war unsere letzte Schaltsekunde. Die Wikipedia-Seite befasst sich mit den Details.
Elimn
7

Sie können eine Kombination aus date()und verwenden mktime():

list($y,$m,$d) = explode('-', date('Y-m-d', $ts));
$start = mktime(0,0,0,$m,$d,$y);
$end = mktime(0,0,0,$m,$d+1,$y);

mktime() ist klug genug, um Monate / Jahre zu verpacken, wenn ein Tag außerhalb des angegebenen Monats angegeben wird (der 32. Januar wird der 1. Februar sein usw.)

Cal
quelle
4

Sie können die Zeit in die aktuellen Daten konvertieren und dann mit der Funktion strtotime den Tagesanfang ermitteln und einfach 24 Stunden hinzufügen, um das Tagesende zu ermitteln.

Sie können auch den Restoperator (%) verwenden, um den nächsten Tag zu finden. Zum Beispiel:

$start_of_day = time() - 86400 + (time() % 86400);
$end_of_day = $start_of_day + 86400;
Cameron
quelle
7
Nicht alle Tage sind 86400 Sekunden lang, daher funktioniert dies nicht wie erwartet
Cal
@Cal oh yeah, daran habe ich nicht gedacht
Cameron
2
Wenn Sie time()zweimal anrufen , können die Sekunden unterschiedlich sein.
Chris Harrison
@ChrisHarrison $ now = time (); $ start_of_day = $ now - 86400 + ($ now% 86400);
Kareem
4

Die akzeptierte Antwort bricht leider aufgrund eines PHP-Fehlers ab, der in sehr spezifischen Szenarien auftritt. Ich werde diese Szenarien diskutieren, aber zuerst die Antwort mit DateTime. Der einzige Unterschied zwischen dieser und der akzeptierten Antwort tritt nach der // IMPORTANTZeile auf:

$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 also feststellen, dass ->modify('1 second ago');wir statt der Verwendung den Zeitstempel erhalten und einen subtrahieren. Die akzeptierte Antwort mit modify sollte funktionieren, bricht aber aufgrund eines PHP-Fehlers in sehr spezifischen Szenarien ab. Dieser Fehler tritt in Zeitzonen auf, die die Sommerzeit um Mitternacht ändern, an dem Tag des Jahres, an dem die Uhren "vorwärts" gestellt werden. Hier ist ein Beispiel, mit dem Sie diesen Fehler überprüfen können.

Fehlerbeispielcode

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

Fehlerbeispiel Code-Ausgabe

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
KayakinKoder
quelle
3

Heute Startdatum Zeitstempel. Einfach

$stamp = mktime(0, 0, 0);
echo date('m-d-Y H:i:s',$stamp);
Ganesh
quelle
Dies kann zu unerwartetem Verhalten an Tagen führen, an denen sich die Sommerzeit genau um Mitternacht
ändert
0

Für alle, die diese Frage in Zukunft haben:

Beliebiger Tagescode

<?php
$date = "2015-04-12 09:20:00";

$midnight = strtotime("midnight", strtotime($date));
$now = strtotime($date);

$diff = $now - $midnight;
echo $diff;
?>

Aktueller Tagescode

<?php
$midnight = strtotime("midnight");
$now = date('U');

$diff = $now - $midnight;
echo $diff;
?>
Daniel Bjørnådal
quelle
0
$start_of_day = floor (time() / 86400) * 86400;
$end_of_day = ceil (time() / 86400) * 86400;

Wenn Sie beide Werte im selben Skript benötigen. Es ist schneller, +/- 86400 Sekunden für eine der Variablen zu verwenden, als sowohl den Boden als auch die Decke abzufeuern. Zum Beispiel:

$start_of_day = floor (time() / 86400) * 86400;
$end_of_day = $start_of_day + 86400;
Kareem
quelle