2013-10-26 15 views
8

In meiner Anwendung versuche ich die verbleibende Zeit bis Mitternacht GMT (UK Zeit) zu berechnen. Im Moment das ich so mache:DateTime mit falscher Zeitzone

$now = new DateTime(); 
$timeToMidnight = $now->setTimezone(new DateTimeZone('Europe/London'))->diff(new DateTime('tomorrow'))->format('%h hours, %i minutes and %s seconds'); 

Der Code funktioniert, aber es scheint eine Stunde hinter zu sein (unter Verwendung von GMT -1). Im Moment ist die Zeit 11.49 Uhr und der Ausgang ist dies:

1 hours, 10 minutes and 36 seconds 

ich doppelt habe habe meine php.ini und ich habe auch, dass die Zeitzone als GMT gesetzt:

date.timezone = Europe/London 

Dies auch bestätigt durch Überprüfung phpinfo().

Was gibt? Warum verwendet meine Anwendung nicht die richtige Zeitzone?

+0

Uhren in Großbritannien Wechsel von BST zu GMT heute Abend –

+0

@MarkBaker Gehen die Uhren heute nicht nach vorne, sondern nach hinten? Und ich bin mir ziemlich sicher, dass das nicht vor 2 Uhr morgens passiert. –

+0

Ich meine, dass die Zeit jetzt in London ist 2 Minuten nach Mitternacht British Summer Time ... GMT ist 2 Minuten nach 11 Uhr, so ist es noch 58 Minuten bis Mitternacht GMT (UST) –

Antwort

20

Ich habe dies auf Linux PHP 5.5.5 getestet, mit Europe/London als Zeitzone in php.ini festgelegt. Ich habe die Uhr sogar um vier Stunden zurückgestellt. Der minimale Code, den ich verwendet, um zu reproduzieren war:

$d = new DateTime('tomorrow'); 
echo $d->format('c e'); 

die (richtige) Ausgabe war:

2013-10-27T00:00:00+01:00 Europe/London 

ich für einen Fehler in PHP oder ein Fehler in der Zeitzone Daten suchen werde. Um herauszufinden, was wir machen, werden wir sehen, was ein anderes Programm heute Abend um Mitternacht in London macht. Epoch Converter sagt mir, dies zu einem Unix-Zeitstempel von 1382828400. haben sollte, um das Doppelte Zeitstempel überprüfen, lief ich in PHP:

$d = new DateTime('27-10-2013'); 
echo $d->format('U'); 

Es ist auch 1382828400. So zurückgekehrt, mal sehen, was es Show soll ...

TZ=Europe/London date --date="@1382828400" +%c 

Der Ausgang war:

Sun 27 Oct 2013 12:00:00 AM BST 

Richtig! Also tzdata ist in Ordnung. Schauen wir uns PHP an.

lief ich Ihren Beispielcode, zusammen mit dem date Befehl, und bekam die folgende Ausgabe:

1 hours, 29 minutes and 53 seconds 
Sat Oct 26 21:30:07 UTC 2013 
Sat Oct 26 22:30:07 BST 2013 

Das ist natürlich richtig.

Ich denke an dieser Stelle haben wir Fehler in tzdata und PHP ausgeschlossen, und müssen Konfigurationsfragen und Programmierer Erwartungen betrachten.


Erstens, wie ich bereits erwähnt, Europa/London ist nicht UTC, die kein Konzept der Sommerzeit hat und somit nicht zweimal pro Jahr nicht verändert. Da solche Probleme nicht auftreten, empfiehlt es sich, Server unabhängig von der Zeitzone, in der sich ihre Benutzer befinden, auf UTC auszuführen. Außerdem empfiehlt es sich, dass Programme UTC intern verwenden und dann in lokale Zeitzonen umwandeln Nur Anzeige und Benutzereingabe.

Meine beste Schätzung ist, dass auf Ihrem Server läuft PHP ist eigentlich auf UTC und nicht Europa/London als Standard-Zeitzone eingestellt. Dies ist die einzige Konfiguration, in der ich Ihr Problem reproduzieren konnte.Die Ergebnisse dieser Tests waren:

date.timezone = UTC 

2 hours, 24 minutes and 36 seconds 
Sat Oct 26 21:35:24 UTC 2013 
Sat Oct 26 22:35:24 BST 2013 

In Zukunft sollten Sie in UTC arbeiten (und mit Unix-Zeitstempel), wo immer praktisch, und so früh in der Verarbeitung von Benutzereingaben, und so spät in der lokalen Zeit konvertieren es in Anzeigen, wie du kannst. Ein Randfall wie dieser, in dem die Sommerzeit kurz vor dem Ende steht, kann eine Ausnahme sein, aber Sie müssen besonders vorsichtig sein, um sicherzustellen, dass jedes neue DateTime-Objekt die richtige Zeitzone aufweist, wenn Sie es konstruieren bewusst, dass sie solche Probleme haben werden.

Siehe auch die große und informative Daylight saving time and time zone best practices


schließlich zu "reparieren" Ihr Code, lassen Sie uns dies tun:

$tz = new DateTimeZone('Europe/London'); 
$now = new DateTime('now', $tz); 
$midnight = new DateTime('tomorrow', $tz); 
$timeToMidnight = $now->diff($midnight); 
echo $timeToMidnight->format('%h hours, %i minutes and %s seconds'); 
+1

+1 für $ tz = neue DateTimeZone ('Europe/London'); –

Verwandte Themen