Timezone
Contents
Notwendige Vorkenntnisse
http://de.wikipedia.org/wiki/UTC
Problem
Alle Zeitfunktionen im PHP und MySQL verwenden eine Zeitzone um ein Datum oder eine Uhrzeit generieren zu können. Jeder Server hat eine Standard-Zeitzone definiert, welche von den entsprechenden PHP- oder MySQL-Funktionen verwendet wird. Diese Standard-Zeitzone entspricht normalerweise dem Standort des Servers und kann bei bedarf selbst festgelegt werden. Wenn dort eine Zeitzone verwendet wird, die Sommer- und Winterzeit (DST - Daylight Savings Time) unterscheidet, so werden Daten im Sommer und im Winter u.U. nicht gleich berechnet.
Zudem sollte der Benutzer sich Daten in seiner Zeitzone anzeigen lassen können. Dazu muss das Datum für den jeweiligen Benutzer umgerechnet werden.
Lösung
Die Unterscheidung zwischen folgenden Zeitzonen führt zur Lösung:
-
user
: Zeitzone des Benutzers (/zur Ausgabe) -
intern
: Zeitzone für Berechnungen -
db
: Zeitzone für Datenablage
Die Zeitzonen können theoretisch auch alle gleich sein. Wichtig ist, dass die Zeitzone zur Datenablage (db
) keine DST beachtet (z.B. UTC).
Seit Contrexx 3.0.0 wird während der Installation eine Zeitzone ausgewählt. Da Contrexx/Cloudrexx (noch) nicht unterscheidet zwischen der Zeitzone des Benutzers und für die Berechnungen, sind diese identisch gesetzt. Lediglich beim Auslesen aus der Datenablage findet eine Zeitzonenumrechnung statt.
Best Practice
- Die Zeitzone der Datenbankablage selbst festlegen (nicht die Zeitzone des Datenbankservers verwenden!)
- Als Zeitzone für die Datenbankablage eine Zeitzone ohne DST verwenden (WICHTIG!)
- Nur PHP-Zeitfunktionen und keine MySQL-Zeitfunktionen verwenden: Somit können Zeit-Unstimmigkeiten zwischen PHP- und MySQL-Server vermieden werden.
- Die MySQL-Datentypen
DATETIME
/DATE
/TIME
verwenden,TIMESTAMP
vermeiden. Der DatentypTIMESTAMP
unterliegt dem y2038-Problem[1][2].-
DATE
undTIME
(allenfalls in Kombination): Bei Referenzen auf einen ortsunabhängigen Zeitpunkt. Beispiele:- weltweit gleiche (/von der Zeitzone unabhängige) Öffnungszeiten von 9-17 Uhr
- Silvester am 31.12. um 24:00
-
DATETIME
: Bei ortsabhängigen Zeipunkten. Beispiel:- Silvesterparty in Zürich um 23 Uhr
-
- Beim Exportieren der Datenbank mittels
mysqldump
ist standardmässig die Option--tz-utc
gesetzt, welche bewirkt, dass Daten von Feldern mit dem DatentypTIMESTAMP
in UTC exportiert werden. Damit nach dem Importieren des Dumps die Daten wieder in der richtigen Zeitzone vorliegen, muss überprüft werden, ob im Dump folgendes enthalten ist:SET TIME_ZONE='+00:00';
.
Cloudrexx
Für Models sollten nur die MySQL-Datentypen DATETIME
, DATE
und TIME
verwendet werden (siehe Begründung dazu oben).
Damit die Konvertierung (zwischen den Zeitzonen der verschiedenen Ebenen Benutzer (user
), Berechnung (intern
) und Datenablage (db
)) immer korrekt erfolgt, bietet der DateTime
Component folgende Helper an:
Initialisierung
Aus Benutzereingabe (GUI)
Erstellt eine neue DateTime
Instanz aus einer Benutzereingabe (in der Zeitzone der Benutzerebene user
) und konvertiert diese zur Weiterverarbeitung in die Zeitzone der Berechnungsebene (intern
):
$datetime = $this->cx->getComponent('DateTime')->createDateTimeForUser($_GET['time']);
$datetime->user2intern();
Für Benutzerausgabe
Vor der Ausgabe an den Benutzer muss eine DateTime
Instanz in die Zeitzone der Benutzerebene (user
) konvertiert werden:
// neue Instanz anlegen in der Zeitzone der Berechnungsebene (intern)
$datetime = new \DateTime($date);
// Ausführung div. Operationen auf $datetime
...
// Konvertierung in Zeitzone der Benutzerebene
$this->cx->getComponent('DateTime')->intern2user($datetime);
// $datetime ist nun bereit für die Benutzerausgabe
createDateTimeForUser()
ohne Argument aufgerufen werden:
$now = $this->cx->getComponent('DateTime')->createDateTimeForUser();
Aus der Datenbank
Erstellt eine neue DateTime
Instanz aus einem Wert aus der Datenbank (in der Zeitzone der Datenbankebene db
) und konvertiert diese zur Weiterverarbeitung in die Zeitzone der Berechnungsebene (intern
):
$datetime = $this->cx->getComponent('DateTime')->createDateTimeForDb($dbValue);
$this->cx->getComponent('DateTime')->db2intern($datetime);
In die Datenbank
Vor der Speicherung einer DateTime
Instanz muss diese in die Zeitzone der Datenbankebene (db
) konvertiert werden:
// neue Instanz anlegen in der Zeitzone der Berechnungsebene (intern)
$datetime = new \DateTime($date);
// Ausführung div. Operationen auf $datetime
...
// Konvertierung in Zeitzone der Datenbankebene
$this->cx->getComponent('DateTime')->intern2db($datetime);
// $datetime ist nun bereit für die Speicherung in der Datenbank
createDateTimeForDb()
ohne Argument aufgerufen werden:
$now = $this->cx->getComponent('DateTime')->createDateTimeForDb();
Konvertierung
Zur Konvertierung einer DateTime
Instanz zwischen den Zeitzonen der verschiedenen Ebenen stehen folgende Methoden bereit:
Ebene | Benutzer (user )
|
Berechnung (intern )
|
Datenbank (db )
|
---|---|---|---|
Benutzer (user )
|
- | $this->cx->getComponent('DateTime')->user2intern($datetime)
|
$this->cx->getComponent('DateTime')->user2db($datetime)
|
Berechnung (intern )
|
$this->cx->getComponent('DateTime')->intern2user($datetime)
|
- | $this->cx->getComponent('DateTime')->intern2db($datetime)
|
Datenbank (db )
|
$this->cx->getComponent('DateTime')->db2user($datetime)
|
$this->cx->getComponent('DateTime')->db2intern($datetime)
|
- |
Zeitzonen-Datenbank
MySQL
Wenn MySQL auf einem UNIX-System installiert ist, so wird auf dessen Zeitzonen-Datenbank zugegriffen, welche sich in den meisten Fällen unter "/usr/share/zoneinfo" befindet. Ist MySQL aber auf einem Windows-System installiert, steht diese Zeitzonen-Datenbank nicht zur Verfügung. In diesem Fall gibt es zwei Möglichkeiten:
a) Die Zeitzonen-Datenbank wird manuell importiert (weitere Informationen unter http://dev.mysql.com/downloads/timezones.html und http://dev.mysql.com/doc/refman/5.1/en/mysql-tzinfo-to-sql.html)
b) Anstelle des Namens (z. B. "Europe/Zurich") wird der Offset (z. B. "+02:00") der Zeitzone gesetzt.
Cloudrexx verwendet Möglichkeit b).
PHP
PHP hat eine Zeitzonen-Datenbank integriert. Demzufolge spielt es keine Rolle, ob PHP auf einem UNIX- oder Windows-System installiert ist.
Olsen-Datenbank
PHP als auch UNIX verwenden die Zeitzonen-Datenbank "Olsen" (weitere Informationen unter http://en.wikipedia.org/wiki/Tz_database). Demzufolge können Zeitzonen-Unstimmigkeiten zwischen PHP und MySQL ausgeschlossen werden.
Hinweise
-
In PHP darf die Methode "DateTime::diff()" nicht verwendet werden, da diese auf Windows-Systemen nicht korrekt funktioniert (siehe https://bugs.php.net/bug.php?id=51184).