Um in Javascript mit Daten und Zeiten zu arbeiten gibt es das Date Objekt.
Ein Aufruf des Konstruktors ohne Argumente liefert ein Objekt mit dem aktuellen Datum und der aktuellen Zeit zurück.
|
1 2 |
var now = new Date(); var now = Date.now(); //In neueren Browsern |
Ein spezifisches Datum lässt sich mit der Übergabe von Argumenten erstellen. Date kann Strings im Format RFC2822 verarbeiten. Neuere Browser unterstützen auch einen Teil des ISO 8601 Standards. Oder man übergibt die Anzahl Millisekunden seit Mitternacht 1.1.1970 UTC. Als dritte Möglichkeit übergibt man Jahr, Monat, Tag und optional Stunden, Minuten, Sekunden, Millisekunden.
|
1 2 3 4 |
new Date(1331121652499); //7. März 2012 13:00:52 GMT+1 new Date("2012-03-07T07:04:12"); //7. März 2012 08:04:12 GMT+1 new Date(2012, 2, 7); //7. März 2012 new Date(2012, 2, 7, 13, 0, 0, 0); //7. März 2012 13:00:00 |
Beim Monat muss darauf geachtet werden das dieser 0 basiert ist (0 = Januar, 11 = Dezember). Nicht vergessen sollte man new anzugeben. Ohne new erhält man anstatt einem Date einen String zurück, der das aktuelle Datum und Zeit beinhaltet.
|
1 |
Date() //"Sun Mar 11 2012 11:48:27 GMT+0100 (W. Europe Standard Time)" |
Das Date Objekt liefert Funktionen mit um Teile des Datums und der Zeit zu lesen und zu verändern. Zum Beispiel liest folgender Code das aktuelle Jahr.
|
1 2 |
var now = new Date(); var year = now.getFullYear(); //2012 |
Mit setFullYear(year) wird das Datum auf ein bestimmtes Jahr gesetzt.
|
1 2 |
var twoYearsAgo = new Date(); twoYearsAgo.setFullYear(2010); |
Eine Auflistung der Date Funktionen findet man auf dem Mozilla Developer Network.
Mit den get/set Funktionen lassen sich auch einfache Berechnungen durchführen. Folgender Code erstellt ein Date Objekt das 3 Tage in der Zukunft liegt.
|
1 2 |
var d = new Date(); d.setDate(d.getDate()+3); |
Differenzen lassen sich mit der Funktion getTime berechnen. Diese Funktion liefert die Anzahl Millisekunden seit dem 1.1.1970 zurück.
|
1 2 3 |
var d1 = new Date(2012, 0, 1); var d2 = new Date(2012, 11, 31); var diffInMillis = d2.getTime()-d1.getTime() |
Ein Schwachpunkt des nativen Date Objektes ist Parsen und Formatieren von Datum und Zeit. Date kennt zwar die parse Funktion aber der String muss entweder als RFC2822 oder ISO 8601 (Subset) übergeben werden. Auch beim Konvertieren in einen String kennt Date einige Funktionen (z.B. toISOString, toLocaleString). Aber wenn man sein eigenes Datumsformat ausgeben will muss dies programmiert werden.
Da Berechnungen und Parsen/Formatieren vom nativen Date Objekt nicht genügend unterstützt werden, gibt es einige Libraries die hier in die Lücke springen und die Behandlung von Datum und Zeit versuchen zu vereinfachen.
Wir schauen uns im folgenden die Libraries XDate, Moment.js und Sugar genauer an.
XDate
XDate ist komprimiert (gzip) 2.9 kB gross und hat keine Abhängigkeit zu anderen Libraries. Das zentrale Objekt in XDate ist XDate. Ein aktuelles Datum mit aktueller Zeit lässt sich, wie das Date Objekt, mit new erstellen.
|
1 |
var now = new XDate(); |
XDate unterstützt alle Konstruktor Aufrufe die vom Date bekannt sind. Zusätzlich kann ein Date Objekt als Argument dem Konstruktor übergeben werden.
|
1 2 |
var date = new Date(2010, 0, 1); var xdate = new XDate(date); |
Umgekehrt lässt sich mit toDate aus dem XDate das Date Objekt extrahieren.
|
1 |
var mydate = xdate().toDate(); |
XDate kennt die vom Date Objekt bekannten get/set Funktionen. Interessant sind die zusätzlichen Funktionen mit denen sich Berechnungen durchführen lassen. Folgendes Beispiel berechnet die Differenz in Tagen bis zu Weihnachen.
|
1 2 3 4 5 |
var now = new XDate() var xmas = new XDate(); xmas.setDate(25); xmas.setMonth(11); var diffInDays = now.diffDays(xmas); |
Für jede Einheit (Year, Month, Week, …) gibt es eine entsprechende diffEinheit Funktion (diffYears, diffMonths, diffWeeks)
Einheiten addieren und subtrahieren lassen sich mit der entsprechenden addEinheit Funktion
|
1 2 3 4 5 |
var now = new XDate() now.addDays(3); var now = new XDate() now.addDays(-3); |
Beim Parsen unterstützt XDate nur Strings im Format ISO8601 und IETF.
|
1 2 |
new XDate("2011-09-05"); new XDate("2011-09-05T12:30:00Z"); |
Beim Formattieren bietet XDate mit den Funktionen toString und toUTCString mehr Möglichkeiten als Date. Mann kann diesen Funktionen einen Formatstring mitgeben der das Outputformat beschreibt.
|
1 2 3 |
var s = new XDate(2012, 6, 3).toString("dd.MM.yyyy"); //03.07.2012 var s = new XDate(2012, 6, 3).toString("d. MMMM yyyy"); //3. July 2012 var s = new XDate(2012, 6, 3).toString("d. MMM yyyy"); |
Eine Beschreibung der unterstützten Tokens findet man hier: http://arshaw.com/xdate/#Formatting
Localization wird auch unterstützt. Allerdings müssen die benötigten Strings für Monatsname und Wochentagname selber angegeben werden. Hier ein Beispiel für Französisch: https://gist.github.com/1221376
Moment.js
Diese Library ist minified und komprimiert 3.3 kB gross und hat, wie XDate, keine Abhängigkeit zu anderen Libraries. Moment.js liefert verschiedene Sprachen mit die allerdings nicht im Core Javascript enthalten sind sondern bei Bedarf zusätzlich geladen werden müssen.
Das zentrale Objekt in Moment.js ist moment. Folgender Code erzeugt ein Objekt mit dem aktuellen Datum und Zeit.
|
1 |
var now = moment(); |
Der Funktion moment können auch ein bestehendes Date Objekt oder die Anzahl Millisekunden übergeben werden um damit ein bestimmtes Datum zu erzeugen.
|
1 2 |
var d = moment(new Date(2020, 3, 7)); var d = moment(1318781876406); |
Eine weitere Möglichkeit ist ein Array mit Parametern zu übergeben. Die Reihenfolge der Zahlen im Array entspricht dem Konstruktor Aufruf beim Date Objekt. Wenn Bestandteile wegelassen werden wird immer der kleinste Wert angenommen.
|
1 2 3 4 5 |
var d = moment([2012]); // 1 Januar 2012 var d = moment([2012, 2]); // 1 März 2012 var d = moment([2012, 6, 10]); // 10 Juli 2012 |
Mehr Möglichkeiten als Date und XDate bietet Moment.js beim Parsen von Strings. Hier kann ein Formatstring mitgegeben werden der angibt in welchem Format der String aufgebaut ist.
|
1 |
var d= moment("25.12.2012", "DD.MM.YYYY"); |
Die Beschreibung der unterstützen Tokens findet man in der Dokumentation: http://momentjs.com/docs/#/parsing/date
Formatieren lässt sich ein Datum mit der format Funktion. Diese Funktion unterstützt die gleichen Tokens wie das Parsen.
|
1 |
d.format("YYYY-MM-DD"); //2012-12-25 |
Eine Möglichkeit um die Differenz zwischen zwei Daten auszugeben bietet from an. Damit lassen sich Strings wie “a day ago” oder “in 5 days” erzeugen.
|
1 2 3 4 5 6 7 8 9 10 11 |
var a = moment([2012, 3, 9]); var b = moment([2012, 3, 20]); a.from(b); //"11 days ago" b.from(a); //"in 11 days" b.from([2012, 3, 21]); //"a day ago" var a = moment([2012, 0, 1, 13, 0, 0]); var b = moment([2012, 0, 1, 13, 5, 0]); a.from(b); //"5 minutes ago" b.from(a); //"in 5 minutes" |
Moment.js liefert auch Funktionen mit um einzelne Bestandteile eines Datums zu lesen und zu ändern. Im Gegensatz zu Date haben diese Funktionen kein set/get Prefix.
|
1 2 3 4 5 |
var day = moment("25.12.2012", "DD.MM.YYYY"); day.date(); // 25 day.date(26); day.format("DD.MM.YYYY"); //26.12.2012 |
Diese Funktionen lassen sich auch miteinander verketten.
|
1 |
moment().date(23).hours(0).minutes(0).seconds(0).milliseconds(0); |
Um die Zeit auf 00:00:00.000 zu setzen gibt es die Funktion sod (start of day) und eod (end of day) um die Zeit auf 23:59:59.999 zu setzen.
Zusätzlich kann mit day der Wochentag gesetzt werden. Dabei ist 0 = Sonntag und 6 = Samstag. Mit der Subtraktion oder Addition von 7 lässt sich der Wochentag von letzter oder nächster Woche setzen.
|
1 2 3 4 5 6 7 8 9 |
var d = moment("07.03.2012", "DD.MM.YYYY"); d.day(5); //Freitag 09.03.2012 d.day(5 + 7); //Freitag 16.03.2012 d.day(5 + 7 + 7); //Freitag 30.03.2012 var d = moment("07.03.2012", "DD.MM.YYYY"); d.day(5 - 7); //Freitag 02.03.2012 |
Die Funktion diff berechnet Differenzen zwischen zwei Daten. Dabei kann spezifiziert werden in welcher Einheit das Ergebnis zurückgegeben werden soll.
|
1 2 3 4 5 6 7 8 |
var a = moment([2012, 0, 1]); var b = moment([2012, 5, 23]); b.diff(a); //Millisekunden: 15033600000 b.diff(a, 'days'); //Tage: 174 b.diff(a, 'months'); //Monate: 6 b.diff(a, 'months', true); //Monate: 5.7333 |
Additionen und Subtraktionen lassen sich mit add und subtract durchführen.
|
1 2 3 |
var a = moment([2012, 0, 1]); a.add('days', 10); //11.01.2012 a.subtract('months', 1); //11.12.2011 |
Eine weitere nützliche Funktion von Moment.js ist isLeapYear die true oder false zurückliefert.
|
1 2 |
moment([2012]).isLeapYear(); //true moment([2011]).isLeapYear(); //false |
Sugar
Sugar ist keine reine Datumslibrary sondern erweitert alle nativen Javascript Objekte (Array, String, Number, …) um weitere Funktionen. Die Library ist deshalb einiges grösser (17kB gzipped). Sugar liefert aber eine Version aus (sugar-x.x.x-dates-only.min.js) die nur die Datumsfunktionen beinhaltet.
Im Gegensatz zu XDate und Moment.js gibt es hier kein neues Objekt sondern die zusätzlichen Funktion werden im Prototype des entsprechenden Objektes angefügt und stehen dann überall zur Verfügung.
Um ein Datumsobjekt zu erstellen führt Sugar die Funktion create ein.
|
1 2 3 |
Date.create(2012, 1); //1. Februar 2012 Date.create(2012, 1, 13); //13. Februar 2012 Date.create(2012, 1, 13, 10, 45); //13. Februar 2012 10:45 Uhr |
Zusätzlich erlaubt es create auch Daten aus Strings zu parsen.
|
1 2 3 4 5 6 |
Date.create("2012-02"); //1. Feburar 2012 Date.create("2012-02-13"); //13. February 2012 Date.create("02.13.2012"); //13. February 2012 Date.create("02/13/2012"); //13. February 2012 Date.create("2012-02-13 10:45:00"); //13. Februar 2012 10:45 Uhr Date.create("February 2012"); //1. Februar 2012 |
Sugar kann auch spezielle String wie “today” oder “the 13th of next month” verarbeiten. Eine Liste von möglichen Werten findet man in der Dokumentation.
|
1 2 3 4 5 |
Date.create("today"); //11. März 2012 Date.create("the 13th of next month"); //13. April 2012 Date.create("this week friday"); //16. März 2012 Date.create("last monday"); //5. März 2012 Date.create("10 minutes ago"); |
Mit der zusätzlichen Angabe einer Sprache werden auch andere Sprachen und Formate verstanden.
|
1 2 3 |
Date.create("13.2.2012", "de"); //13. Februar 2012 Date.create("heute", "de"); //11. März 2012 Date.create("aujourd'hui", "fr"); //11. März 2012 |
Mit set können beliebige Teile des Datums und der Zeit verändert werden.
|
1 2 3 |
Date.create().set({day: 21}); //21. März 2012 Date.create().set({day: 21, month: 1}); //21. Februar 2012 Date.create().set({day: 21, month: 1, year: 2015}); //21. Februar 2015 |
beginningOfUnit setzt das Datum an den Beginn der entsprechenden Einheit. Mit dem Gegenstück endOfUnit setzt man das Datum an das Ende der entsprechenden Einheit.
|
1 2 3 4 5 6 |
Date.create().beginningOfWeek(); //11. März 2012 Date.create().beginningOfMonth(); //1. März 2012 Date.create().beginningOfYear(); //1. Januar 2012 Date.create().endOfYear(); //31. Dezember 2012 Date.create().endOfMonth(); //31. März 2012 Date.create().endOfWeek(); //17. März 2012 |
Für die Datumsarithmetik steht die Funktionen addUnits zur Verfügung. Zusätzlich kann mit rewind und advance das Datum um bestimmte Werte “vorgespult” oder “zurückgespult” werden.
|
1 2 3 4 5 6 7 |
Date.create().addDays(3); //14. März 2012 Date.create().addDays(-3); //8. März 2012 Date.create().addMonths(1); //11. April 2012 Date.create().addMonths(-1); //11. Februar 2012 Date.create().advance({days: 3, months: 1}); //14. April 2012 Date.create().rewind({days: 3, months: 1}); //8. Februar 2012 |
Sugar bietet umfangreiche Funktionen an um Daten zu vergleichen. Es ist möglich zwei Daten miteinander zu vergleichen und zu prüfen ob eins davon zeitlich vor dem anderen liegt. isBetween erlaubt es zu prüfen ob ein Datum zwischen zwei Daten liegt. isFuture und isPast ermöglichen eine Prüfung ob ein Datum in der Zukunft oder in der Vergangenheit liegt. Mit is kann geprüft werden ob das Datum auf einem bestimmten Tag, Monat, Jahr liegt. isWeekend und isWeekday prüfen das Datum darauf ob es auf einem Samstag-Sonntag oder Montag-Freitag liegt.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
var a = Date.create(2012, 0); //1. Januar 2012 var b = Date.create("last day of april"); //30. April 2012 var q = Date.create("2012-03-13"); //13. März 2012 a.isBefore(q); //true b.isAfter(q); //true q.isBetween(a,b); //true q.isBetween("January", "July"); //true q.isPast(); //false q.isFuture(); //true q.isLeapYear(); //true q.isWeekend(); //false q.isWeekday(); //true q.isThisMonth(); //true q.isToday(); //false q.is("2012"); //true q.isAfter("April"); //false q.is("March"); //true |
Differenzen zwischen zwei Daten lassen sich mit unitsSince und unitsUntil berechnen.
|
1 2 3 4 5 6 |
var a = Date.create(2012, 7); var b = Date.create(2012, 8, 23); a.daysUntil(b); //53 a.daysSince(b); //-53 a.monthsUntil(b); //2 a.minutesUntil(b); //76320 |
Mit der Funktion format kann ein Datum auf unterschiedlichste Arten in einen String umgewandelt werden. Dazu übergibt man der Funktionen einen String der das Format beschreibt. Die einzelnen Tokens werden mit geschweiften Klammern {..} umschlossen. Zusätzlich existieren Konstanten, wie Date.ISO8601_DATETIME, die ein standardisiertes Format beschreiben und der format Funktion übergeben werden können.
|
1 2 3 4 5 6 7 8 |
Date.create().format(); //"March 11, 2012" Date.create().format('{yyyy}-{MM}-{dd}'); //"2012-03-11" Date.create().format('{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}'); //"2012-03-11 10:45:33" Date.create().format('Datum: {dd}. {Month} {yyyy} Zeit: {HH}:{mm}:{ss}', 'de'); //"Datum: 11. März 2012 Zeit: 10:46:44" Date.create().format(Date.ISO8601_DATETIME); //"2012-03-11T10:47:18.050+01:00" Date.create().format(Date.RFC1036); //"Sunday, 11-Mar-12 10:47:30 +0100" Date.create().format(Date.RFC1123, "de"); //"Son, 11 Mär 2012 10:47:43 +0100" |
Sugar kennt, wie Moment.js, Funktionen um Strings wie “4 days ago” und “10 minutes from now” zu erzeugen.
|
1 2 3 4 5 |
Date.create().addMinutes(-10).relative(); //"10 minutes ago" Date.create().addMinutes(10).relative(); //"10 minutes from now" Date.create().addMinutes(-10).relative('de'); //"vor 10 Minuten" Date.create().addMinutes(10).relative('de'); //"in 10 Minuten" Date.create(2012, 0).relative(); //"2 months ago" |
Sugar erweiter nicht nur das Date Objekt, sondern auch das Number Objekt um Datumsfunktionen, wie zum Beispiel unitBefore und unitAfter. Oder die unit Funktionen um eine Einheit in Millisekunden umzurechnen.
|
1 2 3 4 5 6 |
(2).hours(); //7200000 (2).milliseconds(); //2 (2).days(); //172800000 (2).months(); //5259600000 (2).daysBefore(Date.create(2012, 0, 5)); //3. Januar 2012 (2).monthsAfter(Date.create("September 2012")); //1. November 2012 |
Fazit
Date bietet nur minimale Funktionen um mit Daten und Zeiten zu arbeiten. XDate ist vom Funktionsumfang gesehen die kleinste der drei hier vorgestellten Libraries. Wenn in einem Projekt Datumsformatierungen vorgenommen werden, Datumsarithmetik oder Differenzen berechnet werden müssen ist XDate aber eine gute Wahl, die mit einem Overhead von 2.9 kB nicht gross ins Gewicht fällt. Moment.js kennt ein paar Tricks mehr, wie das Parsen von Daten und die relativen Daten (10 minutes ago), und ist mit 3.3 kB nicht viel grösser als XDate.
Sugar ist dann eine gute Wahl wenn man nicht nur die Date Funktionen sondern auch die Erweiterungen der anderen nativen Objekte (String, Number,Array, Objekt, Function, RegExp) benutzen möchte. Alternativ kann aber auch das Sugar Javscript File eingebunden werden das nur die Datumsfunktionen beinhaltet.
Es braucht aber nicht immer eine zusätzliche Datum/Zeit Library. Oft genügt das native Date Objekt in anderen Fällen können die Datumsberechnungen auf dem Server durchgeführt werden und der Client muss die Resultate dann nur anzeigen. Wichtig ist das man die Grösse der Javascript Files im Auge behält. Dies ist dann wichtig wenn Webapplikationen für mobile Geräte entwickelt werden.