JavaScript/Anwendung und Praxis/Zeitberechnung

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Zeitberechnungen stellen sowohl für den Menschen als auch für den Computer ein Problem dar. Die Ursache liegt darin, dass Zeitangaben von dem uns gewohnten dezimalen Zahlensystem abweichen. Ein Tag besteht aus 24 Stunden, eine Stunde besteht aus 60 Minuten und eine Minute wiederum aus 60 Sekunden. Diese Darstellungsform der Zeit macht es uns gleichzeitig sehr schwer, größere Zahlenangaben wie z.B. 7835 Sekunden gefühlsmäßig zu erfassen und richtig einzuordnen.

Inhaltsverzeichnis


Um mit Zeiträumen mathematisch zu rechnen, ist es sehr praktisch, einfach in Sekunden zu rechnen. Andererseits ist es unabdingbar, die Ergebnisse wieder in das gewohnte Format hh:mm:ss zurückzuwandeln, damit der Benutzer die Information schon auf den ersten Blick richtig einordnen kann.

Dieser Artikel ist die umfassende Neubearbeitung eines Selfhtml-aktuell-Artikels von Antje Hofmann aus dem Jahre 2002 mit dem Thema Zeitberechnung.

[Bearbeiten] Mathematische Grundlagen

Aus einer Tage-Stunden-Minuten-Sekunden-Angabe wie z.B. 2 Tage 04:12:16 die Sekunden auszurechnen ist simpel:

Sekundenzahl = Sekunden + 60 * Minuten + 60 * 60 * Stunden + 60 * 60 * 24 * Tage 
Sekundenzahl = 16 sec   + 60 * 12 min  + 60 * 60 * 4 h     + 60 * 60 * 24 * 2 d  = 187936 sec

Wie aber erhält man aus 187.936 Sekunden wieder die eindeutig verständlichere Angabe? Die Marschrichtung ist dabei natürlich klar: Beim Weg hin zur Sekundenzahl wurde multipliziert, also wird auf dem Weg zurück dividiert.

Zum Lösen des Problems gehen Sie am besten schrittweise vor. Beginnend von der kleinsten Einheit an, ermitteln Sie die Minuten, Stunden und Tage aus der vorhandenen Sekundenzahl.

Eine Minute dauert 60 Sekunden. Da liegt es nahe, die Anzahl der Sekunden durch 60 zu teilen.

Minutenzahl = Sekundenzahl / 60
Minutenzahl = 187936 sec / 60 = 3132,26666666666666666666666666667 min

Die Zahl vor dem Komma entspricht der Minutenzahl. Sie ist einfach zu gewinnen, indem man den Nachkommateil einfach abschneidet. Im Beispiel steht für das Abschneiden der Nachkommastellen jeweils der Ausdruck INT().

Für eine genaue Zeitangabe ist das jedoch nicht ausreichend. Auch die Nachkommastellen, welche die Restsekunden, darstellen müssen verarbeitet werden. Es liegt nahe, die Nachkommastellen mit 60 zu multiplizieren, um die Zahl der Sekunden zu ermitteln.

Sekunden = 0,26666666666666666666666666667 * 60
Sekunden = 16,0000000000000000000000000002 sec

Sie sind überrascht? Mit dieser doch scheinbar so einfachen Rechenoperation erhalten Sie kein richtiges Ergebnis. Exakt 16 Sekunden gingen in die Berechnung ein. Beim Rückwärtsrechnen erhielten Sie jedoch eine größere Zahl. Rechnet der Computer falsch?

Eigentlich nicht. Die Ursache liegt darin, dass das Ergebnis der Berechnung ein unendlicher Dezimalbruch ist. Mit solchen Zahlen kann ein Computer jedoch nicht rechnen. Deshalb werden die Ergebnisse gerundet. Dieser Rundungsfehler führt zur oben sichtbaren Abweichung.

Ist es überhaupt erforderlich, mit Nachkommastellen zu arbeiten? Die allermeisten Programmiersprachen kennen einen Operator names "MODULO", wahlweise abgekürzt als "x MOD y" oder "x % y". Das Ergebnis dieses Operators steht für den Rest bei der "Ganzzahl-Division mit Rest". Wer sich an seine Grundschulzeit erinnert, wird noch wissen, wie man Zahlen dividiert, ohne Nachkommastellen zu benutzen. Das Ergebnis des Modulo-Operators ergibt sich aus folgender stark vereinfachten Rechnung:

x MOD y = x - INT(x/y)* y
Beispiel:
23 MOD 5 = 23 - INT(23/5)*5 = 23 - 4 * 5 = 23 - 20 = 3

Der Modulo-Operator ist ideal zur Lösung des Problems. Ohne Rundungsfehler erhalten Sie den ganzzahligen Rest der Division einer Zahl und in diesem Beispiel die Anzahl der Restsekunden. Zusammenfassend erhalten Sie:

Minuten  = INT(Sekundenzahl/60) = INT(187936/60) = 3132 min = Minutenzahl
Sekunden = Sekundenzahl MOD 60  = 187936 MOD 60  = 16 sec

Die Anzahl der Minuten ist für den Benutzer nicht sehr viel aufschlussreicher als die Sekundenzahl, da sie immer noch zu groß ist. Jetzt bietet es sich an, zu ermitteln, wieviele Stunden und Restminuten in der ermittelten Minutenzahl enthalten sind. Das Vorgehen ist genau das gleiche: Dividieren Sie die ermittelte Anzahl der Minuten durch die Anzahl der Minuten einer Stunde und schneiden Sie die Nachkommastellen ab. Ermitteln Sie die verbleibenden Restminuten mit Hilfe des Modulu-Operators.

Stunden = INT(Minutenzahl/60) = INT(3132/60)= 52 h   = Stundenzahl
Minuten = Minutenzahl MOD 60  = 3132 MOD 60 = 12 min

Es ist nicht erforderlich, die Minutenzahl wie im Beispiel in einer separaten Variable zu speichern. Stattdessen können Sie einfach die Rechenoperation angeben, welche zur Minutenzahl führte.

Minuten = Sekundenzahl/60 MOD 60  = 187936/60 MOD 60 = 12 min
Stunden = INT(Sekundenzahl/60/60) = INT(187936/60/60)= 52 h   = Stundenzahl

Diese wenigen Umformungsschritte bewirken, dass Sie die Sekundenzahl in der Form hh:mm:ss ausgeben können. Im Beispiel würde ein Benutzer als Ausgabe 52:12:16 erhalten. Auch diese Zeitangabe ist noch nicht ideal und würde vom Benutzer einen weiteren Verarbeitungsprozess erfordern. Er müsste überlegen, wieviele Tage 52h sind. Diese Arbeit können Sie dem Benutzer abnehmen, indem Sie die ermittelte Stundenzahl in Tage umwandeln. Genau wie bei der Umwandlung in Minuten und Stunden verwenden Sie wieder die ganzzahlige Division und den Modulo-Operator. Gerechnet wird jetzt natürlich nicht mehr mit 60 Minuten pro Stunde, sondern mit 24 Stunden pro Tag.

Tage    = INT(Stundenzahl/24) = INT(52/24)= 2 Tage
Stunden = Stundenzahl MOD 24  = 52 MOD 24 = 4 h

Auch hier ist es nicht notwendig, mit dem Zwischenergebnis weiterzurechnen. Sie können stattdessen wiederum für die Stundenzahl die Rechnenoperation angeben, die zur Stundenzahl führte.

Tage    = INT(Sekundenzahl/60/60/24) = INT(187936/60/60/24)= 2 Tage 
Stunden = (Sekundenzahl/60/60) MOD 24  = (187936/60/60) MOD 24 = 4 h

Diese letzte Umformung führte zu dem leicht verständlichen Ergebnis von 2 Tagen 4 Stunden 12 Minuten und 16 Sekunden. Diesen Wert kann jeder Anwender sofort interpretieren.

Sollten es Ihre Ergebnisse erfordern, so können Sie dieses Verfahren beliebig erweitern, um zum Beispiel die Anzahl der Wochen oder Jahre zu berechnen. Da es vollkommen unabhängig von vorhandenen Datumsfunktionen arbeitet, ist es nicht nur auf Zeitumwandlungen begrenzt. Sie können es auf jeden ähnlich gelagerten Anwendungsfall anwenden.

Fassen wir zusammen: Die einzelnen Teilwerte für Tage, Stunden, Minuten und Sekunden lassen sich immer mit demselben Schema von Division und Modulo berechnen. Die bei der Division anfallenden Nachkommastellen fallen grundsätzlich unter den Tisch, es kann also auch zu keinen Rundungsfehlern kommen.

Die Formeln noch einmal in der Übersicht:

Sekunden = Sekundenzahl MOD 60
Minuten  = (Sekundenzahl/60) MOD 60
Stunden  = (Sekundenzahl/60/60) MOD 24
Tage     = INT(Sekundenzahl/60/60/24)

[Bearbeiten] Anwendungsbeispiele

Im Folgenden sehen Sie, wie Sie Zeitberechnungen in JavaScript praktisch umsetzen können. Da es nur wenig native Berechnungsfunktionen in JavaScript gibt, müssen Sie teilweise eigene, hier vorgestellte Helferfunktionen verwenden

[Bearbeiten] Zeitspannen addieren und abziehen

Das Verändern von Datums- und Zeitangaben durch das Addieren oder Substrahieren eines Intervalls ist eine der leichteren Übungen.

Bei Settern wie setDate() sollen Sie laut Spec nur sinnvolle Werte von 1-31 eingeben. Es mag auf den ersten Blick wie ein Bug aussehen, dass man auch höhere Werte verarbeiten kann. Dies ist bei der Berechnung von in der Zukunft liegenden Daten jedoch sehr nützlich, weil man sich bei Berechnungen nicht um einen eventuellen Monatswechsel kümmern muss. Beim Ändern des Datums mit höheren Werten wird das Datum automatisch richtig ermittelt.

Beispiel
var gesetzt  = new Date(2017, 1, 11);      // heutiges Datum ist der 11.02.2017
gesetzt.setDate(jetzt.getDate() + 50);
console.log(gesetzt.toLocaleDateString()); //angezeigt wird der 02.04.2017
Im Beispiel wird das heutige Datum mit getDate() ausgelesen. Der so erhaltene Tageswert wird mit 50 addiert und dann mit setDate() neu gesetzt.
JaavaScript berechnet das Datum intern um und berücksichtigt dabei auch Schalttage.

In diesem Live-Beispiel können Sie ausprobieren, wie die eingegebenen Werte automatisch zu einem neuen Datum führen:

Beispiel ansehen …
function changeDate() {
  var gesetzt = new Date(),
      tage = parseInt(this.value);
 
  gesetzt.setDate(jetzt.getDate() + tage);
  resultierend.innerHTML = gesetzt.toLocaleDateString('de-DE');
 
  if (tage < 0) {
    label_resultierend.innerHTML = "vor " + (-1)*tage + " Tagen: ";
    if (tage == -1) {
      label_resultierend.innerHTML = "gestern: ";
    }
  }
  else if (tage > 0) {
    label_resultierend.innerHTML = "in " + tage + " Tagen: ";
    if (tage == 1) {
      label_resultierend.innerHTML = "morgen: ";
    }
  }
  else {
    label_resultierend.innerHTML = "heute: "
  }
}
Das Beispiel erzeugt ein neues Datumsobjekt jetzt mit dem aktuellen Datum, zu dessen mit getDate() ermitteltem Tageswert der Wert des Sliders addiert wird. Diese Summe wird mit setDate() neu gesetzt und das neu gesetzte Datum und zum Vergleich das aktuelle Datum werden mit toLocaleDateString('de-DE'); formatiert und ausgegeben.


Analog können Sie auch mit setFullYear(), setMonth(), setHours() und setMinutes() verfahren.

[Bearbeiten] Differenz zwischen zwei Zeitangaben

Schwieriger ist es eine Differenz zwischen zwei gegebenen Zeitangaben zu ermitteln, da date-Objekte nicht einfach miteinander addiert werden können.

Über die Methode getTime() können Sie aber die Anzahl der Millisekunden ausgeben und diese voneinander subtrahieren:

Beispiel
var startDate = new Date(),
    endDate   = new Date(),
    differenz = (endDate.getTime() - startDate.getTime());
Das Beispiel enthält zwei Datums-Objekte, die in Zeile 3 jeweils mit der getTime-Methode in Millisekunden umgewandelt und voneinander subtrahiert werden.
Der so ermittelte Wert ist in Millisekunden und muss nun noch passend formatiert werden.

[Bearbeiten] Formatierung der Ausgabe

In den obigen Berechnungen wurde keine Zeit, sondern nur die Anzahl Millisekunden ermittelt. Sie können dies aber in eine lesbare Zeitangabe formatieren:

{{ToDo|Zwischenstand, muss fertiggestelllt werden.--Matthias Scharwies (Diskussion) 05:16, 13. Feb. 2017 (CET)}

Beispiel
function fuehrendeNull(wert) {
  if (wert < 10) return "0" + parseInt(wert);
  else return parseInt(wert);
}
 
function Sekundenumwandeln(Sekundenzahl) {
  Sekundenzahl = Math.abs(Sekundenzahl)
  return parseInt(Sekundenzahl/60/60/24)+ " Tage " + fuehrendeNull((Sekundenzahl/60/60)%24) + ":" +
                 fuehrendeNull((Sekundenzahl/60)%60) + ":" + fuehrendeNull(Sekundenzahl%60);
}
 
console.log(Sekundenumwandeln(187936));


Da JavaScript keine speziellen Formatierungsfunktionen für Ausgaben kennt, wurde die Formatierung in die Funktion Sekundenumwandeln() ausgelagert. Der Rückgabewert der Funktion ist ein formatierter String, der dann ausgegeben wird. Der ganzzahlige Anteil einer Zahl wird mit der Methode parseInt() ermittelt. Die Funktion fuehrendeNull() erledigt 2 Aufgaben. Sie fügt gegebenenfalls eine führende Null an und gibt den ganzzahligen Wert des übergebenen Parameters zurück.


[Bearbeiten] Der Tag hat 24 Stunden - oder nicht?

[Bearbeiten] Anzahl der Tage im Monat

[Bearbeiten] Der erste Dienstag im November

[Bearbeiten] noch x Tage bis Weihnachten

[Bearbeiten] Weblinks

Meine Werkzeuge
Namensräume

Varianten
Aktionen
Übersicht
Index
Mitmachen
Werkzeuge
Spenden
SELFHTML