TypeScript Datumsberechnungen: Komplettanleitung für Entwickler
Einführung in Datumsberechnungen mit TypeScript
Die Arbeit mit Datumsangaben gehört zu den häufigsten Aufgaben in der Webentwicklung. TypeScript bietet als typisierte Obermenge von JavaScript mächtige Werkzeuge, um mit Daten präzise und typsicher zu arbeiten. Dieser Leitfaden zeigt Ihnen, wie Sie komplexe Datumsoperationen in TypeScript implementieren – von einfachen Differenzberechnungen bis hin zu Geschäftslogik mit Feiertagsberechnungen.
Vorteile von TypeScript für Datumsberechnungen
- Typsicherheit verhindert häufige JavaScript-Datumsfehler
- Bessere IDE-Unterstützung durch Typinferenz
- Einfachere Wartung durch klare Schnittstellendefinitionen
- Moderne JavaScript-Features mit Kompatibilität zu älteren Browsern
Häufige Anwendungsfälle
- Berechnung von Fälligkeitsterminen
- Altersverifikation in Formularen
- Zeiterfassungssysteme
- Kalenderanwendungen
- Finanzielle Zinsberechnungen
Grundlagen der Datumsverarbeitung in TypeScript
Das Date-Objekt verstehen
Das fundamentale Objekt für Datumsoperationen in TypeScript ist das Date-Objekt, das von JavaScript geerbt wird. Es repräsentiert einen einzelnen Moment in der Zeit und wird in Millisekunden seit dem 1. Januar 1970 (Unix-Epoche) gemessen.
// Grundlegende Erstellung von Date-Objekten
const jetzt = new Date(); // Aktuelles Datum und Uhrzeit
const spezifischesDatum = new Date(‘2023-12-31’); // ISO-Format
const mitParametern = new Date(2023, 11, 31); // Jahr, Monat (0-11), Tag
// Wichtige Methoden
const jahr = jetzt.getFullYear();
const monat = jetzt.getMonth(); // 0-11
const tag = jetzt.getDate(); // 1-31
const wochentag = jetzt.getDay(); // 0 (Sonntag) – 6 (Samstag)
Zeitzonen und lokale vs. UTC-Zeiten
Ein kritischer Aspekt bei Datumsberechnungen ist das Verständnis von Zeitzonen. JavaScript/TypeScript arbeitet intern mit UTC (Koordinierte Weltzeit), stellt aber auch Methoden für lokale Zeiten bereit:
| Methode |
Beschreibung |
Beispiel |
getTimezoneOffset() |
Gibt die Differenz in Minuten zwischen lokaler Zeit und UTC zurück |
new Date().getTimezoneOffset() |
getUTC*() |
UTC-Äquivalente der get*-Methoden |
getUTCFullYear() |
toISOString() |
Gibt ISO-8601 String in UTC zurück |
'2023-12-31T23:00:00.000Z' |
toLocaleString() |
Formatiert nach lokalen Einstellungen |
'31.12.2023, 23:59:59' |
Für komplexe Zeitzonenoperationen empfiehlt sich die Verwendung von Bibliotheken wie Luxon oder date-fns, die umfassende Zeitzonenunterstützung bieten.
Praktische Datumsberechnungen implementieren
Differenz zwischen zwei Daten berechnen
Eine der häufigsten Operationen ist die Berechnung der Differenz zwischen zwei Daten. Hier ein typsicheres Beispiel in TypeScript:
interface DateDifference {
years: number;
months: number;
days: number;
totalDays: number;
totalHours: number;
totalMinutes: number;
totalSeconds: number;
}
function getDateDifference(startDate: Date, endDate: Date): DateDifference {
const start = new Date(startDate);
const end = new Date(endDate);
// Millisekunden Differenz
const diffInMs = end.getTime() – start.getTime();
const diffInSeconds = diffInMs / 1000;
const diffInMinutes = diffInSeconds / 60;
const diffInHours = diffInMinutes / 60;
const diffInDays = diffInHours / 24;
// Berechnung von Jahren, Monaten, Tagen
let years = end.getFullYear() – start.getFullYear();
let months = end.getMonth() – start.getMonth();
let days = end.getDate() – start.getDate();
if (days < 0) {
months--;
const tempDate = new Date(end.getFullYear(), end.getMonth(), 0);
days += tempDate.getDate();
}
if (months < 0) {
years--;
months += 12;
}
return {
years,
months,
days,
totalDays: diffInDays,
totalHours: diffInHours,
totalMinutes: diffInMinutes,
totalSeconds: diffInSeconds
};
}
// Verwendung
const start = new Date('2020-01-15');
const end = new Date('2023-06-20');
const difference = getDateDifference(start, end);
console.log(difference);
Tage zu einem Datum hinzufügen
Das Hinzufügen von Tagen zu einem Datum erfordert besondere Aufmerksamkeit bei Monatswechseln:
function addDays(date: Date, days: number): Date {
const result = new Date(date);
result.setDate(result.getDate() + days);
return result;
}
// Beispiel: 30 Tage zu heute hinzufügen
const today = new Date();
const futureDate = addDays(today, 30);
console.log(futureDate.toLocaleDateString());
Wochentage und Geschäftstage berechnen
Für viele Geschäftsanwendungen ist es wichtig, zwischen Kalendertagen und Geschäftstagen (Montag-Freitag) zu unterscheiden:
function isWeekend(date: Date): boolean {
const day = date.getDay();
return day === 0 || day === 6; // 0 = Sonntag, 6 = Samstag
}
function addBusinessDays(startDate: Date, days: number, holidays: string[] = []): Date {
const result = new Date(startDate);
let addedDays = 0;
while (addedDays < days) {
result.setDate(result.getDate() + 1);
// Überspringen von Wochenenden
if (!isWeekend(result)) {
// Überspringen von Feiertagen
const dateStr = result.toISOString().split('T')[0];
if (!holidays.includes(dateStr)) {
addedDays++;
}
}
}
return result;
}
// Beispiel: 10 Geschäftstage ab heute
const businessDate = addBusinessDays(new Date(), 10, ['2023-12-25', '2023-12-26']);
console.log(businessDate.toLocaleDateString());
Fortgeschrittene Techniken und Best Practices
Immutable Datumsoperationen
Ein wichtiger Grundsatz in der funktionalen Programmierung ist die Unveränderlichkeit (Immutability) von Daten. Bei Datumsoperationen bedeutet das, dass wir immer neue Date-Objekte zurückgeben sollten, statt bestehende zu modifizieren:
function addMonthsImmutable(date: Date, months: number): Date {
const result = new Date(date);
const currentMonth = result.getMonth();
result.setMonth(currentMonth + months);
// Korrektur wenn der Tag im neuen Monat nicht existiert (z.B. 31. Januar + 1 Monat)
if (result.getMonth() !== (currentMonth + months) % 12) {
result.setDate(0); // Letzter Tag des vorherigen Monats
}
return result;
}
// Verwendung
const originalDate = new Date(‘2023-01-31’);
const newDate = addMonthsImmutable(originalDate, 1);
console.log(newDate.toLocaleDateString()); // 28.02.2023 (kein 31.02.)
Performance-Optimierung bei Massenoperationen
Bei der Verarbeitung großer Datumsmengen (z.B. in Datenbankabfragen oder Batch-Prozessen) ist Performance entscheidend. Hier einige Optimierungstipps:
- Vermeiden Sie unnötige Objektinstanziierungen: Erstellen Sie Date-Objekte nur wenn nötig
- Nutzen Sie UTC-Methoden: Diese sind oft schneller als lokale Methoden
- Cache häufig verwendete Werte: Speichern Sie z.B. Monatslängen zwischen
- Verwenden Sie TypedArrays für Millisekunden-Operationen: Für hochperformante Berechnungen
// Optimierte Differenzberechnung in Millisekunden
function daysBetweenOptimized(date1: Date, date2: Date): number {
// Direkte Berechnung ohne Objektinstanziierung
return Math.abs((date2.getTime() – date1.getTime()) / (1000 * 60 * 60 * 24));
}
// Benchmark-Vergleich
console.time(‘Standard’);
for (let i = 0; i < 100000; i++) {
const diff = new Date('2023-01-01').getTime() - new Date('2022-01-01').getTime();
}
console.timeEnd('Standard');
console.time('Optimiert');
const start = new Date('2022-01-01').getTime();
const end = new Date('2023-01-01').getTime();
for (let i = 0; i < 100000; i++) {
const diff = end - start;
}
console.timeEnd('Optimiert');
Typisierung komplexer Datumsoperationen
TypeScript glänzt bei der Modellierung komplexer Datumsoperationen durch benutzerdefinierte Typen:
type DateUnit = ‘years’ | ‘months’ | ‘weeks’ | ‘days’ | ‘hours’ | ‘minutes’ | ‘seconds’;
interface DateDuration {
[key: string]: number;
years?: number;
months?: number;
weeks?: number;
days?: number;
hours?: number;
minutes?: number;
seconds?: number;
}
class TypeSafeDate {
private date: Date;
constructor(date: Date | string | number) {
this.date = new Date(date);
}
add(duration: DateDuration): TypeSafeDate {
const result = new Date(this.date);
if (duration.years) result.setFullYear(result.getFullYear() + duration.years);
if (duration.months) result.setMonth(result.getMonth() + duration.months);
if (duration.weeks) result.setDate(result.getDate() + duration.weeks * 7);
if (duration.days) result.setDate(result.getDate() + duration.days);
if (duration.hours) result.setHours(result.getHours() + duration.hours);
if (duration.minutes) result.setMinutes(result.getMinutes() + duration.minutes);
if (duration.seconds) result.setSeconds(result.getSeconds() + duration.seconds);
return new TypeSafeDate(result);
}
diff(other: TypeSafeDate, unit: DateUnit = ‘days’): number {
const diffMs = this.date.getTime() – other.date.getTime();
switch (unit) {
case ‘years’: return diffMs / (1000 * 60 * 60 * 24 * 365);
case ‘months’: return diffMs / (1000 * 60 * 60 * 24 * 30); // Approximation
case ‘weeks’: return diffMs / (1000 * 60 * 60 * 24 * 7);
case ‘days’: return diffMs / (1000 * 60 * 60 * 24);
case ‘hours’: return diffMs / (1000 * 60 * 60);
case ‘minutes’: return diffMs / (1000 * 60);
case ‘seconds’: return diffMs / 1000;
default: return diffMs;
}
}
format(pattern: string): string {
// Implementierung einer einfachen Formatierung
return pattern
.replace(‘YYYY’, this.date.getFullYear().toString())
.replace(‘MM’, (this.date.getMonth() + 1).toString().padStart(2, ‘0’))
.replace(‘DD’, this.date.getDate().toString().padStart(2, ‘0’));
}
}
// Verwendung
const birthday = new TypeSafeDate(‘1990-05-15’);
const futureBirthday = birthday.add({ years: 1, days: 10 });
console.log(futureBirthday.format(‘YYYY-MM-DD’));
console.log(`Tage bis zum nächsten Geburtstag: ${birthday.diff(futureBirthday, ‘days’)}`);
Feiertagsberechnungen und Geschäftslogik
Dynamische Feiertagsberechnung
Viele Anwendungen benötigen die Fähigkeit, Feiertage zu berechnen, die sich jährlich ändern (wie Ostern) oder von lokalen Regelungen abhängen. Hier ein Beispiel für die Berechnung beweglicher Feiertage in Deutschland:
interface Holiday {
name: string;
date: Date;
type: ‘fixed’ | ‘movable’;
}
function calculateGermanHolidays(year: number): Holiday[] {
const holidays: Holiday[] = [];
// Feste Feiertage
holidays.push(
{ name: ‘Neujahr’, date: new Date(year, 0, 1), type: ‘fixed’ },
{ name: ‘Tag der Arbeit’, date: new Date(year, 4, 1), type: ‘fixed’ },
{ name: ‘Tag der Deutschen Einheit’, date: new Date(year, 9, 3), type: ‘fixed’ },
{ name: ‘Weihnachten’, date: new Date(year, 11, 25), type: ‘fixed’ },
{ name: ‘2. Weihnachtsfeiertag’, date: new Date(year, 11, 26), type: ‘fixed’ }
);
// Berechnung von Ostern (Gaußsche Osterformel)
const y = year;
const a = y % 19;
const b = Math.floor(y / 100);
const c = y % 100;
const d = Math.floor(b / 4);
const e = b % 4;
const f = Math.floor((b + 8) / 25);
const g = Math.floor((b – f + 1) / 3);
const h = (19 * a + b – d – g + 15) % 30;
const i = Math.floor(c / 4);
const k = c % 4;
const l = (32 + 2 * e + 2 * i – h – k) % 7;
const m = Math.floor((a + 11 * h + 22 * l) / 451);
const month = Math.floor((h + l – 7 * m + 114) / 31);
const day = ((h + l – 7 * m + 114) % 31) + 1;
const easter = new Date(year, month – 1, day);
// Bewegliche Feiertage basierend auf Ostern
holidays.push(
{ name: ‘Karfreitag’, date: new Date(easter.getTime() – 2 * 24 * 60 * 60 * 1000), type: ‘movable’ },
{ name: ‘Ostermontag’, date: new Date(easter.getTime() + 24 * 60 * 60 * 1000), type: ‘movable’ },
{ name: ‘Christi Himmelfahrt’, date: new Date(easter.getTime() + 39 * 24 * 60 * 60 * 1000), type: ‘movable’ },
{ name: ‘Pfingstmontag’, date: new Date(easter.getTime() + 50 * 24 * 60 * 60 * 1000), type: ‘movable’ }
);
return holidays;
}
// Beispielverwendung
const holidays2023 = calculateGermanHolidays(2023);
console.log(‘Feiertage 2023:’);
holidays2023.forEach(h => console.log(`${h.name}: ${h.date.toLocaleDateString()}`));
Integration mit Arbeitszeitmodellen
Für Unternehmensanwendungen ist oft die Kombination von Feiertagsberechnungen mit individuellen Arbeitszeitmodellen erforderlich. Hier ein Beispiel für ein flexibles Arbeitszeitmodell:
interface WorkingHours {
start: string; // ’09:00′
end: string; // ’17:00′
breakStart?: string;
breakEnd?: string;
}
interface WorkSchedule {
monday: WorkingHours[];
tuesday: WorkingHours[];
wednesday: WorkingHours[];
thursday: WorkingHours[];
friday: WorkingHours[];
saturday?: WorkingHours[];
sunday?: WorkingHours[];
}
class BusinessTimeCalculator {
private holidays: Date[];
private schedule: WorkSchedule;
constructor(holidays: Date[], schedule: WorkSchedule) {
this.holidays = holidays;
this.schedule = schedule;
}
isWorkingDay(date: Date): boolean {
const dayOfWeek = date.getDay(); // 0 (Sonntag) – 6 (Samstag)
const dateStr = date.toISOString().split(‘T’)[0];
// Prüfe auf Wochenende
if (dayOfWeek === 0 || dayOfWeek === 6) {
return !!this.schedule.sunday || !!this.schedule.saturday;
}
// Prüfe auf Feiertag
if (this.holidays.some(h => h.toISOString().split(‘T’)[0] === dateStr)) {
return false;
}
return true;
}
getWorkingHoursForDate(date: Date): WorkingHours[] | null {
const dayOfWeek = date.getDay();
const days = [‘sunday’, ‘monday’, ‘tuesday’, ‘wednesday’, ‘thursday’, ‘friday’, ‘saturday’];
return this.schedule[days[dayOfWeek] as keyof WorkSchedule] || null;
}
addBusinessHours(startDate: Date, hours: number): Date {
const result = new Date(startDate);
let remainingHours = hours;
while (remainingHours > 0) {
result.setTime(result.getTime() + 60 * 60 * 1000); // +1 Stunde
if (this.isWorkingDay(result)) {
const workingHours = this.getWorkingHoursForDate(result);
if (workingHours) {
const currentHour = result.getHours();
const currentMinute = result.getMinutes();
// Prüfe ob aktuelle Zeit innerhalb Arbeitszeit
const isWorkingTime = workingHours.some(slot => {
const [startH, startM] = slot.start.split(‘:’).map(Number);
const [endH, endM] = slot.end.split(‘:’).map(Number);
const slotStart = new Date(result);
slotStart.setHours(startH, startM, 0, 0);
const slotEnd = new Date(result);
slotEnd.setHours(endH, endM, 0, 0);
return result >= slotStart && result < slotEnd;
});
if (isWorkingTime) {
remainingHours--;
}
}
}
}
return result;
}
}
// Beispielverwendung
const holidays = calculateGermanHolidays(2023).map(h => h.date);
const standardSchedule: WorkSchedule = {
monday: [{ start: ’09:00′, end: ’17:00′, breakStart: ’12:00′, breakEnd: ’13:00′ }],
tuesday: [{ start: ’09:00′, end: ’17:00′, breakStart: ’12:00′, breakEnd: ’13:00′ }],
wednesday: [{ start: ’09:00′, end: ’17:00′, breakStart: ’12:00′, breakEnd: ’13:00′ }],
thursday: [{ start: ’09:00′, end: ’17:00′, breakStart: ’12:00′, breakEnd: ’13:00′ }],
friday: [{ start: ’09:00′, end: ’15:00′ }],
saturday: [], // Keine Arbeitszeit am Samstag
sunday: [] // Keine Arbeitszeit am Sonntag
};
const calculator = new BusinessTimeCalculator(holidays, standardSchedule);
const start = new Date(‘2023-06-01T09:00:00’);
const end = calculator.addBusinessHours(start, 16); // 16 Arbeitsstunden hinzufügen
console.log(`Start: ${start.toLocaleString()}`);
console.log(`Ende nach 16 Arbeitsstunden: ${end.toLocaleString()}`);
Testing und Validierung von Datumslogik
Unit Tests für Datumsfunktionen
Datumsberechnungen sind fehleranfällig und sollten gründlich getestet werden. Hier ein Beispiel mit Jest:
// addDays.test.ts
import { addDays } from ‘./dateUtils’;
describe(‘addDays’, () => {
it(‘should add days correctly’, () => {
const date = new Date(‘2023-01-15’);
const result = addDays(date, 5);
expect(result.toISOString()).toBe(‘2023-01-20T00:00:00.000Z’);
});
it(‘should handle month transitions’, () => {
const date = new Date(‘2023-01-30’);
const result = addDays(date, 5);
expect(result.toISOString()).toBe(‘2023-02-04T00:00:00.000Z’);
});
it(‘should handle year transitions’, () => {
const date = new Date(‘2022-12-30’);
const result = addDays(date, 5);
expect(result.toISOString()).toBe(‘2023-01-04T00:00:00.000Z’);
});
it(‘should not modify original date’, () => {
const date = new Date(‘2023-01-15’);
const originalTime = date.getTime();
addDays(date, 5);
expect(date.getTime()).toBe(originalTime);
});
});
Edge Cases und Sonderfälle
Besondere Aufmerksamkeit verdienen diese häufig übersehenen Szenarien:
| Szenario |
Problem |
Lösung |
| Schaltjahre |
Falsche Berechnung von Tagen im Februar |
Immer das Date-Objekt für Monatslängen verwenden |
| Zeitzonenwechsel |
Unerwartete Datumsänderungen bei DST |
UTC-Methoden bevorzugen oder Bibliotheken wie Luxon nutzen |
| Monatsende |
31. Januar + 1 Monat = 28./29./30./31. Februar? |
Automatische Korrektur durch setMonth() nutzen |
| Große Zeitspannen |
Performance-Probleme bei Millionen von Tagen |
Mathematische Berechnung statt Schleifen |
| Invalid Dates |
new Date(‘2023-02-30’) erstellt gültiges Datum |
Immer Validierung durchführen |
Validierung von Datumseingaben
Benutzereingaben sollten immer validiert werden, bevor sie verarbeitet werden:
function isValidDate(input: unknown): input is Date {
return input instanceof Date && !isNaN(input.getTime());
}
function parseDate(input: string | Date): Date | null {
if (input instanceof Date) {
return isValidDate(input) ? input : null;
}
if (typeof input === ‘string’) {
const date = new Date(input);
return isValidDate(date) ? date : null;
}
return null;
}
function validateDateRange(start: Date, end: Date): boolean {
return isValidDate(start) && isValidDate(end) && start <= end;
}
// Verwendung
const userInput = '2023-13-01'; // Ungültiges Datum
const parsed = parseDate(userInput);
if (!parsed) {
console.error('Ungültiges Datumsformat');
} else {
// Sichere Verarbeitung
}
Performance-Vergleich von Datumsbibliotheken
Für komplexe Anwendungen lohnt sich der Vergleich verschiedener Ansätze:
| Bibliothek/Ansatz |
Größe |
Performance (Ops/sec) |
Typsicherheit |
Zeitzonen |
Lernkurve |
| Vanilla JavaScript |
0 KB |
~5,000,000 |
❌ (keine) |
⚠️ (begrenzt) |
⭐ |
| TypeScript + Date |
0 KB |
~4,800,000 |
✅ (voll) |
⚠️ (begrenzt) |
⭐⭐ |
| date-fns |
~70 KB |
~3,200,000 |
✅ (voll) |
✅ (voll) |
⭐⭐ |
| Luxon |
~180 KB |
~2,800,000 |
✅ (voll) |
✅ (voll) |
⭐⭐⭐ |
| Moment.js |
~300 KB |
~1,500,000 |
✅ (voll) |
✅ (voll) |
⭐⭐⭐ |
| Day.js |
~5 KB |
~4,000,000 |
✅ (voll) |
⚠️ (Plugin) |
⭐⭐ |
Quellen: Bundlephobia, JSPerf Benchmarks
Empfehlungen für verschiedene Anwendungsfälle
- Einfache Webanwendungen: Vanilla TypeScript mit Date-Objekt + ggf. kleine Helferfunktionen
- Komplexe Frontend-Anwendungen: date-fns (modular, gute TypeScript-Unterstützung)
- Enterprise-Anwendungen mit Zeitzonen: Luxon (Nachfolger von Moment.js)
- Size-kritische Anwendungen: Day.js (sehr klein, aber weniger Features)
- Node.js Backend: Native Date + ggf. Intl.DateTimeFormat für Lokalisierung
Rechtliche Aspekte von Datumsberechnungen
Datumsberechnungen können rechtliche Implikationen haben, insbesondere in folgenden Bereichen:
- Vertragsrecht: Fristberechnungen müssen oft “Geschäftstage” berücksichtigen
- Arbeitsrecht: Kündigungsfristen, Urlaubsansprüche
- Finanzwesen: Zinsberechnungen (ACT/360 vs. ACT/365)
- Datenschutz: Altersverifikation (z.B. für COPPA-Compliance)
- Steuerrecht: Fristen für Steuererklärungen
In Deutschland sind insbesondere die Regelungen des Bürgerlichen Gesetzbuchs (BGB) zu Fristen und Terminen relevant. §186 BGB definiert beispielsweise, dass der Beginn einer Frist nicht mitgezählt wird, während §193 BGB regelt, dass eine Frist, die an einem Sonnabend, Sonntag oder gesetzlichen Feiertag endet, mit Ablauf des nächsten Werktages endet.
Beispiel: Fristberechnung nach BGB
function calculateLegalDeadline(startDate: Date, days: number, holidays: Date[]): Date {
const result = new Date(startDate);
let addedDays = 0;
// §186 BGB: Der Tag, in den das Ereignis oder der Zeitpunkt fällt, wird nicht mitgerechnet
result.setDate(result.getDate() + 1);
while (addedDays < days) {
result.setDate(result.getDate() + 1);
// §193 BGB: Sonntage, Samstage und Feiertage zählen nicht
const dayOfWeek = result.getDay();
const dateStr = result.toISOString().split('T')[0];
if (dayOfWeek !== 0 && dayOfWeek !== 6 && !holidays.some(h => h.toISOString().split(‘T’)[0] === dateStr)) {
addedDays++;
}
}
return result;
}
// Beispiel: 14-tägige Frist ab 15. Juni 2023
const germanHolidays = calculateGermanHolidays(2023).map(h => h.date);
const deadline = calculateLegalDeadline(new Date(‘2023-06-15’), 14, germanHolidays);
console.log(`Fristende: ${deadline.toLocaleDateString()}`);
Für internationale Anwendungen müssen die lokalen Gesetzgebungen berücksichtigt werden. Die Vereinten Nationen bieten eine Übersicht über internationale Standards zu Datumsformaten und Fristberechnungen.
Zukunft der Datumsverarbeitung: Temporal API
Die JavaScript-Community arbeitet an einer neuen Temporal API, die die bestehenden Date-Probleme lösen soll. Diese neue API wird voraussichtlich 2024 als ECMAScript-Standard veröffentlicht und bietet:
- Unveränderliche (immutable) Datumsobjekte
- Vollständige Zeitzonenunterstützung
- Präzisere Berechnungen (z.B. für Schaltsekunden)
- Bessere Unterstützung für nicht-gregorianische Kalender
- Einfachere API für häufige Operationen
Ein Vergleich zwischen der aktuellen Date-API und der neuen Temporal-API:
| Operation |
Aktuelle Date-API |
Temporal-API (Zukunft) |
| Aktuelles Datum |
new Date() |
Temporal.Now.plainDateISO() |
| Datum parsen |
new Date('2023-12-31') |
Temporal.PlainDate.from('2023-12-31') |
| Tage addieren |
date.setDate(date.getDate() + 5) |
date.add({ days: 5 }) |
| Differenz berechnen |
(date2 - date1) / (1000*60*60*24) |
date1.until(date2).days |
| Zeitzonenkonvertierung |
Komplex, oft Bibliotheken nötig |
date.toZonedDateTime('Europe/Berlin') |
| Unveränderlichkeit |
❌ (mutabel) |
✅ (immutable) |
Die Temporal-API wird voraussichtlich abwärstkompatibel sein und kann bereits heute über Polyfills wie @js-temporal/polyfill genutzt werden.
Zusammenfassung und Best Practices
10 Goldene Regeln für Datumsberechnungen in TypeScript
- Immer Typsicherheit nutzen: Definieren Sie klare Interfaces für Datumsoperationen
- Unveränderlichkeit bevorzugen: Erstellen Sie neue Date-Objekte statt bestehende zu modifizieren
- Zeitzonen bewusst behandeln: Dokumentieren Sie, ob UTC oder lokale Zeit verwendet wird
- Edge Cases testen: Besonders Monatsenden, Schaltjahre und Zeitzonenwechsel
- Validierung implementieren: Prüfen Sie alle Benutzereingaben auf gültige Daten
- Performance im Blick behalten: Vermeiden Sie unnötige Objektinstanziierungen in Schleifen
- Dokumentation schreiben: Klären Sie, welche Datumslogik (inkl./exkl. Enddatum etc.) verwendet wird
- Externe Bibliotheken evaluieren: Für komplexe Anforderungen können Bibliotheken wie Luxon oder date-fns sinnvoll sein
- Rechtliche Anforderungen prüfen: Besonders bei Fristberechnungen für Verträge
- Zukunftssicher planen: Bereiten Sie sich auf die Temporal-API vor
Empfohlene Ressourcen