Ich glaube, eine echte Lösung müsste noch etwas konsequenter sein.
Noch mal rasch rekapituliert: Problem mit NOW() war, dass der MySQL-Server auf eine abweichende Zeit(-zone) eingestellt sein könnte und ein NOW() deshalb vielleicht "09:18:00" zurückgibt statt "15:18:00" (eine "US"-Zeitzone gegen die "deutsche"). Weil das PHP-Script die Daten aber in seiner Zeitzone (15:18:00) anliefert und sie auch so in die Tabelle eingetragen werden (DATETIME- und TIME-Felder speichern die Zeitzone nicht mit), würde jede Query falsche Daten zurückgeben, die etwa sagt:
Code:
SELECT `col1` FROM `table` WHERE DATE_SUB(NOW(), INTERVAL 5 MINUTE) <= `date_added`
Na ja, kein Problem:
PHP:
$now = mysql_real_escape_string(date('Y-m-d H:i:s'));
$q = "
SELECT
`col1`
FROM
`table`
WHERE
DATE_SUB(STR_TO_DATE('" . $now . "', '%Y-%m-%d %H:%i:%s'),
INTERVAL 5 MINUTE) <= `date_added`";
// Das geht bestimmt simpler, aber egal. Das ist hier nicht der Punkt.
So rechnet MySQL auch in der Zeitzone des PHP-Scripts, da es nur von dort Zeitangaben bezieht. Problem gelöst? -- Jain.
Sobald sich die Zeitzone des PHP-Scripts ändert, besteht "Zeitverschiebung" zu den bereits in der Datenbank gespeicherten Daten. Neu hinzugefügte Daten werden zudem in der neuen Zeitzone eingespeist, wodurch Daten in der DB entstehen, die zur alten Zeitzone gehören und Daten entstehen, die zur neuen gehören.
Die Zeitzone des PHP-Scripts kann theoretisch immer dann geändert werden, wenn Daten und Zeiten für einen Besucher lokalisiert angezeigt werden sollen (dazu vielleicht in einem späteren Post mal mehr) oder wenn zwei verschiedene Server in unterschiedlichen Zeitzonen Daten vom MySQL-Server beziehen. Damit es in so einem Szenario nicht zum im letzten Absatz genannten Problem kommt, müssen alle PHP-Scripts, die mit der Datenbank interagieren, entweder in derselben Zeitzone laufen oder ihre Zeitangaben vor dem Absenden von Queries in eine gemeinsame Zeitzone -- gewissermaßen die Zeitzone der Datenbank ("Datenbankzeit") -- umwandeln.
(Achtung: Mit "Zeitzone der Datenbank" ist hier *nicht* die Zeitzone gemeint, die auf dem Datenbankserver eingestellt ist. Es geht vielmehr um eine theoretische Zeitzone x, in der DATETIME- und TIME-Felder in der DB gespeichert werden. Diese Zeitzone *wird* in den meisten Fällen von der Zeitzone des DB-Servers verschieden sein. Deshalb der Begriff "Datenbankzeit". NOW() liefert dann übrigens meist keine Datenbankzeit, sondern Serverzeit des DB-Servers.)
Aber der Ansatz klingt doch ganz sinnvoll. PHP-Scripts wandeln ihre Zeit vor der Ausführung von Queries in Datenbankzeit um und für etwaige Ausgaben von Datenbankzeit in lokalisierte Zeit. So kann jedes Script in einer beliebigen Zeitzone laufen, ohne dass sich Schwierigkeiten ergeben.
Das wirkt bisher vielleicht alles etwas kompliziert, Zeit also, ein wenig Eleganz in die Sache zu bringen: Als Wahl für die Datenbankzeit steht
UTC schon seit der Einführung des Begriffs in den Startlöchern. UTC enthält keine Zeitumstellungen für Sommer- und Winterzeit (löst damit einige Probleme automatisch), ist die weltweite Standardzeit (siehe Wikipedia) und außerdem gibt es
Datenbankfunktionen, die UTC zurückgeben und faktisch NOW() ersetzen.
Umwandlung von UTC in lokale Zeit und umgekehrt:
PHP:
function localDateToUtc($date)
{
return gmdate('Y-m-d H:i:s', strtotime($date));
}
function utcTolocalDate($utcDate)
{
// Das ist nicht wirklich schön, sollte aber klappen.
$tz = date_default_timezone_get();
date_default_timezone_set('UTC');
$utc_timestamp = strtotime($utcDate);
date_default_timezone_set($tz);
return date('Y-m-d H:i:s', $utc_timestamp);
}
date_default_timezone_set('Europe/Berlin');
// Tun wir so, als wären wir in Berlin.
$utc = localDateToUtc(date('Y-m-d H:i:s'));
echo $utc . " (UTC)<br />\n";
// Jetzt in Toronto
date_default_timezone_set('America/Toronto');
$local = utcTolocalDate($utc);
echo $local . " (America/Toronto)<br />\n";
// Zurück in Berlin
date_default_timezone_set('Europe/Berlin');
$local = utcTolocalDate($utc);
echo $local . " (Europe/Berlin)<br />\n";