PHPGangsta - Der praktische PHP Blog

PHP Blog von PHPGangsta


Das Y2K38 Problem

with 18 comments

Wer viel mit Terminen und Datumsangaben arbeitet kennt das Problem vielleicht, aber häufig fällt uns das Problem jetzt noch nicht auf, und in einigen Jahren werden wir dann Probleme bekommen.

Es geht um den Unix Timestamp, also die Anzahl der Sekunden seit 1970. In PHP arbeiten Funktionen wie time() und strtotime() mit diesem Timestamp, aktuell heute liegt diese Zahl bei ca. 1,3 Milliarden (1307428397). Wenn wir nun mit Geburtsdaten arbeiten und jemand hat vor 1970 Geburtstag, dann können wir bekannterweise nicht den Timestamp nutzen. Aber es gibt auch eine obere Grenze, und kaum jemand weiß wo diese liegt. PHP arbeitet im 32-bit-Modus mit 4-Byte signed Integers, also vorzeichenbehaftete Zahlen zwischen -2.147.483.647 und 2.147.483.647, aktuell sind wir mit 1,3 Milliarden bereits über die Hälfte vorangeschritten. Exakt am 19.01.2038 um 03:14:07 werden wir einen Überlauf haben, der Timestamp wird also von 2.147.483.647 auf -2.147.483.647 umspringen, und negative Timestamps bedeuten immer 01.01.1970.

Mit einem Zweizeiler können wir zeigen dass wir bei Timestamps größer 2038 ein Problem bekommen:

<?
$date = strtotime('2037-02-01');
echo date('d.m.Y H:i', $date);

Die Ausgabe in diesem Fall lautet 01.02.2037 00:00.

<?
$date = strtotime('2039-02-01');
echo date('d.m.Y H:i', $date);

Hier haben wir das Maximum überschritten, es wird ausgegeben: 01.01.1970 01:00.

Aber nicht nur PHP hat Probleme damit, sehr viele Programmiersprachen, Programme und Betriebssysteme sind betroffen. Und da wir alle wissen wie lang einige Programme laufen werden (na, wer muss noch mit alten Cobol-Programmen arbeiten, oder Intranetseiten von 1995 nutzen?), oder man Termine für die Zukunft plant, sollte man schon jetzt mit dem Problem vertraut sein, um nicht schwer zu findende Bugs zu produzieren.

Es gibt mehrere Lösungen um das Problem zu umgehen. Entweder man arbeitet mit 64-bit Systemen und Software, die 8-Byte signed Integers nutzen, um damit das Problem effektiv zu beseitigen. Eine zweite Möglichkeit ist die Zeit in einem String zu speichern, also einfach „2045-05-27“ speichern und dann mit Hilfe der  DateTime Klassen diesen String umwandeln und mit ihm rechnen:

$date = new DateTime('2045-05-27');
echo $date->format('d.m.Y H:i');

Gibt aus: 27.05.2045 00:00.

Also kurz drüber nachdenken wenn ihr das nächste Mal Unix Timestamps nutzt die in der Vergangenheit oder der Zukunft liegen, oder falls euer Programm evtl. auch noch in 27 Jahren laufen wird.

Written by Michael Kliewe

Juni 7th, 2011 at 9:09 am

Posted in PHP

Tagged with , , ,

18 Responses to 'Das Y2K38 Problem'

Subscribe to comments with RSS or TrackBack to 'Das Y2K38 Problem'.

  1. Ich habe Timestamps schon lange aus meinem Alltag verbannt. Nach vorne UND nach hinten begrenzt, das hat doch nur Nachteile.

    Daniel

    7 Jun 11 at 09:18

  2. Danke, werde demnächst wieder alle Termine als String speichern. „Hintenrum“ ändert sich nix, habe ich grade gemerkt, Zend_Date sei Dank 😉

    Sascha Presnac

    7 Jun 11 at 09:51

  3. Ich finde, dass Timestamps nicht mehr zeitgerecht sind. Zwar bietet der Timestamp Vorteile bezüglich weniger* Speicherverbrauch und schnellerem Umrechnen aber hat immer auch das „Problem“ mit der Relation zum Beginn der Unix-Epoche. Des Weiteren bieten Formate wie YmdHis schnellere Lesbarkeit.

    *
    1111111111 vs. 20050318015831 = 18.03.2005 – 01:58:31
    1111104000 vs. 20050318 = 18.03.2005 – 00:00:00

    php

    7 Jun 11 at 10:02

  4. Mir war das Problem durchaus bekannt (wurde uns in der Schule anno dazumals mehrmals eingetrichtert), und in PHP lässt sich das, wie gesagt, bereits jetzt einfach umgehen. Viel mehr Sorgen bereitet mir gerade MySQL/MSSQL.

    Nehmen wir an, wir haben ~30 Tabellen mit je etwa 60k Datensätzen. So gut wie jede Tabelle besitzt die Felder created und modified, welche automatisch befüllt werden (on update CURRENT_TIMESTAMP z.B.)

    Wie baut man das nun um? Komplettes Auslagern in PHP kommt in den meisten Fällen nicht in Frage: Eine MySQL-Klasse so zu ändern, dass sie damit klarkommt, setzt voraus, dass jede Tabelle diese Felder besitzt, man müsste also grobe Anpassungen am Datenmodell vornehmen, jede Abfrage zu ändern ist in grösseren Projekten ein Overkill. Hinzu kommt noch die Migration

    Ich denke, da muss früher oder später ein MySQL-Update her, obwohl ich nicht denke, dass das sofort die Runde machen und innert kürzester Zeit auf jedem Server installiert sein wird…

    DukeNightcrawler

    7 Jun 11 at 10:31

  5. Ich hatte ebenfalls schon vor ein paar Jahren Timestamps verbannt und nehme eigentlich nur noch das mysql datetime Format. Damit kann man auch die Berechnungen auf die DB auslagern und die Resultsets verkleinert und damit meistens effektiv beschleunigt.

    Oliver

    7 Jun 11 at 10:31

  6. 64Bit sollte so oder so echt mal langsam Standard werden.

    KingCrunch

    7 Jun 11 at 10:40

  7. Mir ist das Problem bekannt und verwende wo es geht DATE bzw. DATETIME Felder.

    Aber wie sieht es mit Zeitzonen aus? Ich habe eine Software für einen Kunden am Laufen, die er an allen Produktionsstandorten (3 verschiedene Zeitzonen) im Einsatz hat. Mit Timestamps bleibe ich „zeitzonen-neutral“.

    Steht noch auf meiner Todo mich genauer damit zu befassen, würde mich aber interessieren, wie ihr das gelöst habe / lösen würdet.

    Andi

    7 Jun 11 at 11:57

  8. Oliver

    7 Jun 11 at 12:19

  9. ROMOPAT

    7 Jun 11 at 14:55

  10. @DukeNightcrawler: der unix timestamp hat mit dem mysql timestamp nichts gemeinsam. da dürfte es keine probleme geben, da der mysql timestamp in form von yyyy-mm-dd hh:ii:ss gespeichert wird.

    volker

    7 Jun 11 at 16:06

  11. Hehe,

    Wer von euch hat denn vor 2038 noch zu arbeiten? Und dann auch noch PHP?

    Laut:

    http://entwickler.com/itr/news/psecom,id,55213,nodeid,82.html

    ist 2037 Schluss mit PHP …

    ilja

    7 Jun 11 at 16:21

  12. „negative Timestamps bedeuten immer 01.01.1970“ – das ist dann wohl eine Eigenart von PHP, denn der Timestamp -2.147.483.648 (nicht …7!) entspricht dem 13. Dezember 1901 20:45:52 Uhr. Nur der Timestamp 0 ist exakt der 1. Januar 1970 01:00:00.

    Bei dem MySQL-Typ DATETIME gibt es auch ein Problem: seit MySQL 5 ist die Funktion TIMEDIFF, die zwei DATETIMEs akzeptiert und die Differenz zwischen zwei Daten in hh:mm:ss zurückgibt, nach oben beschränkt, der Maximalwert ist 838:59:59 (knapp 35 Tage). Liegen zwei DATETIME-Werte mehr als 35 Tage auseinander, so wird empfohlen, die DATETIMEs in Timestamps umzuwandeln mit UNIX_TIMESTAMP und von diesen normal die Differenz zu berechnen:

    SELECT UNIX_TIMESTAMP(‚2000-01-01 23:00:00‘) – UNIX_TIMESTAMP(‚1999-12-31 23:00:00‘)
    Ergibt die Differenz in Sekunden 86400
    (Hier würde TIMEDIFF natürlich funktionieren, nur zur Illustration. ^^)

    Das Jahr-2038-Problem ist hier selbstverständlich auch vertreten:
    SELECT UNIX_TIMESTAMP(‚2039-01-01 23:00:00‘) – UNIX_TIMESTAMP(‚1999-12-31 23:00:00‘)
    Ergibt -946677600

    Spätestens, wenn man also Differenzen von DATETIMEs berechnen will, stösst man damit auch an Grenzen. Ich habe leider im Moment kein MySQL 4 zur Hand, sonst würde ich noch testen, ob TIMEDIFF dort für das letzte Beispiel einen korrekten Wert zurückgibt.

    Z4ppy

    7 Jun 11 at 16:40

  13. Im Jahr 2037 sind wir hoffentlich mit allen Systemen auf 64 Bit … nein? 😉

    coke

    12 Jun 11 at 13:39

  14. „negative Timestamps bedeuten immer 01.01.1970″

    Das stimmt so nicht ganz. Die Unterstützung von negativen Timestamps ist vom Betriebssystem abhängig (gemäss meinem Wissen; Windows: n/a, Linux: meistens verfügbar).

    Sofern vom System unterstützt, funktioniert es also problemlos:

    echo mktime(2,15,15,2,5,1965).“\n“;
    echo date(‚d.m.Y‘,-154737885);

    ergibt:
    -154737885
    05.02.1965

    Siehe auch php-Doku:
    „Not all conversion specifiers may be supported by your C library, in which case they will not be supported by PHP’s strftime(). Additionally, not all platforms support negative timestamps, so your date range may be limited to no earlier than the Unix epoch.[…]“ – http://ch.php.net/manual/en/function.strftime.php

    rolf

    4 Jul 11 at 02:48

  15. […] der Sekunden seit 1.1.1970 gespeichert, weshalb der mögliche Zeitraum nur von 1901-12-13 bis 2038-01-19 reicht. Wenn das Betriebssystem 64-Bit-Zeitstempel unterstützt, tut dies der PHP-Zeitstempel aber […]

  16. php kann inzwischen mit 64bit timestamps umgehen.
    mysql wird noch deutlich vor 2038 folgen.

    für viele bereiche (vor allem interne berechnungen, zeitlimits etc.) finde ich timestamps immer noch am einfachsten und performantesten (weil nicht ständig irgendwelche datetime-strings umgewandelt werden müssen).

    ich würde die timestamps daher nicht komplett verbannen. die wurden „damals“ nicht umsonst aufgrund ihrer einfachheit erfunden.

    hans

    12 Dez 12 at 20:34

  17. Hallo und danke für den Beitrag. Leider scheint der Befehl strftime nicht zu funktionieren, hier wird immer mit 1. Januar 1970 übersetzt ->

    $date = $date->getTimestamp();
    echo strftime(‚%d. %B %Y‘, $date);

    Gibt es hier eine Lösung?

    Vielen Dank im voraus 🙂

    Andreas

    23 Jan 17 at 11:11

  18. @Andreas Was ist bei dir $date?

    $date = new DateTime('2017-01-23');
    $date = $date->getTimestamp();
    echo strftime('%d. %B %Y', $date)."\n";

    $date = new DateTime('2045-05-27');
    $date = $date->getTimestamp();
    echo strftime('%d. %B %Y', $date)."\n";

    Die Ausgabe lautet:
    23. January 2017
    27. May 2045

    Ich habe hier PHP 7.1.1 unter Linux.

    Wie rolf oben schon schrieb, strftime hat einige Limitierungen, z.B. unter Windows. Siehe auch die Hinweise auf http://php.net/strftime

    Michael Kliewe

    23 Jan 17 at 11:45

Leave a Reply

You can add images to your comment by clicking here.