4 Date and Time
Das Arbeiten mit Datums- und Zeitangaben ist nicht immer ganz einfach. Zum einen sind die unterschiedlichen Zahlensysteme für Stunden und Minuten oft ein Problem, zum anderen sind Monate unterschiedlich lang, und auch Schaltjahre stören immer wieder.
4.1 Date 

Besprochene Version: 1.4.3 | Lizenz: PHP-Lizenz |
Klassendatei(en): Date.php; Date/Span.php |
Die Klasse PEAR::Date ist sehr hilfreich, wenn Sie mit Daten und Zeiten arbeiten müssen. Sie stellt Ihnen einfache Möglichkeiten zum Vergleich von Daten, zur Addition und Subtraktion von Zeitspannen und Ähnlichem zur Verfügung. Ein besonders interessantes Feature ist die Fähigkeit, mit Zeitzonen zu arbeiten. Die Klasse ist in der Datei Date.php definiert.
require_once("Date.php"); // Neues Date-Objekt generieren $datum= new Date("2005–12–30 12:30:01"); // Datum auslesen und ausgeben lassen echo $datum->getDate(); echo "<br />"; // Lokalisierung auf Deutsch setzen setlocale(LC_ALL,"de_DE"); // Formatiertes Datum auslesen echo $datum->format("%d. %B %Y"); //Ausgabe des Programms ist: // 2005–12–30 12:30:01 // 30. Dezember 2005
Dem Konstruktor können Sie, wie Sie in diesem Beispiel sehen, eine Zeitangabe im ISO-Format (YYY-MM-DD HH:MM:SS) übergeben. Bitte beachten Sie hierbei, dass die Jahresangabe vierstellig und alle anderen Angaben zweistellig sein müssen. Alternativ akzeptiert der Konstruktor auch einen Timestamp. Geben Sie keinen Parameter an, wird die aktuelle Uhrzeit vom System übernommen.
Zum Auslesen des Datums werden in diesem Beispiel zwei unterschiedliche Methoden genutzt. getDate() liefert Ihnen standardmäßig die Zeit im ISO-Format zurück. Allerdings akzeptiert die Methode auch noch verschiedene Konstanten als Parameter, mit denen eine Zeitangabe in einem anderen Format ausgelesen werden kann.
In Tabelle 4.1 finden Sie die Formate, in denen das Datum zurückgegeben werden kann. YYYY steht für die Jahreszahl, MM für den Monat usw. In verschiedenen Formaten ist ein einzelnes T (kursiv geschrieben) enthalten. Dieses T wird eins zu eins in den Rückgabewert übernommen und dient zur Abtrennung des eigentlichen Datums und der Zeit. Das kursive TZD ist die Abkürzung für »Time Zone Designator«. An dieser Stelle kann entweder ein Z oder die Abweichung der Zeitzone von der Greenwich Mean Time im Format +/–HH:MM [In der momentan aktuellen Version 1.4.3 scheint hier ein Fehler vorzuliegen. Die Abweichung von GMT wird nicht mit ausgegeben. ] ausgegeben werden. Das Z steht hierbei für GMT bzw. UTC, und Abweichungen von der GMT werden z. B. entsprechend mit +2:00 angegeben.
Die zweite Variante, die zur Ausgabe der Datumsinformation gewählt wurde, ist die Methode format(). Sie akzeptiert einen String, der aus Format-Beschreibern besteht, wie sie auch für die PHP-Funktion strftime() genutzt werden. Einige der wichtigsten Platzhalter können Sie in Tabelle 4.2 nachlesen. Eine komplette Liste finden Sie unter http://www.php.net/strftime.
Die Klasse unterstützt darüber hinaus noch weitere Funktionen, mit deren Hilfe Sie einen Teil des Datums, wie den Tag oder die Stunde, auslesen können. Diese Methoden finden Sie in Tabelle 4.3.
Die Klasse unterstützt darüber hinaus auch verschiedene Methoden, mit denen Sie einen Teil des Datums setzen können. Für jeden Bestandteil des Datums stehen set-Funktionen zur Verfügung. So können Sie mit $datum->setSecond(59); die Sekunden im Datumsobjekt $dat auf 59 setzen, mit der Methode setMinute() die Minuten manipulieren etc.
4.1.1 Datumsberechnungen 

Ein sehr hilfreiches Feature dieser Klasse ist die Möglichkeit, mit Daten zu rechnen. Im einfachsten Fall wollen Sie das Datum des nächsten bzw. des vorhergehenden Tages ermitteln. Hierfür stehen die Methoden getNextDay() und getPrevDay() zur Verfügung, die beide ein Date-Objekt zurückliefern.
In diesem Zusammenhang sind die Methoden getNextWeekday() und getPrevWeekday() interessant. Auch diese Methoden liefern grundsätzlich den nächsten Tag, wobei das Wochenende immer übersprungen wird. Ist im aktuellen Objekt also das Datum eines Freitags enthalten, liefert die Methode getNextWeekday() den darauf folgenden Montag zurück.
Sie können allerdings auch beliebige Zeitspannen addieren oder subtrahieren. Die Methoden addSeconds() und subtractSeconds() bekommen einen Integer-Wert übergeben, der, als Anzahl von Sekunden interpretiert, zum gespeicherten Datum addiert bzw. davon abgezogen wird.
$datum= new Date("2005–06–09 00:00:00"); //7 Tage mit 24 Stunden, die 60 Minuten * 60 Sekunden enthalten $eine_woche=7*24*60*60; $datum->addSeconds($eine_woche); // $datum enthaelt jetzt // 2005–06–16 00:00:00
Darüber hinaus sind die Methoden addSpan() und subtractSpan()definiert, die eine Zeitspanne addieren oder subtrahieren können. Eine Zeitspanne geben Sie hierbei mithilfe eines Date_Span-Objekts an.
Die Klasse Date_Span
Die Klasse Date_Span ist ein Teil des Date-Pakets und dient dazu, mit Zeitspannen zu rechnen bzw. diese zu vergleichen. Eine Zeitspanne kann aus Tagen, Stunden, Minuten und Sekunden bestehen, nicht aber aus Monaten oder Jahren, da diese in ihrer Länge variabel sind. Die Klasse ist in der Datei Date/Span.php definiert und verfügt über einen sehr flexiblen Konstruktor. Zum Definieren einer Zeitspanne akzeptiert er zum Ersten eine Zeitangabe in Sekunden. Zum Zweiten können Sie eine Zeitspanne als String angeben. In diesem Fall muss über einen zweiten Parameter definiert werden, wie der zeitführende String aufgebaut ist. Hierzu werden die Platzhalter verwendet, wie sie für die Funktion strftime() vorgesehen sind und zum Teil in Tabelle 4.2 dargestellt sind. Glücklicherweise haben die Entwickler aber auch noch einfachere Möglichkeiten vorgesehen. Die Zeitinformation kann auch in einem indizierten Array mit maximal vier Elementen angegeben werden. Hierbei gilt, dass der letzte Wert des Arrays als Sekundenangabe interpretiert wird. Die davor liegenden Werte werden – wenn sie vorhanden sind – als Minuten, Stunden und Tage interpretiert. Eine weitere sehr einfache Möglichkeit, eine fest definierte Zeitspanne zum Initialisieren zu nutzen, besteht darin, einen String zu nutzen. Ein String im Format "12:30:14" würde 12 Stunden und 30 Minuten und 14 Sekunden entsprechen. Enthält der String bis zu drei Zahlen, wird die erste als Stunden interpretiert, die zweite als Minuten und die dritte als Sekunden. Geben Sie nur zwei Zahlen an, werden die Sekunden automatisch auf null gesetzt. Geben Sie allerdings vier Zahlen an, so wird die erste als Anzahl der Tage interpretiert.
// 2 Tage und 1 Stunde $sekunden=2*24*60*60 + 60*60; $span1=new Date_Span($sekunden); //1 Tag, 8 Stunden und 20 Minuten $span2=new Date_Span ("32:20","%H:%M"); // 12 Stunden, 50 Minuten und 10 Sekunden $zeit=array(12,50,10); $span3=new Date_Span($zeit); // 1 Tag, 12 Stunden, 30 Minuten und 3 Sekunden $span4=new Date_Span("1:12:30:3");
Zusätzlich existiert auch die Möglichkeit, dem Konstruktor zwei Date-Objekte zu übergeben. Diese beiden werden dann voneinander subtrahiert, und die so berechnete Differenz wird zur Initialisierung genommen.
$datum= new Date("2003–06–09 00:00:00"); $datum2= new Date("2005–06–19 01:02:03"); $span=new Date_Span($datum,$datum2); // $span enthaelt jetzt 741 Tage, 1 Stunde, // 2 Minuten und drei Sekunden
Die Informationen, die in einem Date_Span-Objekt enthalten sind, können auch nachträglich mit einer Reihe von set-Methoden wie setFromMinutes(), setFromSeconds() etc. überschrieben werden.
Natürlich ist es auch möglich, mit Zeitspannen zu rechnen. Die Methode add() addiert eine als Parameter übergebene Zeitspanne zu dem Objekt, aus dem sie aufgerufen wird, wohingegen subtract() eine Spanne subtrahiert.
Um logische Bedingungen von if-Abfragen oder Ähnlichem konstruieren zu können, sind auch mehrere Methoden vorgesehen. Die Methoden greater() und lower() entsprechen einem echten Größer-als bzw. einem Kleiner-als, wohingegen greaterEqual() und lowerEqual() einem Größer-gleich und einem Kleiner-gleich entsprechen. Alle Methoden bekommen ein Date_Span-Objekt übergeben, das sie mit dem Wert des Objekts vergleichen. Hierbei gilt, dass greater() dann ein true zurückliefert, wenn der Wert des Objekts größer ist als der des Parameters. Die Auswertung der Bedingung ist also »Objekt größer als Parameter«.
$tag=new Date_Span(24*60*60); $woche=new Date_Span(7*24*60*60); if (false===$tag->isEmpty()) { if (true===$tag->lower($woche)) { // Das hier wird ausgegeben echo("\$tag ist kleiner als \$woche"); } else { echo("\$tag ist größer als \$woche"); } }
Wie Sie in diesem kleinen Beispiel schon sehen, gibt es auch noch die Methode isEmpty(), mit der Sie prüfen können, ob ein Zeitspannen-Objekt dem Wert Null entspricht.
Um den Wert einer Zeitspanne auf einfache Art und Weise ausgeben zu können, sind verschiedene Member-Funktionen zur Konvertierung vorgesehen. Die Methoden toDays(), toHours() und toMinutes() liefern eine Float-Zahl zurück, die den Tagen, Stunden bzw. Minuten entspricht. toSeconds() hingegen konvertiert die Zeitspanne in Sekunden und gibt eine Integer-Zahl zurück.
$tag=new Date_Span(24*60*60); echo "Tage: ".$tag->toDays(); // Gibt 1 aus echo "Stunden: ".$tag->toHours();// Gibt 24 aus echo "Minuten: ".$tag->toMinutes();// Gibt 1440 aus
4.1.2 Vergleich von Daten 

Die Klasse stellt auch Methoden zur Verfügung, mit denen Sie Daten vergleichen können, um herauszufinden, ob ein Datum in der Zukunft oder in der Vergangenheit liegt. Die Methoden after() und before() vergleichen die Zeit, die im Objekt enthalten ist, mit einem Date-Objekt, das als Parameter übergeben wird. after() liefert ein true, wenn der Wert des Objekts zeitlich hinter dem Parameter liegt, wohingegen before() sich genau andersherum verhält. Um eine Gleichheit von zwei Date-Objekten festzustellen, können Sie auf equals() zurückgreifen. Diese Methode liefert ein true, wenn die beiden Werte exakt identisch sind, und andernfalls ein false.
Möchten Sie ein ganzes Array von Datumsobjekten sortieren, ist compare() Ihr »Freund«. Hierbei handelt es sich um eine Methode, die nur statisch aufgerufen werden kann und zwei Date-Objekte übergeben bekommt. Sie liefert –1, wenn der erste Parameter zeitlich vor dem zweiten liegt, eine 1, wenn es umgekehrt ist, und eine 0, wenn die beiden Daten denselben Zeitpunkt beschreiben. Diese Funktion ist gedacht, um sie mit der PHP-Funktion usort() einzusetzen, die ein Array sortiert. usort() erfordert neben dem Array, das sortiert werden soll, den Namen der Vergleichsfunktion, die für die Sortierung genutzt werden soll. Leider ist es hier nicht möglich, direkt eine statische Methode einer Klasse aufzurufen, so dass eine Wrapper-Funktion benötigt wird, über die Date::compare() aufgerufen werden kann.
require_once("Date.php"); $date[]=new Date(); $date[]=new Date("2005–12–14 20:20:20"); $date[]=new Date("2005–12–12 20:20:20"); // Wrapper-Funktion function my_compare($d1, $d2) { return Date::compare($d1,$d2); } // Aufruf von usort() sortiert das Array aufsteigend usort($date,"my_compare");
Hilfreich sind auch die Methoden isPast() und isFuture(), die ermitteln, ob das im Objekt enthaltene Datum in der Vergangenheit oder in der Zukunft liegt, und das mithilfe eines booleschen Wertes mitteilen.
4.1.3 Zeitzonen und Sommerzeit 

Das Paket kann auch mit verschiedenen Zeitzonen arbeiten. Wichtig hierfür ist die Klasse Date_TimeZone, die in der Datei Date/TimeZone.php definiert ist. Standardmäßig geht PEAR::Date davon aus, dass mit UTC [UTC steht für Coordinated Universal Time und entspricht der Greenwich Mean Time (GMT). ] gearbeitet wird. Sollten Sie nicht mit Sommerzeit arbeiten oder Termine über verschiedene Zeitzonen hinweg koordinieren wollen, sollte das kein Problem für Sie sein, und Sie sollten sich auch nicht weiter um die Zeitzonen kümmern. [In Version 1.4.3 hat PEAR::Date doch eine große »Vorliebe« für UTC und springt teilweise von allein in die falsche Zeitzone. Wenn Sie Zeitzonen nutzen, dann testen Sie ausführlich! ]
Welche Zeitzone Standard ist, versucht das Paket auf verschiedenen Wegen zu ermitteln. Primär wird aber der Inhalt der Variable $_DATE_TIMEZONE_DEFAULT ausgewertet, die per Default mit der Zeitzone UTC belegt wird. Möchten Sie von vornherein mit der Zeitzone arbeiten, die für Deutschland gültig ist, können Sie die Variable z. B. mit
vorbelegen. Bei dem hier übergebenen String handelt es sich um eine »TimeZone-ID«. Die Klasse kennt insgesamt 553 dieser IDs, von denen ich einige der wichtigsten in Tabelle 4.4 zusammengestellt habe.
Möchten Sie eine Liste mit allen verfügbaren IDs erhalten, können Sie diese mithilfe der Methode getAvailableIDs() auslesen, die Sie statisch aufrufen können:
Die so ermittelten IDs können Sie, wie schon erwähnt, zum Belegen der Variable $_DATE_TIMEZONE_DEFAULT nutzen. Darüber hinaus können Sie einem Date-Objekt auch eine andere Zeitzone zuweisen. Dies geschieht entweder über die Methoden setTZbyID() oder convertTZbyID(). Die erste legt nur einfach die Zeitzone für ein bestehendes Datum fest, wohingegen die zweite die enthaltene Information korrekt umrechnet. Somit ändern sich also die enthaltenen Werte; der Zeitpunkt, der damit definiert wird, bleibt aber gleich.
$date=new Date("2005–06–14 09:30:00"); $date->setTZbyID("Europe/Berlin"); // Zeitzone auf D setzen echo "Berlin: ".$date->getDate()."<br />"; // Gibt 'Berlin: 2005–06–14 09:30:00' aus // Zeitzone umrechnen auf USA / Westkueste $date->convertTZbyID("PST"); echo "Los Angeles: ".$date->getDate()."<br />"; // Gibt 'Los Angeles: 2005–06–13 23:30:00' aus // Zeitzone auf Tokyo setzen $date->convertTZbyID("Asia/Tokyo"); echo "Tokyo: ".$date->getDate(); // Gibt 'Tokyo: 2005–06–14 16:30:00' aus
Da die lokale Uhrzeit auch von einer eventuellen Umstellung auf Sommerzeit abhängt, kann die Klasse auch zu ermitteln versuchen, ob das angegebene Datum sich auf eine Zeitzone bezieht, die sich zum angegebenen Zeitpunkt in der Sommerzeit befindet. Die Methode inDaylightTime() ist zurzeit nur unter Unix-artigen Betriebssystemen und für die Jahre zwischen 1970 und 2038 verfügbar und funktioniert auch nur dann, wenn die putenv()-Funktion genutzt werden darf, was im Safe-Mode unter Umständen nicht möglich ist.
$date=new Date("2005–06–14 09:30:00"); // UTC hat keine Sommerzeit $date->setTZbyID("Europe/Berlin"); if (true==$date->inDaylightTime()) { echo ("Ja, Sommerzeit"); }
Bitte beachten Sie, dass die Methode 1 und 0 als Rückgabewerte nutzt. Ein Vergleich mithilfe des Identitätsoperators (===) würde hier also fehlschlagen.
Möchten Sie weitergehende Informationen über eine Zeitzone haben, können Sie ein Date_TimeZone-Objekt ableiten, das einige hilfreiche Methoden mit sich bringt, die Sie in Tabelle 4.5 finden.
Darüber hinaus ist in der Klasse noch die Methode getOffset() definiert, mit der Sie die Zeitverschiebung zu UTC an einem bestimmten Datum berechnen können. Sie bekommt ein Date-Objekt als Parameter übergeben:
// Datum in Tokyos Zeitzone definieren $datum = new Date ("2004–06–12 12:00:00"); $datum->setTZbyID("Asia/Tokyo"); // Neues TimeZone-Objekt $tz=new Date_TimeZone("Europe/Berlin"); // Gibt 3600000 aus echo $tz->getRawOffset()."<br>"; // Gibt 7200000 aus, also den Offset von $tz zu // dem uebergebenen Datum. Nicht von der Zeitzone // des Date-Objekts echo $tz->getOffset($datum);
Auch hierbei gelten die Einschränkungen, die ich bereits bei inDaylightTime() erwähnt habe.