JavaScript: Zeit und Datum
► JavaScript-Referenz: Date.now() Date.UTC() Date.parse() getTime() setTime() getTimezoneOffset()
JavaScript bietet eine Reihe von Merkmalen zur Feststellung, Berechnung und Ausgabe von Zeitinformationen. Referenzpunkt für die Zeitmessung ist die sogenannte Unix-Epoche am 1. Januar 1970 um 0:00 Uhr der koordinierten Weltzeit (UTC).
Mit new Date() wird ein neues Date-Objekt erzeugt, das für jede Art von Zeitberechnung benötigt wird. Es erwartet als Argument einen Zeitstempel. Wird dieses Argument ausgelassen, wird der Zeitstempel des Aufrufzeitpunktes angenommen, der aber auch explizit mit Date.now() angegeben werden kann.
Mit der Methode Date.UTC() kann auch der Zeitstempel für einen beliebigen anderen Zeitpunkt übergeben werden. Diese Methode erwartet die numerischen Werte für Jahr, Monat, Tag, Stunde, Minute, Sekunde und Millisekunde in dieser Reihenfolge als Argumente. Die Argumente können auch von hinten beginnend weggelassen werden und werden damit auf 0 gesetzt. Die Zählung der Monate beginnt mit 0 für Januar.
Mit der Methode Date.parse() kann eine Zeichenkette, die eine Zeitinformation enthält, analysiert werden und so aus ihr ein Zeitstempel gebildet werden.
Mit der Methode getTime() kann der Zeitstempel eines Date-Objektes ermittelt werden. Dieser Zeitstempel bezieht sich auf UTC und ist damit unabhängig von der jeweiligen Zeitzone des Benutzers.
Mit der Methode setTime() kann der Zeitstempel eines neuen Zeitpunktes übergeben werden.
Um die einzelnen Komponenten eines Date-Objektes auszulesen, stehen entsprechende Methoden zur Verfügung:
getFullYear() – Jahr
getMonth() – Monat (beginnend mit 0 für Januar)
getDate() – Tag
getDay() – Wochentag (beginnend mit 0 für Sonntag)
getHours() – Stunde
getMinutes() – Minute
getSeconds() – Sekunde
getMilliseconds() – Millisekunde
Diese Methoden geben die Komponenten in der Ortszeit des Benutzers entsprechend seiner Zeitzone zurück. Für die Ausgabe in UTC können die Methoden getUTCFullYear() etc. verwendet werden.
Die Zeitdifferenz zwischen der Ortszeit und UTC in Minuten kann mit der Methode getTimezoneOffset() ermittelt werden. Für Daten nach Übernahme einer Zeitzonenregelung wird die Differenz bezüglich der Zonenzeit angegeben, ansonsten zur Sonnenzeit. Zonenzeit und Sonnenzeit werden anhand der Zeiteinstellungen im Benutzersystem ermittelt.
Aktueller Ort für die Zeitbestimmung unter Linux: readlink -f /etc/localtime
jetzt = new Date(Date.now());
timestamp = jetzt.getTime();
console.log(timestamp); // aktueller Zeitstempel (= Millisekunden seit Unix-Epoche)
einTermin = new Date(Date.UTC(1970, 0, 1)); // Unix-Epoche: 1. Januar 1970, 00:00:00 Uhr UTC
console.log(einTermin.getTime()); // 0
einTermin = new Date(Date.parse("2015-05-23T18:49:32Z"));
console.log("UTCString:", einTermin.toUTCString()); // UTCString: Sat, 23 May 2015 18:49:32 GMT
einTermin.setTime(957191400000); // 1. Mai 2000, 14:30 Uhr UTC
console.log("Jahr:", einTermin.getFullYear(), einTermin.getUTCFullYear());
console.log("Monat:", einTermin.getMonth(), einTermin.getUTCMonth());
console.log("Tag:", einTermin.getDate(), einTermin.getUTCDate());
console.log("Wochentag:", einTermin.getDay(), einTermin.getUTCDay());
console.log("Stunde:", einTermin.getHours(), einTermin.getUTCHours());
console.log("Minute:", einTermin.getMinutes(), einTermin.getUTCMinutes());
console.log("Sekunde:", einTermin.getSeconds(), einTermin.getUTCSeconds());
console.log("Millisekunde:", einTermin.getMilliseconds(), einTermin.getUTCMilliseconds());
console.log("Differenz zu UTC:", einTermin.getTimezoneOffset(), "min");
► JavaScript-Referenz: toString() toDateString() toTimeString()
► JavaScript-Referenz: toLocaleString() toLocaleDateString() toLocaleTimeString()
► JavaScript-Referenz: toUTCString() toISOString() toJSON()
Date-Objekte können mit verschiedenen Methoden als vorformatierter String ausgegeben werden.
console.log("String:", einTermin.toString()); // Mon May 01 2000 16:30:00 GMT+0200 (Mitteleuropäische Sommerzeit)
console.log("DateString:", einTermin.toDateString()); // Mon May 01 2000
console.log("TimeString:", einTermin.toTimeString()); // 16:30:00 GMT+0200 (Mitteleuropäische Sommerzeit)
console.log("LocaleString:", einTermin.toLocaleString()); // 1.5.2000, 16:30:00
console.log("LocaleDateString:", einTermin.toLocaleDateString()); // 1.5.2000
console.log("LocaleTimeString:", einTermin.toLocaleTimeString()); // 16:30:00
console.log("UTCString:", einTermin.toUTCString()); // Mon, 01 May 2000 14:30:00 GMT
console.log("ISOString:", einTermin.toISOString()); // 2000-05-01T14:30:00.000Z
console.log("JSON:", einTermin.toJSON()); // 2000-05-01T14:30:00.000Z
console.log("Zeitzone:", einTermin.toString().match(/\(([A-Za-z\s].*)\)/)[0]); // (Mitteleuropäische Sommerzeit)
console.log("Zeitzone:", einTermin.toString().match(/\(([A-Za-z\s].*)\)/)[1]); // Mitteleuropäische Sommerzeit
► JavaScript-Referenz: setFullYear() setHours()
Um einzelne Komponenten eines Date-Objektes zu ändern, stehen folgende Methoden zur Verfügung:
setFullYear(yyyy, mm, dd) – Jahr
setMonth(mm, dd) – Monat (beginnend mit 0 für Januar)
setDate(dd) – Tag
setHours(hh, nn, ss, zzz) – Stunde
setMinutes(nn, ss, zzz) – Minute
setSeconds(ss, zzz) – Sekunde
setMilliseconds(zzz) – Millisekunde
Diese Methoden beziehen sich auf die Ortszeit des Benutzers. Für den Bezug zur UTC können die Methoden setUTCFullYear() etc. verwendet werden.
einTermin = new Date(Date.parse("2015-05-23T18:49:32Z"));
console.log("UTCString:", einTermin.toUTCString()); // UTCString: Sat, 23 May 2015 18:49:32 GMT
einTermin.setUTCFullYear(2017);
console.log("UTCString:", einTermin.toUTCString()); // UTCString: Tue, 23 May 2017 18:49:32 GMT
einTermin.setUTCHours(10);
console.log("UTCString:", einTermin.toUTCString()); // UTCString: Tue, 23 May 2017 10:49:32 GMT
Gregorianisches Datum in julianisches Datum umrechnen
Die Zeit- und Datumsfunktionen von JavaScript beziehen sich grundsätzlich auf den gegenwärtig verwendeten gregorianischen Kalender, der allerdings erst im 16. Jahrhundert eingeführt wurde, womit der bis dahin verwendete julianische Kalender abgelöst wurde. Grund für diese Reform war eine ungenaue Anwendung von Schaltjahren, die zu einer immer größer werdenden Differenz zwischen natürlichem Sonnenjahr und Kalenderjahr geführt hatte.
Berechnet man mit JavaScript nun ein Datum vor der Einführung des gregorianischen Kalenders, so entspricht das Ergebnis nicht dem damals gebräuchlichen Kalender. Für eine korrekte Umrechnung existiert in JavaScript kein Algorithmus, weshalb man sich diesen selbst bauen muss.
Dabei müssen folgende Voraussetzungen berücksichtigt werden:
- Die Einführung des gregorianischen Kalenders erfolgte in verschiedenen Ländern zu verschiedenen Zeitpunkten.
- Es existierte noch keine Zonenzeit, die ebenfalls erst später und sehr unterschiedlich eingeführt wurde (in Deutschland am 1. April 1893).
- Mit der Umstellungen wurden 10 Tage übersprungen. Die Zählung der Wochentage wurde dagegen beibehalten.
- Im julianischen Kalender war jedes vierte Jahr ein Schaltjahr. Im gregorianischen Kalender sind die Jahre, die ganzzahlig durch einhundert teilbar sind, dagegen keine (also 1800, 1900, 2100 etc.), es sei denn, sie sind ganzzahlig durch vierhundert teilbar (also 2000, 2400 etc.).
- Die lokale Zonenzeit wird nach der Einstellung des Benutzersystems bestimmt.
einTermin = new Date(Date.parse("1893-03-31T23:06:32Z")); // == 31.3.1893 00:06:32 MEZ
console.log("Offset:", einTermin.getTimezoneOffset()); // -60
einTermin = new Date(Date.parse("1893-03-31T23:06:31Z")); // == 31.3.1893 23:59:59 Lokale Zeit
console.log("Offset:", einTermin.getTimezoneOffset()); // -53
Für unsere Umrechnung ist der Termin von Bedeutung, zu dem am relevanten Ort der gregorianische Kalender eingeführt wurde. Entweder dieser Termin wird explizit an die Funktion übergeben oder es wird ein Standardwert verwendet. Da der gregorianische Kalender am 15. Oktober 1582 um 0 Uhr vom katholischen Papst eingeführt wurde, kann man als Standardwert also diesen Termin bezogen auf die Sonnenzeit im Vatikan verwenden. Der Vatikan liegt auf 12,45° östlicher Länge, die Zeitdifferenz zu UTC beträgt dort also rund 49 Minuten.
einTermin = new Date(Date.parse("1582-10-14T23:11:00Z")); // == 15.10.1582 0:00 Sonnenzeit Vatikan
console.log("Offset:", einTermin.getTimezoneOffset()); // -49
Die Funktion getJulGreg(timeStamp, anytime, offset, gregStart) ermittelt für einen übergebenen Zeitpunkt das Kalendersystem. Wenn es sich um den julianischen Kalender handelt, konvertiert sie das Datum entsprechend. Es werden folgende Parameter verarbeitet:
- timeStamp – der Zeitstempel des zu prüfenden Date-Objekts
- anytime – bei true wird jede Zeitangabe in den julianischen Kalender umgerechnet, ansonsten nur, wenn der Zeitpunkt vor der Einführung des gregorianischen Kalenders liegt.
- offset – die Zeitdifferenz zu UTC in Minuten für andere Ortszeiten; wird dieser Wert nicht angegeben, wird UTC angenommen
- gregStart – ein Date-Objekt mit dem Zeitpunkt der Einführung des gregorianischen Kalenders für den gewünschten Ort; wird dieser Wert nicht angegeben, wird der 15. Oktober 1582, 0:00 Uhr im Vatikan angenommen
Die Funktion gibt ein Array mit folgenden Elementen zurück:
- [0] – das Jahr
- [1] – der Monat
- [2] – der Tag
- [3] – die Stunde
- [4] – die Minute
- [5] – die Sekunde
- [6] – der Wochentag
- [7] – der Wert von offset
- [8] – 1 für den julianischen oder 0 für den gregorianischen Kalender
Die Ausgabe dieser Elemente in einen formatierten String wird in die Funktion dateFormat() ausgelagert.
function getJulGreg(timeStamp, anytime = false, offset = 0, gregStart = new Date(Date.parse("1582-10-14T23:11:00Z"))) {
/*
this function calculates time values according to julian or gregorian calendar.
parameters are:
a timestamp for input time,
a flag to indicate whether any date object should be converted to julian calendar,
offset to utc for local times,
a date object for beginning of gregorian calendar at local place or at vatican if omitted
output is [year, month, day, hours, minutes, seconds, weekday, offset to utc, flag (julian=1; gregorian=0)]
version 1.9 (6 february 2020) by holger löwenherz, www.decocode.de
*/
out = new Array(9);
timeStamp -= offset * 6e4;
dateObj = new Date(timeStamp);
if (anytime || timeStamp < gregStart.getTime() - offset * 6e4) { // -------------------------- julian calendar
jsY = 1580; // leap year before reform
julPStart = Date.UTC(jsY, 0, 11); // start of 4 years period
msP = 1262304e5; // milliseconds per 4 years period
// move julPStart just before timeStamp
f = Math.floor((timeStamp - julPStart) / msP);
jsY += f * 4;
julPStart += f * msP;
dP = (timeStamp - julPStart) / 864e5; // day with fraction in 4 years period
yP = (dP >= 366) + (dP >= 731) + (dP >= 1096); // year count in 4 years period
out[0] = jsY + yP; // get year
dayY = Math.floor(dP - 365 * yP - (out[0] != jsY)) + 1; // day in year
daysM = [31, 28 + (out[0] == jsY), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
i = 0;
do { // find month
dayY -= daysM[i];
i++;
} while (dayY > 0); // month not found
out[1] = i - 1; // get month
out[2] = dayY + daysM[i - 1]; // get day
out[8] = 1; // flag for julian calendar
} else { // -------------------------- gregorian calendar
out[0] = dateObj.getUTCFullYear();
out[1] = dateObj.getUTCMonth();
out[2] = dateObj.getUTCDate();
out[8] = 0;
}
out[3] = dateObj.getUTCHours();
out[4] = dateObj.getUTCMinutes();
out[5] = dateObj.getUTCSeconds();
out[6] = dateObj.getUTCDay();
out[7] = offset;
return out;
}
function dateFormat(data) {
// creates a formatted time string from getJulGreg() data.
plus = (-data[7] >= 0 ? "+" : "");
return ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"][data[6]] + ", " +
data[2].toString().padStart(2, "0") + ". " +
["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"][data[1]] + " " +
Math.abs((data[0] - (data[0] < 1))) + "<sup>" + ["greg", "jul"][data[8]] + "</sup> " + // there is no year 0
["v.Chr. ", "n.Chr. "][+(data[0] > 0)] +
data[3].toString().padStart(2, "0") + ":" +
data[4].toString().padStart(2, "0") + ":" +
data[5].toString().padStart(2, "0") + " h (UTC " +
plus + -data[7] + " min)";
}
temptime = new Date();
skytime = new Date(temptime);
shiftTime(0);
before = new Date(Date.parse("1582-10-14T23:10:59Z")); // last second of julian calendar in vatican
after = new Date(Date.parse("1582-10-14T23:11:00Z")); // first second of gregorian calendar in vatican
// times for greenwich
console.log(dateFormat(getJulGreg(before.getTime(), false))); // Do, 04. Okt 1582<sup>jul</sup> 23:10:59 h (UTC +0 min)
console.log(dateFormat(getJulGreg(after.getTime(), false))); // Do, 14. Okt 1582<sup>greg</sup> 23:11:00 h (UTC +0 min)
// times for vatican
console.log(dateFormat(getJulGreg(before.getTime(), false, -49))); // Do, 04. Okt 1582<sup>jul</sup> 23:59:59 h (UTC +49 min)
console.log(dateFormat(getJulGreg(after.getTime(), false, -49))); // Fr, 15. Okt 1582<sup>greg</sup> 00:00:00 h (UTC +49 min)
// times for berlin (local time)
off1 = before.getTimezoneOffset();
off2 = after.getTimezoneOffset();
console.log(dateFormat(getJulGreg(before.getTime(), false, off1))); // Fr, 05. Okt 1582<sup>jul</sup> 00:03:59 h (UTC +53 min)
console.log(dateFormat(getJulGreg(after.getTime(), false, off2))); // Fr, 15. Okt 1582<sup>greg</sup> 00:04:00 h (UTC +53 min)
Die Angaben für Stunde, Minute, Sekunde und Wochentag sind vom Kalendersystem unabhängig und werden daher nicht besonders ermittelt.
Zunächst wird der Zeitstempel timeStamp an die gewünschte Ortszeit angepasst, indem von ihm das Produkt aus offset und der Anzahl der Millisekunden pro Minute 6e4 abgezogen wird.
Dann wird geprüft, ob sich das betreffende Datum im Geltungsbereich des julianischen Kalenders befindet (bzw. anytime == true). Sollte das der Fall sein, wird in der Variable jsY das Schaltjahr vor dem frühsten Termin des Wechsels zum gregorianischen Kalender 1580 gespeichert und mit diesem Wert der entsprechende Zeitstempel julPStart für den 1. Januar dieses Jahres, 0:00 Uhr erzeugt.
Im nächsten Schritt wird das Schaltjahr jsY bzw. julPStart unmittelbar vor das betreffenden Datum verschoben.
Berechnung von Tag, Monat und Jahr
- Der Tag out[2] wird ermittelt, indem in einer Schleife das Array daysM mit den Tageszahlen jedes Monats durchlaufen wird. Von der zuvor ermittelten Variable dayY, die die auf das betreffende Jahr bezogene Tageszahl des Datums enthält, werden diese Tageszahlen der Reihe nach abgezogen. Fällt dieser Wert unter 0, ist der Monat out[1] gefunden. Addiert man die zuvor abgezogene Tageszahl wieder zu dayY, erhält man den Tag.
- Die auf das betreffende Jahr bezogene Tageszahl des Datums dayY erhält man, in dem man von der auf die Vierjahresperiode bezogenen Tageszahl dP die Tageszahl der vollen Jahre (365 * yP) vor dem betreffenden Datum seit Beginn der Vierjahresperiode abzieht, wobei ein Schalttag berücksichtigt wird, wenn das betreffende Jahr kein Schaltjahr ist (out[0] != jsY). Von diesem Betrag wird die Ganzzahl bestimmt und 1 addiert, da der 1. Januar bislang als Tag 0 geführt wurde.
- Die Jahreszahl out[0] erhält man, indem man zur Jahreszahl des Beginns der Vierjahresperiode jsY die Zeitdifferenz zwischen dem betreffenden Datum und dem Beginn der Vierjahresperiode in ganzen Jahren yP addiert.
- Die Zeitdifferenz zwischen dem betreffenden Datum und dem Beginn der Vierjahresperiode in ganzen Jahren yP erhält man, indem man prüft, in welches Jahr die Tageszahl dP fällt.
- Die auf die Vierjahresperiode bezogenen Tageszahl dP erhält man, indem man vom Zeitstempel des betreffenden Datums timeStamp den Zeitstempel des Beginns der Vierjahresperiode julPStart abzieht und diesen Wert durch die Anzahl der Millisekunden pro Tag (864e5) teilt.
Hier kann diese Funktion für die persönliche Ortszeit getestet werden. Über den Schieberegler kann die Zeit eingestellt werden. Dabei sind die jeweiligen Änderungen immer gleich lang, unabhängig von Sommerzeitregelungen oder der unterschiedlichen Länge von Schaltjahren und Monaten. Dadurch kann es zu scheinbaren Abweichungen kommen, die aber nachjustiert werden können. Eine weitere Abweichung im Sekundenbereich kann entstehen, wenn ein Zeitpunkt außerhalb der Geltung einer Zeitzonenregelung gewählt wurde. Dann wird wie erwähnt die Sonnenzeit des Ortes zugrunde gelegt, die von JavaScript sekundengenau aus der Systemzeit abgeleitet wird, während getTimezoneOffset() diese auf volle Minuten rundet.
Das Tool berechnet das julianische Datum auch für Zeitpunkte, an denen der julianische Kalender noch gar nicht eingeführt war (vor 45 v. Chr.).
Gregorianisch: | |
Julianisch: | |
Unix [ms]: |