Wie man Datumsbereiche wie 1. Jan - 5. Jan formatiert

Verwenden Sie JavaScript, um Datumsbereiche mit lokalisierungsgerechter Formatierung und intelligenter Redundanzentfernung anzuzeigen

Einführung

Datumsbereiche erscheinen in zahlreichen Webanwendungen. Buchungssysteme zeigen Verfügbarkeiten vom 1. Januar bis 5. Januar an, Eventkalender stellen mehrtägige Konferenzen dar, Analyse-Dashboards präsentieren Daten für spezifische Zeiträume, und Berichte umfassen Geschäftsquartale oder benutzerdefinierte Datumsspannen. Diese Bereiche kommunizieren, dass etwas für alle Daten zwischen zwei Endpunkten gilt.

Wenn Sie Datumsbereiche manuell formatieren, indem Sie zwei formatierte Datumsangaben mit einem Bindestrich verbinden, erzeugen Sie unnötig ausführliche Ausgaben. Ein Bereich vom 1. Januar 2024 bis zum 5. Januar 2024 muss nicht Monat und Jahr im zweiten Datum wiederholen. Die Ausgabe "1. - 5. Januar 2024" vermittelt dieselbe Information prägnanter, indem redundante Komponenten weggelassen werden.

JavaScript bietet die Methode formatRange() in Intl.DateTimeFormat, um die Formatierung von Datumsbereichen automatisch zu handhaben. Diese Methode bestimmt, welche Datumskomponenten in jedem Teil des Bereichs enthalten sein sollen, wendet lokalitätsspezifische Konventionen für Trennzeichen und Formatierung an und entfernt unnötige Wiederholungen.

Warum Datumsbereiche intelligente Formatierung benötigen

Verschiedene Datumsbereiche erfordern unterschiedliche Detailebenen. Ein Bereich innerhalb desselben Monats benötigt weniger Informationen als ein Bereich, der mehrere Jahre umfasst. Das optimale Format hängt davon ab, welche Datumskomponenten sich zwischen Start- und Enddatum unterscheiden.

Für einen Bereich innerhalb desselben Tages müssen Sie nur den Zeitunterschied anzeigen: "10:00 - 14:00 Uhr". Die Wiederholung des vollständigen Datums für beide Zeiten fügt keine Informationen hinzu.

Für einen Bereich innerhalb desselben Monats zeigen Sie den Monat einmal an und listen beide Tagesnummern auf: "1.-5. Januar 2024". Die zweimalige Angabe von "Januar" erschwert das Lesen der Ausgabe, ohne Klarheit zu schaffen.

Für einen Bereich, der verschiedene Monate im selben Jahr umfasst, zeigen Sie beide Monate an, können aber das Jahr vom ersten Datum weglassen: "25. Dezember 2024 - 2. Januar 2025" benötigt die vollständigen Informationen, aber "15. Januar - 20. Februar 2024" kann in einigen Spracheinstellungen das Jahr vom ersten Datum weglassen.

Für Bereiche, die mehrere Jahre umfassen, müssen Sie das Jahr für beide Daten angeben: "1. Dezember 2023 - 15. März 2024".

Die manuelle Implementierung dieser Regeln erfordert die Überprüfung, welche Datumskomponenten sich unterscheiden, und die entsprechende Konstruktion von Formatierungsstrings. Verschiedene Spracheinstellungen wenden diese Regeln auch unterschiedlich an, mit verschiedenen Trennzeichen und Anordnungskonventionen. Die Methode formatRange() kapselt diese Logik.

Verwendung von formatRange zur Formatierung von Datumsbereichen

Die Methode formatRange() akzeptiert zwei Date-Objekte und gibt eine formatierte Zeichenfolge zurück. Erstellen Sie eine Intl.DateTimeFormat-Instanz mit Ihrer gewünschten Locale und Optionen, und rufen Sie dann formatRange() mit dem Start- und Enddatum auf.

const formatter = new Intl.DateTimeFormat("en-US");

const start = new Date(2024, 0, 1);
const end = new Date(2024, 0, 5);

console.log(formatter.formatRange(start, end));
// Ausgabe: "1/1/24 – 1/5/24"

Der Formatierer wendet das standardmäßige US-englische Datumsformat auf beide Daten an und verbindet sie mit einem Halbgeviertstrich. Bei Daten innerhalb desselben Monats zeigt die Ausgabe immer noch beide vollständigen Daten an, da das Standardformat recht kurz ist.

Sie können festlegen, welche Datumskomponenten einbezogen werden sollen, indem Sie dieselben Optionen verwenden, die für die reguläre Datumsformatierung verfügbar sind.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const start = new Date(2024, 0, 1);
const end = new Date(2024, 0, 5);

console.log(formatter.formatRange(start, end));
// Ausgabe: "January 1 – 5, 2024"

Jetzt lässt der Formatierer intelligent den Monat und das Jahr aus dem zweiten Datum weg, da sie mit dem ersten Datum übereinstimmen. Die Ausgabe zeigt nur die Tagesnummer für das Enddatum an, was den Bereich lesbarer macht.

Wie formatRange die Ausgabe von Datumsbereichen optimiert

Die Methode formatRange() untersucht beide Daten und bestimmt, welche Komponenten sich unterscheiden. Sie fügt nur die notwendigen Komponenten in jedem Teil des Bereichs ein.

Bei Daten im selben Monat und Jahr erscheint nur der Endtag im zweiten Teil.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(formatter.formatRange(
  new Date(2024, 0, 1),
  new Date(2024, 0, 5)
));
// Ausgabe: "January 1 – 5, 2024"

console.log(formatter.formatRange(
  new Date(2024, 0, 15),
  new Date(2024, 0, 20)
));
// Ausgabe: "January 15 – 20, 2024"

Beide Bereiche zeigen den Monat und das Jahr einmal an, wobei nur die Tagesnummern durch den Bereichstrenner verbunden sind.

Bei Daten in verschiedenen Monaten desselben Jahres erscheinen beide Monate, aber das Jahr erscheint nur einmal.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(formatter.formatRange(
  new Date(2024, 0, 15),
  new Date(2024, 1, 20)
));
// Ausgabe: "January 15 – February 20, 2024"

Der Formatierer enthält beide Monatsnamen, platziert aber das Jahr am Ende und wendet es auf den gesamten Bereich an.

Bei Daten, die verschiedene Jahre umfassen, erscheinen beide vollständigen Daten.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(formatter.formatRange(
  new Date(2023, 11, 25),
  new Date(2024, 0, 5)
));
// Ausgabe: "December 25, 2023 – January 5, 2024"

Jedes Datum enthält sein vollständiges Jahr, da sich die Jahre unterscheiden. Der Formatierer kann keines der Jahre weglassen, ohne Mehrdeutigkeit zu erzeugen.

Formatierung von Datums- und Zeitbereichen

Wenn Ihr Format Zeitkomponenten enthält, wendet die Methode formatRange() dieselbe intelligente Auslassung auf Zeitfelder an.

Bei Zeiten am selben Tag unterscheiden sich nur die Zeitkomponenten in der Ausgabe.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric",
  hour: "numeric",
  minute: "numeric"
});

const start = new Date(2024, 0, 1, 10, 0);
const end = new Date(2024, 0, 1, 14, 30);

console.log(formatter.formatRange(start, end));
// Ausgabe: "January 1, 2024, 10:00 AM – 2:30 PM"

Das Datum erscheint einmal, gefolgt vom Zeitbereich. Der Formatierer erkennt, dass die Wiederholung des vollständigen Datums und der Zeit für das Ende keine nützlichen Informationen hinzufügen würde.

Bei Zeiten an verschiedenen Tagen erscheinen beide vollständigen Datums- und Zeitwerte.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric",
  hour: "numeric",
  minute: "numeric"
});

const start = new Date(2024, 0, 1, 10, 0);
const end = new Date(2024, 0, 2, 14, 30);

console.log(formatter.formatRange(start, end));
// Ausgabe: "January 1, 2024, 10:00 AM – January 2, 2024, 2:30 PM"

Beide Daten und Zeiten erscheinen, weil sie verschiedene Tage darstellen. Der Formatierer kann keine Komponenten sicher weglassen.

Formatierung von Datumsbereichen in verschiedenen Sprachen

Die Bereichsformatierung passt sich den Konventionen jeder Sprache für die Reihenfolge der Datumskomponenten, Trennzeichen und welche Komponenten weggelassen werden sollen, an.

const enFormatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(enFormatter.formatRange(
  new Date(2024, 0, 1),
  new Date(2024, 0, 5)
));
// Ausgabe: "January 1 – 5, 2024"

const deFormatter = new Intl.DateTimeFormat("de-DE", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(deFormatter.formatRange(
  new Date(2024, 0, 1),
  new Date(2024, 0, 5)
));
// Ausgabe: "1.–5. Januar 2024"

const jaFormatter = new Intl.DateTimeFormat("ja-JP", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(jaFormatter.formatRange(
  new Date(2024, 0, 1),
  new Date(2024, 0, 5)
));
// Ausgabe: "2024年1月1日~5日"

Englisch stellt den Monat zuerst und zeigt das Jahr am Ende. Deutsch stellt die Tageszahlen mit Punkten zuerst, dann den Monatsnamen, dann das Jahr. Japanisch verwendet die Reihenfolge Jahr-Monat-Tag und den Wellenstrich (~) als Bereichstrenner. Jede Sprache wendet ihre eigenen Konventionen an, welche Komponenten einmal oder zweimal angezeigt werden sollen.

Diese Unterschiede erstrecken sich auch auf monatsübergreifende Bereiche.

const enFormatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(enFormatter.formatRange(
  new Date(2024, 0, 15),
  new Date(2024, 1, 20)
));
// Ausgabe: "January 15 – February 20, 2024"

const deFormatter = new Intl.DateTimeFormat("de-DE", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(deFormatter.formatRange(
  new Date(2024, 0, 15),
  new Date(2024, 1, 20)
));
// Ausgabe: "15. Januar – 20. Februar 2024"

const frFormatter = new Intl.DateTimeFormat("fr-FR", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

console.log(frFormatter.formatRange(
  new Date(2024, 0, 15),
  new Date(2024, 1, 20)
));
// Ausgabe: "15 janvier – 20 février 2024"

Alle drei Sprachen zeigen beide Monatsnamen, positionieren sie aber unterschiedlich in Bezug auf die Tageszahlen. Die Formatierer handhaben diese Variationen automatisch.

Formatierung von Datumsbereichen mit verschiedenen Stilen

Sie können die Option dateStyle verwenden, um die Gesamtlänge des Formats zu steuern, genau wie bei der Formatierung einzelner Datumsangaben.

const shortFormatter = new Intl.DateTimeFormat("en-US", {
  dateStyle: "short"
});

console.log(shortFormatter.formatRange(
  new Date(2024, 0, 1),
  new Date(2024, 0, 5)
));
// Output: "1/1/24 – 1/5/24"

const mediumFormatter = new Intl.DateTimeFormat("en-US", {
  dateStyle: "medium"
});

console.log(mediumFormatter.formatRange(
  new Date(2024, 0, 1),
  new Date(2024, 0, 5)
));
// Output: "Jan 1 – 5, 2024"

const longFormatter = new Intl.DateTimeFormat("en-US", {
  dateStyle: "long"
});

console.log(longFormatter.formatRange(
  new Date(2024, 0, 1),
  new Date(2024, 0, 5)
));
// Output: "January 1 – 5, 2024"

const fullFormatter = new Intl.DateTimeFormat("en-US", {
  dateStyle: "full"
});

console.log(fullFormatter.formatRange(
  new Date(2024, 0, 1),
  new Date(2024, 0, 5)
));
// Output: "Monday, January 1 – Friday, January 5, 2024"

Der Stil short erzeugt numerische Datumsangaben und wendet keine intelligente Auslassung an, da das Format bereits kompakt ist. Die Stile medium und long kürzen den Monatsnamen ab oder schreiben ihn aus und lassen redundante Komponenten weg. Der Stil full enthält Wochentagsnamen für beide Datumsangaben.

Verwendung von formatRangeToParts für benutzerdefinierte Formatierung

Die Methode formatRangeToParts() gibt ein Array von Objekten zurück, die die Komponenten des formatierten Bereichs darstellen. Dies ermöglicht es Ihnen, einzelne Teile der Bereichsausgabe zu formatieren oder zu manipulieren.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const parts = formatter.formatRangeToParts(
  new Date(2024, 0, 1),
  new Date(2024, 0, 5)
);

console.log(parts);

Die Ausgabe ist ein Array von Objekten, jedes mit den Eigenschaften type, value und source.

[
  { type: "month", value: "January", source: "startRange" },
  { type: "literal", value: " ", source: "startRange" },
  { type: "day", value: "1", source: "startRange" },
  { type: "literal", value: " – ", source: "shared" },
  { type: "day", value: "5", source: "endRange" },
  { type: "literal", value: ", ", source: "shared" },
  { type: "year", value: "2024", source: "shared" }
]

Die Eigenschaft type identifiziert die Komponente: Monat, Tag, Jahr oder literaler Text. Die Eigenschaft value enthält den formatierten Text. Die Eigenschaft source gibt an, ob die Komponente zum Startdatum, Enddatum gehört oder zwischen ihnen geteilt wird.

Sie können diese Teile verwenden, um benutzerdefiniertes HTML mit Formatierung für verschiedene Komponenten zu erstellen.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const parts = formatter.formatRangeToParts(
  new Date(2024, 0, 1),
  new Date(2024, 0, 5)
);

let html = "";

parts.forEach(part => {
  if (part.type === "month") {
    html += `<span class="month">${part.value}</span>`;
  } else if (part.type === "day") {
    html += `<span class="day">${part.value}</span>`;
  } else if (part.type === "year") {
    html += `<span class="year">${part.value}</span>`;
  } else if (part.type === "literal" && part.source === "shared" && part.value.includes("–")) {
    html += `<span class="separator">${part.value}</span>`;
  } else {
    html += part.value;
  }
});

console.log(html);
// Output: <span class="month">January</span> <span class="day">1</span><span class="separator"> – </span><span class="day">5</span>, <span class="year">2024</span>

Diese Technik bewahrt die sprachspezifische Formatierung und ermöglicht gleichzeitig eine benutzerdefinierte visuelle Gestaltung.

Was passiert, wenn Daten gleich sind

Wenn Sie dasselbe Datum sowohl für den Start- als auch für den Endparameter übergeben, gibt formatRange() ein einzelnes formatiertes Datum anstelle eines Bereichs aus.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const date = new Date(2024, 0, 1);

console.log(formatter.formatRange(date, date));
// Ausgabe: "January 1, 2024"

Der Formatierer erkennt, dass ein Bereich mit identischen Endpunkten nicht wirklich ein Bereich ist und formatiert ihn als einzelnes Datum. Dieses Verhalten gilt auch, wenn die Date-Objekte verschiedene Instanzen mit demselben Wert sind.

const formatter = new Intl.DateTimeFormat("en-US", {
  year: "numeric",
  month: "long",
  day: "numeric"
});

const start = new Date(2024, 0, 1, 10, 0);
const end = new Date(2024, 0, 1, 10, 0);

console.log(formatter.formatRange(start, end));
// Ausgabe: "January 1, 2024"

Obwohl es sich um separate Date-Objekte handelt, repräsentieren sie dasselbe Datum und dieselbe Uhrzeit. Der Formatierer gibt ein einzelnes Datum aus, da der Bereich auf der Präzisionsebene der Formatoptionen eine Dauer von null hat. Da das Format keine Zeitkomponenten enthält, sind die Uhrzeiten irrelevant und die Daten werden als gleich betrachtet.

Wann formatRange vs. manuelle Formatierung verwenden

Verwenden Sie formatRange(), wenn Sie Datumsbereiche für Benutzer anzeigen. Dies gilt für Buchungszeiträume, Veranstaltungsdauer, Berichtszeiträume, Verfügbarkeitsfenster oder andere Zeitspannen. Die Methode gewährleistet eine korrekte, regionsspezifische Formatierung und optimale Komponentenauslassung.

Vermeiden Sie formatRange(), wenn Sie mehrere unabhängige Daten anzeigen müssen. Eine Liste von Fristen wie "January 1, January 15, February 1" sollte reguläre format()-Aufrufe für jedes Datum verwenden, anstatt sie als Bereiche zu behandeln.

Vermeiden Sie formatRange() auch, wenn Sie Vergleiche oder Unterschiede zwischen Daten anzeigen. Wenn Sie anzeigen, wie viel früher oder später ein Datum im Vergleich zu einem anderen ist, stellt dies eine relative Zeitberechnung dar und keinen Bereich.