Unixzeit

aus Wikipedia, der freien Enzyklopädie
(Weitergeleitet von Unix-Zeit)
Wechseln zu: Navigation, Suche

Die Unixzeit ist eine einfache Zeitdefinition, die für das Betriebssystem Unix entwickelt und als POSIX-Standard festgelegt wurde. Vor Unix Version 6 (1975) zählte die Unix-Uhr in Hundertstelsekunden, daher musste die Epoche jedes Jahr neu festgelegt werden. Seit Unix Version 6 zählt die Unixzeit die vergangenen Sekunden seit Donnerstag, dem 1. Januar 1970, 00:00 Uhr UTC, wobei Schaltsekunden nicht mitgezählt werden. Dieses Startdatum wird auch als The Epoch (siehe Epoche) bezeichnet.

Eigenschaften[Bearbeiten | Quelltext bearbeiten]

Umrechnung[Bearbeiten | Quelltext bearbeiten]

Die Umrechnung in eine menschenlesbare Form sowie die Anwendung von Zeitzonen, Sommerzeit und Schaltjahren werden dann von zusätzlichen Funktionen der Standardbibliothek übernommen. Die Darstellung des Datums als Sekunden seit der Unix-Epoche wird häufig verwendet, weil sie für Computerprogramme viel leichter zu verarbeiten ist als das „menschliche“ Datumsformat. Außerdem lassen sich mit diesen Werten leicht Zeiträume berechnen, indem man einfach den einen Wert vom anderen abzieht. Umstellung auf Sommer- oder Winterzeit spielen dann keine Rolle mehr. Aus diesem Grund wird dieser Wert auch gerne als Zeitstempel verwendet. In vielen modernen Server-Anwendungen spielt der Zeitstempel aufgrund dieser Vorteile weiterhin eine tragende Rolle, so etwa im Umfeld von PHP- oder MySQL-Applikationen bei der Unterscheidung und Generierung zeitbezogener Datenbank-Einträge. Die vordefinierten PHP-Funktionen date() und mktime() ermöglichen hier beispielsweise durch das Einsetzen passender Funktionsargumente die einfache Konvertierung eines Zeitstempels in ein menschenlesbares Datumsformat und umgekehrt.

Jahr-2038-Problem[Bearbeiten | Quelltext bearbeiten]

Vorlage:Zukunft/In 5 Jahren

Hauptartikel: Jahr-2038-Problem
Exemplarische Darstellung des Jahr-2038-Problems

Viele, aber bei weitem nicht alle Systeme, welche die Unixzeit verwenden, speichern und verarbeiten die Zeitangabe in Sekunden seit 1. Januar 1970 als vorzeichenbehaftete 32-Bit-Zahl (Integer). Somit umfasst der Sekundenraum die Werte −2.147.483.648 bis +2.147.483.647. Umgerechnet in Jahre entspricht dies etwas mehr als −68 bis +68.

Am 19. Januar 2038 um 3:14:08 Uhr UTC wird es daher bei Computersystemen, welche die Unixzeit in einer vorzeichenbehafteten 32-Bit-Variable speichern, zu einem Überlauf kommen. Die darzustellende Zeit wird dann mit der 2.147.483.648sten Sekunde nicht mehr in der Variable gespeichert werden können, womit es dann zum Jahr-2038-Problem kommen würde.

Unixzeiten vor dem 13. Dezember 1901 20:45:52 UTC sind mit einer vorzeichenbehafteten 32-Bit-Zahl auch nicht darstellbar, da die Zeitstempel kleiner als −2.147.483.648 wären.

Moderne Unix-Systeme verwenden zumindest in ihrer 64-Bit-Variante eine vorzeichenbehaftete 64-Bit-Zahl, was keine nennenswerte Beschränkung des Wertebereichs bewirkt.

Trotz der allgemeinen Tendenz zu 64-Bit-Systemen sind eingebettete Systeme auf Unix-Basis zurzeit noch nahezu ausschließlich 32-Bit-Systeme. Die in letzter Zeit erkennbare Tendenz, Haushaltsgeräte (z. B. Router, Radiowecker und Ähnliches) durch eingebettete Systeme auf Unix-Basis zu implementieren, birgt daher das Risiko, dass diese Geräte ab dem 19. Januar 2038 nicht mehr korrekt funktionieren.

Verwendet ein Entwickler den vorzeichenlosen (unsigned-) 32-bit-Typ, kann er die UNIX-Zeit noch bis über das Jahr 2100 hinaus verwenden, allerdings sind Zeitwerte vor 1970 dann nicht mehr darstellbar.

Schaltsekunden[Bearbeiten | Quelltext bearbeiten]

Schaltsekunden werden nicht mitgezählt, da die Unixzeit mit der UTC-Zeit synchronisiert wird. Das bedeutet, dass während der Schaltsekunde die Unixzeit weiter läuft. Sobald die UTC-Zeit von 23:59:60 auf 00:00:00 springt (nach Ablauf der Schaltsekunde), wird von der Unixzeit die Differenz (1 Sekunde) subtrahiert. Ab diesem Zeitpunkt durchläuft sie also nochmals den gleichen Wertebereich wie in der Sekunde zuvor. Die Unixzeit-Angaben für die Sekunde, die der Schaltsekunde folgt, sind somit mehrdeutig: sie entsprechen jeweils zwei Zeitpunkten der physikalischen Zeit (Atomzeit), die sich um eine Sekunde unterscheiden.

The Epoch, also der Einsatzpunkt der Unixzeit, ist als 1. Januar 1970 00:00 Uhr UTC definiert. Jedoch gab es zu dieser Zeit das heutige UTC-System noch nicht, da es in der jetzigen Form erst 1972 eingeführt wurde. Der Zeitpunkt der Epoche ist eigentlich der 1. Januar 1970 00:00 Uhr GMT. Zu diesem Zeitpunkt sind zurückgerechnete UTC-Zeit und GMT-Zeit zufällig identisch. Jedoch stimmen UTC-Unixzeiten vor dem 1. Januar 1972 aufgrund unterschiedlicher Schaltsekunden in UTC und GMT nicht immer exakt mit den damals gebrauchten GMT-Zeitangaben überein. Unixzeit eignet sich daher nicht für die sekundengenaue Zeitdarstellung jeder beliebigen Zeit vor dem 1. Januar 1972.

In den letzten Jahren gab es mehrere Versuche, im Rahmen der POSIX-Standardisierung eine Darstellung der Schaltsekunde zur POSIX-Unix-Zeitdefinition hinzuzufügen. Die Diskussionen zu diesem Thema führten jedoch bislang nicht zu einem allgemein akzeptierten Ergebnis. Viele Unix-Systeme implementieren aber neben der Unix-Zeit, die meist der gesetzlichen Zeit nachgeführt wird, zusätzlich eine hochaufgelöste Zeit, die monoton seit dem letzten Reboot zählt und daher für hochgenaue Zeitdifferenz-Messungen geeignet ist.

Vergleich[Bearbeiten | Quelltext bearbeiten]

Die Unixzeit hat sich im Computerbereich durchgesetzt, da die Zeitdifferenz zwischen zwei Ereignissen eine Subtraktion zweier Integer-Werte ist. Dies kann durch moderne Rechenwerke in einem Takt erfolgen. Dies ist sinnvoll für Hochdurchsatz bei Spezialanwendungen wie Kommunikationselementen (Internet) und Dateiservern (auch Datenbanken). Zur Verbreitung des Internets war zudem eine einheitliche Darstellung der Zeit zur Koppelung der Dateisysteme entfernter Rechner notwendig. Tatsächlich basieren viele der handelsüblichen Netzwerkgeräte intern auf einem angepassten Unixsystem (Embedded Linux).

Für die menschliche Anwendung sinnvoller sind oft die gebrochenen Zeiten, bei der die übliche UTC-Zeit in sechs Zahlen für Jahr, Monat, Tag, Stunde, Minute, Sekunde und zusätzlichen Angaben für Zeitzone und Sommerzeit ausgedrückt wird. Auch Unix kennt eine Konvertierung der Unixzeit in eine gebrochene Darstellung mittels localtime(). In den DOS-Systemen war dagegen die gebrochene Zeit ohne Zeitzonenangaben das Standardformat und wird auf FAT-Dateisystemen für Zeitstempel der Dateien in einer kompakten Darstellung gespeichert. Die gebrochene Darstellung macht jedoch Berechnungen aufwändig. In einzelnen Fällen ist eine Zeitangabe ohne einen Hinweis auf die Zeitzone unbrauchbar.

Eine Zeitangabe kann auch als Gleitkommazahl gespeichert werden. Dabei können auch sehr weit entfernte Zeitangaben gespeichert werden, teils Millionen Jahre entfernt, dann aber unter verminderter Zeitgenauigkeit. Eine sekundengenaue Angabe erfolgt nur nahe der Basiszeit (Epoche), die der Gleitkomma-Null entspricht. Eine Auflösung von unter einer Sekunde ist z. B. mit einem Double-Wert für die nächsten 10.000 Jahre gesichert.

Besondere Werte[Bearbeiten | Quelltext bearbeiten]

Das Unix-Millennium wurde am 9. September 2001 in Kopenhagen auf einer Party der dänischen Unix User Group um 03:46:40 Ortszeit gefeiert

Unix-Enthusiasten haben es zum Brauch gemacht, zu bestimmten Werten der Unixzeit so genannte time_t parties – ähnliche den Neujahrsfeiern zum Jahreswechsel – zu veranstalten. Üblicherweise werden runde Dezimal-Werte, wie 1.000.000.000 oder 2.000.000.000 gefeiert. Unter manchen Benutzern werden allerdings auch runde Binär-Werte gefeiert, beispielsweise +230 (1.073.741.824), welcher auf den 10. Januar 2004 13:37:04 UTC fiel. Am 13. Februar 2009 um 23:31:30 UTC (14. Februar 2009 um 00:31:30 CET) schaltete der Suchmaschinenbetreiber Google ein spezielles Doodle, da die Unixzeit in diesem Moment den Wert 1234567890 erreichte.[1] Auch der Heise Newsticker widmete diesem Wert einen Artikel.[2]

Diese Zeitpunkte werden üblicherweise als „n Sekunden seit der Unix-Epoche“ gefeiert. Durch die Einführung von Schaltsekunden ist diese Bezeichnung allerdings nicht ganz korrekt.

Wert hexadezimal Zeitpunkt (UTC)
−231 = −2 147 483 648 80 00 00 00 13. Dezember 1901   20:45:52
−230 = −1 073 741 824 B0 00 00 00 23. Dezember 1935   10:22:56
−1 000 000 000 C4 65 36 00 24. April 1938   22:13:20
−229 = −0536 870 912 E0 00 00 00 27. Dezember 1952   05:11:28
−228 = −0268 435 456 F0 00 00 00 30. Juni 1961   02:35:44
0 00 00 00 00 1. Januar 1970   00:00:00
216 = 0000065 536 00 01 00 00 1. Januar 1970   18:12:16
224 = 0016 777 216 01 00 00 00 14. Juli 1970   04:20:16
100 000 000 05 F5 E1 00 3. März 1973   09:46:40
228 = 0268 435 456 10 00 00 00 4. Juli 1978   21:24:16
500 000 000 1D CD 65 00 5. November 1985   00:53:20
229 = 0536 870 912 20 00 00 00 5. Januar 1987   18:48:32
805 306 368 30 00 00 00 9. Juli 1995   16:12:48
1 000 000 000 3B 9A CA 00 9. September 2001   01:46:40
230 = 1 073 741 824 40 00 00 00 10. Januar 2004   13:37:04
1 111 111 111 42 3A 35 C7 18. März 2005   01:58:31
1 234 567 890 49 96 02 D2 13. Februar 2009   23:31:30
1 300 000 000 4D 7C 6D 00 13. März 2011   07:06:40
1 342 177 280 50 00 00 00 13. Juli 2012   11:01:20
1 400 000 000 53 72 4E 00 13. Mai 2014   16:53:20
1 500 000 000 59 68 2F 00 14. Juli 2017   02:40:00
1 600 000 000 5F 5E 10 00 13. September 2020   12:26:40
1 610 612 736 60 00 00 00 14. Januar 2021   08:25:36
1 700 000 000 65 53 F1 00 14. November 2023   22:13:20
1 800 000 000 6B 49 D2 00 15. Januar 2027   08:00:00
1 879 048 192 70 00 00 00 18. Juli 2029   05:49:52
1 900 000 000 71 3F B3 00 17. März 2030   17:46:40
2 000 000 000 77 35 94 00 18. Mai 2033   03:33:20
2 100 000 000 7D 2B 75 00 18. Juli 2036   13:20:00
231 −1 = 2 147 483 647 7F FF FF FF 19. Januar 2038   03:14:07

Unix-Befehle[Bearbeiten | Quelltext bearbeiten]

Bei einigen Unix-ähnlichen Systemen lässt sich mittels nachstehendem Befehl eine Unixzeit in die äquivalente UTC-Zeit umrechnen (das Verhalten von date aus dem Beispiel ist nicht Bestandteil des POSIX-Standards).

 date -u -d @UNIXTIME

Beispiel:

 date -u -d @1234567890
 Fr 13. Feb 23:31:30 UTC 2009

Umgekehrt lässt sich die aktuelle Anzahl der vergangenen Sekunden seit dem 1. Januar 1970 auf einigen Unix-/Linux-Systemen mittels

 date +%s

anzeigen (das Verhalten von date ist auch hier nicht Bestandteil des POSIX-Standards).

Beispiel-Implementierung[Bearbeiten | Quelltext bearbeiten]

Möchte man die Unixzeit zu einem gegebenen Zeitpunkt berechnen, lässt sich das über folgenden Rechenweg bewerkstelligen. Die Unixzeit kennt keine Zeitzonen und nutzt als Eingabe eine von Zeitzonen bereinigte Zeit.

Achtung: Der folgende Quelltext ist in der Programmiersprache C verfasst, und arbeitet daher mit maschinenabhängigen Genauigkeiten. Das Jahr-2038-Problem tritt bei diesem Programm jedoch nicht auf. Wie jeder Beispielquelltext dient er allein der Illustration und sollte ohne Überprüfung nicht in den Praxiseinsatz übernommen werden.

/** Konvertiert gegliederte UTC-Angaben in Unix-Zeit.
 * Parameter und ihre Werte-Bereiche:
 * - jahr [1970..2038]
 * - monat [1..12]
 * - tag [1..31]
 * - stunde [0..23]
 * - minute [0..59]
 * - sekunde [0..59]
 */
long long unixzeit(int jahr, int monat, int tag,
              int stunde, int minute, int sekunde)
{
  const short tage_seit_jahresanfang[12] = /* Anzahl der Tage seit Jahresanfang ohne Tage des aktuellen Monats und ohne Schalttag */
    {0,31,59,90,120,151,181,212,243,273,304,334};

  int schaltjahre = ((jahr-1)-1968)/4 /* Anzahl der Schaltjahre seit 1970 (ohne das evtl. laufende Schaltjahr) */
                  - ((jahr-1)-1900)/100
                  + ((jahr-1)-1600)/400;

  long tage_seit_1970 = (jahr-1970)*365 + schaltjahre
                      + tage_seit_jahresanfang[monat-1] + tag-1;

  if ( (monat>2) && (jahr%4==0 && (jahr%100!=0 || jahr%400==0)) )
    tage_seit_1970 += 1; /* +Schalttag, wenn jahr Schaltjahr ist */

  return sekunde + 60 * ( minute + 60 * (stunde + 24*tage_seit_1970) );
}

Eine Umrechnung von einer gegebenen Unixzeit in unsere gewöhnliche Datums- und Zeitdarstellung ist mit folgender Funktion möglich.

void UnixzeitNachDatumZeit(unsigned long int unixtime,
                           int *pJahr, int *pMonat, int *pTag,
                           int *pStunde, int *pMinute, int *pSekunde)
{
    const unsigned long int SEKUNDEN_PRO_TAG   =  86400ul; /*  24* 60 * 60 */
    const unsigned long int TAGE_IM_GEMEINJAHR =    365ul; /* kein Schaltjahr */
    const unsigned long int TAGE_IN_4_JAHREN   =   1461ul; /*   4*365 +   1 */
    const unsigned long int TAGE_IN_100_JAHREN =  36524ul; /* 100*365 +  25 - 1 */
    const unsigned long int TAGE_IN_400_JAHREN = 146097ul; /* 400*365 + 100 - 4 + 1 */
    const unsigned long int TAGN_AD_1970_01_01 = 719468ul; /* Tagnummer bezogen auf den 1. Maerz des Jahres "Null" */

    unsigned long int TagN = TAGN_AD_1970_01_01 + unixtime/SEKUNDEN_PRO_TAG;
    unsigned long int Sekunden_seit_Mitternacht = unixtime%SEKUNDEN_PRO_TAG;
    unsigned long int temp;

    /* Schaltjahrregel des Gregorianischen Kalenders:
       Jedes durch 100 teilbare Jahr ist kein Schaltjahr, es sei denn, es ist durch 400 teilbar. */
    temp = 4 * (TagN + TAGE_IN_100_JAHREN + 1) / TAGE_IN_400_JAHREN - 1;
    *pJahr = 100 * temp;
    TagN -= TAGE_IN_100_JAHREN * temp + temp / 4;

    /* Schaltjahrregel des Julianischen Kalenders:
       Jedes durch 4 teilbare Jahr ist ein Schaltjahr. */
    temp = 4 * (TagN + TAGE_IM_GEMEINJAHR + 1) / TAGE_IN_4_JAHREN - 1;
    *pJahr += temp;
    TagN -= TAGE_IM_GEMEINJAHR * temp + temp / 4;

    /* TagN enthaelt jetzt nur noch die Tage des errechneten Jahres bezogen auf den 1. Maerz. */
    *pMonat = (5 * TagN + 2) / 153;
    *pTag = TagN - (*pMonat * 153 + 2) / 5 + 1;
    /*  153 = 31+30+31+30+31 Tage fuer die 5 Monate von Maerz bis Juli
        153 = 31+30+31+30+31 Tage fuer die 5 Monate von August bis Dezember
              31+28          Tage fuer Januar und Februar (siehe unten)
        +2: Justierung der Rundung
        +1: Der erste Tag im Monat ist 1 (und nicht 0).
    */

    *pMonat += 3; /* vom Jahr, das am 1. Maerz beginnt auf unser normales Jahr umrechnen: */
    if (*pMonat > 12)
    {   /* Monate 13 und 14 entsprechen 1 (Januar) und 2 (Februar) des naechsten Jahres */
        *pMonat -= 12;
        ++*pJahr;
    }

    *pStunde  = Sekunden_seit_Mitternacht / 3600;
    *pMinute  = Sekunden_seit_Mitternacht % 3600 / 60;
    *pSekunde = Sekunden_seit_Mitternacht        % 60;
}

Diese Funktion erwartet als Eingangsparameter eine vorzeichenlose Ganzzahl ("unsigned long int"). Nach dem C-Standard sind das mindestens 32 Bit. Die Funktion liefert somit korrekte Ergebnisse bis mindestens zum Januar 2106.

Weblinks[Bearbeiten | Quelltext bearbeiten]

Einzelnachweise[Bearbeiten | Quelltext bearbeiten]

  1. Doodle zur Unixzeit 1234567890
  2. heise.de