2016-09-21 4 views
4

Betrachten Sie diesen Code, wo wir an zweiter Stelle addieren oder subtrahieren eine wollen:Ist strtotime() einen Fehler?

date_default_timezone_set("Europe/Amsterdam"); 

$time = 1477789199; 
echo $time . ' - ' . date('r', $time) . "\n"; 
// 1477789199 - Sun, 30 Oct 2016 02:59:59 +0200 

Das ist richtig, da dieser Zeitstempel immer noch nur innerhalb DST (Sommerzeit/Sommerzeit) ist.

Aber nun einer Sekunde auf die Zeitstempel integer hinzufügen und Ausfahrt DST:

$new = $time + 1; 
echo $new . ' - ' . date('r', $new); 
// 1477789200 - Sun, 30 Oct 2016 02:00:00 +0100 

Hooray! PHP sieht, dass es eine Sekunde später keine Sommerzeit mehr gibt und eine richtige Zeitkette anzeigt.

Aber was, wenn wir nicht eine Sekunde auf die Zeitstempel integer hinzugefügt haben, aber wir benutzten strtotime(), dass eine Sekunde hinzuzufügen:

$new = strtotime('+1 second', $time); 
echo $new . ' - ' . date('r', $new); 
// 1477792800 - Sun, 30 Oct 2016 03:00:00 +0100 

Huch! Wir sind nur um mehr als eine Stunde statt um eine Sekunde vorgegangen. Und es ist nicht einmal wichtig, wenn Sie eine Sekunde, eine Stunde, einen Tag oder ein Jahr hinzufügen, Sie werden immer eine zusätzliche Stunde damit bekommen. Selbst wenn Sie mehrere Jahre hinzufügen, erhalten Sie nur eine zusätzliche Stunde, was komisch ist, weil wir die Sommerzeit jedes Jahr eingeben und wieder verlassen, aber Sie erhalten nur eine zusätzliche Stunde unabhängig davon, wie viele Jahre Sie hinzufügen

Aber wir Ausfahrt Sommerzeit im Oktober und subtrahieren Sie eine Sekunde, alles geht gut ...

Aber dann wieder. Wenn wir im März waren und wir gerade die Sommerzeit eingegeben haben und wir eine Sekunde subtrahieren, beobachten wir das genau umgekehrt.


Warten Sie, was?! Damit ... ?

echo strtotime('+ 1 second - 1 second', 1477789199); // echoes 1477792799 

Whoa ...


Für mich klingt das wie ein Bug. Oder ist das "mit Absicht"? Weiß jemand überhaupt, ob das irgendwo dokumentiert ist oder ob es gemeldet werden muss?

+0

Hoppla. Wenn ich den PHP-Bug-Pool vor dem Posten überprüft hätte, hätte ich festgestellt, dass 2012 ein ähnliches Problem ohne Follow-up gemeldet wird: https://bugs.php.net/bug.php?id=62185 –

+1

Aus dem [doc] (http://php.net/manual/en/function.strtotime.php): 'Diese Funktion für mathematische Operationen ist nicht ratsam. Es ist besser, DateTime :: add() und DateTime :: sub() in PHP 5.3 und höher oder DateTime :: modify() in PHP 5.2 zu verwenden. ' –

+0

Berichtet unter https://bugs.php.net/bug.php?id=73138 –

Antwort

1

Das Verhalten wird als „gut dokumentiert“ .... in einem Test:

Siehe https://bugs.php.net/bug.php?id=30532 (was auch Ihr erwartetes Ergebnis zeigt, wie erwartet) und die damit verbundene Testdatei (die behauptet, dass das aktuelle Verhalten korrekt ist)

https://github.com/php/php-src/blob/master/ext/date/tests/bug30532.phpt
<?php date_default_timezone_set("America/New_York"); 

echo date('Y-m-d H:i:s T', strtotime('2004-10-31 EDT +1 hour'))."\n"; 
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 EDT +2 hours'))."\n"; 
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 EDT +3 hours'))."\n"; 
/* 2004-10-31 01:00:00 EDT 
    2004-10-31 01:00:00 EST 
    2004-10-31 02:00:00 EST */ 

echo date('Y-m-d H:i:s T', strtotime('2004-10-31 +1 hour'))."\n"; 
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 +2 hours'))."\n"; 
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 +3 hours'))."\n"; 
/* 2004-10-31 01:00:00 EDT 
    2004-10-31 02:00:00 EST 
    2004-10-31 03:00:00 EST */ 

Beachten sie, dass im ersten Fall die Zeitzone (hier: EDT) direkt an die Saite geführt wird, im letzteren Fall ist es nicht.

Im Allgemeinen strtotime nimmt den Zeitstempel (dh von 2004-10-31 - oder in Ihrem speziellen Fall: der übergebene Zeitstempel), in eine Darstellung mit individuellen Parametern konvertiert, die DST (dh einzelne Stunden, Minuten, Sekunden, Tag, Monat, Jahr usw.), wird die Operation darauf angewendet und dann zurück in den Zeitstempel konvertiert.

Insbesondere:

echo date('r', strtotime('+ 0 second', 1477789199)); 
#> Sun, 30 Oct 2016 02:59:59 +0100 

strtotime() führt die Zeitzone nach der Umwandlung entfernt, d.h.nur nimmt

Sun, 30 Oct 2016 02:59:59 

und dann gilt die primäre anwendbar Zeitzone Ihre Zeitzone Lage (das heißt Europe/Amsterdam), mit CET enden (primäre!) - CEST auch möglich ist, aber nur zweite Wahl.

Nun, zurück zum obigen Test, geben Sie die ursprüngliche Zeitzone explizit an.

So, wenn Sie es wünschen, den Weg verhalten Sie sie brauchen:

echo date('r', strtotime('CEST', 1477789199)); 
#> Sun, 30 Oct 2016 02:59:59 +0200 
echo date('r', strtotime('CEST + 1 second', 1477789199)); 
#> Sun, 30 Oct 2016 02:00:00 +0100 

In der Tat 'CEST ' Voranstellen werden für alle Zeiten in Ordnung sein (wie es immer zu CET Rückfall, wenn CEST ist nicht passend und es gibt keine Überlappung auf CET ->CEST Übergang).