Datum- / Zeitformat

Datum- / Zeitformat

Motivation sich hier Gedanken zu machen

Was bewegt mich, mir Gedanken über ein Datum- / Zeitformat zu machen. Heute arbeiten wir mit Timestamp, Datum und Uhrzeit. Schön der Timestamp wird intern oft als Milli- oder Microsekunden ab einem fixen Zeitpunkt abgelegt. Damit gibt es schon mal für alte Zeiten keinen Timestamp mit all seinen Funktionen. Ein Datum wird dann meist direkt als solches verwaltet. Dazu dann noch die Zeitzonen. Zu einem Datum gerade mal 1 Stunde addieren? Wie speichere ich dieses? Klar mit einer Menge an Funktionalitäten haben wir es irgendwie im Griff. Aber es müsste einfach gehen.

Dazu kommt, dass wir in den modernen Zeiten viele Daten im JSON - Format oder in Python Wörterbücher ablegen. Da ein Timestamp (hier als String), der aus verschiedenen Einzelwerten zusammen gesetzt ist, ein Wert ergibt, muss ständig dieser Wert zerlegt und abgeglichen werden. Bei großen Mengen ein Zeitfaktor und bei historischer Datenhaltung schon eine Herausforderung.

So suchen wir eine Lösung. Die Art die ich hier beschreibe ist vielleicht nicht die optimale, aber mit Sicherheit eine gute Lösung. Sollte es Ideen geben, diese noch zu verbessern, lasse es mich wissen.

Das Format für ein Datum

Wir haben beim Datum Jahre, Monate und Tage. Wenn wir es in diesen Einheiten (JJJJMMTT) haben und verarbeiten, dan haben wir innerhalb einer Zahl zwei Umbrüche der Einheiten. Das bedeutet bei den Tagen ist der Umbruch zum Monat ein Wert zwischen 28 und 31. Dieses ist dann vom Monat abhängig, dazu kommt, dass im Februar noch das Schaltjahr beachtet werden muss. Dazu kommt dann der zweite Umbruch von Monat aufs Jahr. Dieser ist relativ einfach, da nach dem Monat 12 immer der Monat 1 des Folgejahres folgt.

Einen Dezimalen Umbruch in jeder Ziffer wäre das Beste. Dann sind wir aber wieder bei Tagen, die wir ab irgendwo zählen. Damit wir alle Daten darstellen können, die sich auf Datum beziehen wäre es gut, wenn wir uns auf das julianische Datumsformat besinnen. Also die Jahreszahl und der Industrietag (JJJJIII). Der Industrietag ist der Tag im Jahr gezählt ab 1. Januar. Also der 01.01.2020 entspricht dann 2020001 (einer ganzen Zahl), der 01.02.2020 entspricht dann 2020032 (also dem 32 Tag im Jahr). Damit können wir jedes Datum eindeutig und lesbar darstellen. Als Umbruch haben wir nur den Jahresumbruch bei 365/366 bzw. 1.

Die Werte die dann vor Christus sind können wir einfach als negativen Wert darstellen. Die Negation bezeiht sich dann nur auf die Jahreszahl. Demnach ist -5032 der 1. Februar 5 vor Christus. Klar ist, dass wir zu unterschiedlichen Zeitepochen auch unterschiedliche Kalender hatten. Es macht aber Sinn, dieses nach unserem heutigen Kalenderverständnis einheitlich zu verwalten. In der Regel wird man bis auf ganz geringe Ausnahmen im positiven Bereich bleiben. Diesen wollen wir auch noch weiter betrachten.

Noch eine Festlegung, damit es mit der Zeit später auch funktioniert. Das Datum hat immer die Uhrzeit 00:00 Uhr. Dieses auch dann wenn wir es getrennt verwenden.

Der große Vorteil hierbei ist dass man im selben Format einfach damit addieren und subtrahieren kann. Also wenn ich zum Beispiel zu einem Datum (2020032) einfach 40 Tage dazu zählen möchte rechne ich einfach 2020032 + 40 = 2020072 (dieses ist der 12.03.2020). Hier muss ich nur den Umbuch zum nächsten Jahr betrachten und ggf. korrigieren. Gehen wir er und zeihen die 40 Tage ab, rechnen wir 2020032 - 40 = 2019992 (die letzten 3 Stellen sind größer 365, also modifizieren. 2019992 + 365 - 1000 = 2019357 (dieses ist der 24.12.2019).

Noch ein Beispiel mit dem Umbruch bei der Addition über den Jahreswechsel. Wir haben den 01.12.2020 (2020336) und addieren hier wieder unser 40 Tage (2020336 + 40 = 2020376(die letzten 3 Stellen sind größer 366 (2020 ist ein Schaltjahr), also modifizieren. 2020376 + 1000 - 366 = 2021010 (diese ist der 10.01.2021)

Dieses funktioniert nicht nur mit Tagen sonden auch Jahr und Tagen. Also wenn ich zu unserm 01.02.2020 - 2020032 einfach zwei Jahre und 40 Tage addieren möchte errechne ich unseren Additionswert (2 Jahre * 1000 = 2000  dazu kommen dann noch die Tage, enspricht damit 2040). Rechnen wir 2020032 + 2040 = 2022072 (dieses ist der 12.03.2022).

Wir können auch 1 Jahr und 340 Tage zum 01.02.2020 (2020032) addieren. Additionswert 1 Jahr * 1000 = 1000 zuzüglich 340 Tage = 1340. Rechnen wir 2020032 + 1340 = 2021372 ( die letzten 3 Stellen sind größer als 365, also modifizieren.  2021372 + 1000 - 365 = 2022007 (dieses ist der 07.01.2022).

Berechnen können wir damit auch eine Differenz zwischen weit Daten. Also zum Beispiel das Alter. Geburtstag ist 1955259 und als heute nehmen wir 2020063 an. Wir rechnen 2020063 - 1955259 = 64804 (modifizieren 64804 - 1000 + 365 (Jahreswert es letzten Jahres) = 64169). Das Alter ist damit 64 Jahre und 169 Tage.

Noch ein Gedanke zu diesem Format. Wir haben ein Ende eines Zeitraumes wie ein Vertragsende zum 31.01.2020, dann endet der Vertrag um 24:00 Uhr. Diese Uhrzeit gibt es in Wirklichkeit nicht, es ist 00:00 Uhr des nächsten Tages. Und so wird ein solches Datum in diesem Datumsformat auch gespeichert. Hier also der 01.02.2020 00:00 Uhr. Logisch oder?

Damit man später mit einem Datum arbeiten kann ist der Wert < 1000 kein Datum, sondern höchstens ein Rechenwert. Auf der anderen Seite ist ein offenes Datum (gültig-für-immer) der Wert 4999365 (31.12.4999). Dieses wird so gewählt, da größere Daten vonden meisten Datumsprüfungen abgewiesen werden. Es ist damit in dem System der maximale Wert.

Dieses Datumsformat werde ich in meinen Beispielen verwenden und natürlich bauen wir auch die entsprechenden Funktionalitäten dazu. Ich drücke dieses so aus, da ich nicht immer genau nach den Schulungsmethoden vorgehe.

Format für die Zeit

Wir haben bei der Zeit die Stunden, Minuten, Sekunden, Milli- oder Microsekunden. Da die Milli- oder Microsekunden nach dem Dezimalsystem funktionieren und umbrechen machen diese uns die wenigsten Herausforderungen. Bei den anderen Einheiten ist dieses schon wirklich nicht ganz einfach. Es ist einfach so:
  • 1 Tag hat 24 Stunden
  • 1 Stunde hat 60 Minuten
  • 1 Minute hat 60 Sekunden
  • 1 Sekunde hat 1000 Millisekunden
So gesehen wird nun ziemlich schnell klar, dass wir diese Werte zu einem einheitlichen Wert machen müssen, damit wir damit rechnen können. Dieses sollte dann natürlich alleine als Zeit funktionieren, aber auch in Zusammenhang mit einem Datum. Die Zeit muss so sein, dass diese in Einheit mit dem Datum einen Timestamp bilden kann. Genauso muss ich einfach mal 5 Stunden 42 Minuten oder auch 4,5 Stunden oder 32 Minuten addieren oder subtrahieren können. Auch Differenzen zwischen zwei Zeiten sollten möglich sein.

Es ist bei genauer Betrachtung logisch eine ganze einfach Lösung. Die ganze Zahl sind (Jahr)Tage und war wenn der Wert hinter einem Komma nicht vorhanden (= 0) ist, dann ist es ja 00:00 Uhr. Dann machen wir es einfach so, dass der Wert hinter dem Komma den Zeitanteil eines Tages (24 Stunden) in dezimaler Form darstellt. Die Genauigkeit hängt dann einfach von den Nachkommastellen ab.

Also 0,25 entspricht 6 Stunden. Damit stellt der Wert 2020032,25 den 01.02.2020 06:00 Uhr dar. 25 % von 24 Stunden sind 6 Stunden.

Schauen wir es uns ein wenig genauer an:

  • 1 Stunde entspricht {1 / 24 = 0,0416666667}  // z.B.  6 Stunden entsprechen {1 /24 * 6 = 0,25}
  • 1 Minute entspricht {1 / 24 / 60 = 0,000694444} // z.B. 30 Minuten entsprechen {1 / 24 / 60 * 30 = 0,0208333333} also genau der Hälfte einer Stunde.
  • 1 Sekunde entspricht {1 / 24 / 60 / 60 = 0,000011574} // z.B 90 Sekunden entsprechen {1 / 24 / 60 / 60 * 90 = 0,0010416667}
  • 1 MilliSekunde entspricht {1 / 24 / 60 / 60 / 1000 = 0,000000011574} // wie weit dieser Wert benötigt wird ist fraglich. Hinter den Sekunden können wir, da der Rest dezimal ist auch mit 10tel, 100tel der 1000tel Sekunden rechnen, bzw. Speichern.
Ich habe diese Formeln so geschreiben, damit man nachvollziehen kann wir sich der Wert nach dem Komma zusammensetzt. Diese Formeln können natürlich auch verkürzt verwendet werden.

  • 1 Stunde {1 / 24}
  • 1 Minute {1 / 1440}   //  (24 * 60 = 1440)
  • 1 Sekunde {1 / 86400} // (24 * 60 * 60 = 86400)
  • 1/10 Sekunde {1 / 864000} // (24 * 60 * 60 * 10 = 864000)
Rechnerisch in der Formel ist darauf zu achten, dass man einfach die Einheiten durch den Divisor für die Einheit teilt.  Also wenn man den Wert für 6 Stunden haben möchte, dann teilen wir einfach 6 / 24 = 0,25; kommen nun noch 30 Minuten dazu, dann rechnen wir 30 / 1440 = 0,0208333333; der gesamte Wert für 06:30 Uhr ist dann  0,25 + 0,0208333333 = 02708333333. Bis dahin sind dann so rund 27,08 % des Tages vergangen.

Mit diesen Zeitwerten kann man dann auch addieren und subtrahieren. Es muss lediglich beim Datum der Jahresumbruch stattfinden. Zum Beispiel habe ich 5 Stunden (5 / 24 = 0,2083333333) und addiere 60 Minuten (60 / 1440 = 0,0416666667) dazu bekomme ich den Wert von 0,25 folglich meine 6 Stunden.

Format für DateTime

Wenn wir uns nun die Formate für das Datum und die Zeit betrachten, dann können wir mit einem Wert den DateTime darstellen, mit diesem rechnen und dabei noch Datum und die Zeit getrennt verwenden.

Damit wird es dann möglich, ein Gültig-ab in einem Objekt auf den Tag zu beziehen und in einem anderen Objekt auf den Tag/Zeit. Beide können dann ohne sich die Finger zu brechen gemischt zu einem Zeitpunkt (Stichtag/-zeit) gelesen und verarbeitet werden.

Ein weiterer Vorteil liegt darin, dass dieses darstellungsunabhängige Format nach den erforderlichen Vorschriften dargestellt werden kann. Zum Beispiel in einer deutschen Oberfläche und gleichzeitg in einer amerikanischen Oberfläche.

Die dazu erforderliche Umsetzung ist unter der Dokumentation zu pdvm_datetime.py zu finden.
Share by: