Szczegółowy przewodnik po Temporal API w JavaScript – nowoczesnym rozwiązaniu do efektywnego zarządzania datami i czasem w różnych kontekstach międzynarodowych.
Temporal API w JavaScript: Nowoczesne zarządzanie datą i czasem dla globalnej publiczzności
Obiekt `Date` w JavaScript od dawna był źródłem frustracji dla deweloperów. Jego mutowalność, niespójne API i słabe wsparcie dla stref czasowych doprowadziły do powstania licznych bibliotek, takich jak Moment.js i date-fns, które miały wypełnić te luki. Teraz, dzięki Temporal API, JavaScript oferuje nowoczesne, wbudowane rozwiązanie do obsługi dat i czasu z lepszą przejrzystością i precyzją. Ten artykuł stanowi kompleksowy przegląd Temporal API, koncentrując się na jego funkcjach, korzyściach i zastosowaniu w różnorodnych kontekstach międzynarodowych.
Czym jest Temporal API?
Temporal API to nowy, globalny obiekt w JavaScript, zaprojektowany w celu rozwiązania problemów obiektu `Date`. Zapewnia on czyste, niemutowalne API do pracy z datami, czasem, strefami czasowymi i systemami kalendarzowymi. Co kluczowe, ma na celu przedstawienie koncepcji daty i czasu w sposób, który jest bardziej zgodny z rzeczywistym użyciem i oczekiwaniami, co znacznie ułatwia internacjonalizację.
Kluczowe cechy:
- Niezmienność (Immutability): Obiekty Temporal są niemutowalne, co oznacza, że operacje takie jak dodawanie dni czy miesięcy zwracają nowe obiekty, zamiast modyfikować oryginalne. Eliminuje to częste źródło błędów i sprawia, że kod jest łatwiejszy do zrozumienia.
- Przejrzyste API: Temporal dostarcza spójne i intuicyjne API do typowych operacji na dacie i czasie.
- Wsparcie dla stref czasowych: Temporal oferuje solidne wsparcie dla stref czasowych, umożliwiając pracę z datami i czasem w różnych lokalizacjach bez złożoności starego obiektu `Date`. Korzysta z bazy danych stref czasowych IANA, zapewniając dokładne i aktualne informacje.
- Systemy kalendarzowe: Poza kalendarzem gregoriańskim, Temporal wspiera alternatywne systemy kalendarzowe, odpowiadając na potrzeby różnych kultur i regionów.
- Zwiększona precyzja: Temporal oferuje precyzję na poziomie nanosekund, rozwiązując ograniczenia obiektu `Date` opartego na milisekundach.
Podstawowe obiekty Temporal
Temporal API wprowadza kilka nowych typów obiektów. Oto niektóre z najważniejszych:
- `Temporal.PlainDate`: Reprezentuje datę (rok, miesiąc, dzień) bez strefy czasowej.
- `Temporal.PlainTime`: Reprezentuje czas (godzina, minuta, sekunda, milisekunda, mikrosekunda, nanosekunda) bez daty i strefy czasowej.
- `Temporal.PlainDateTime`: Reprezentuje datę i czas bez strefy czasowej.
- `Temporal.ZonedDateTime`: Reprezentuje datę i czas w określonej strefie czasowej.
- `Temporal.Instant`: Reprezentuje określony moment w czasie, mierzony w nanosekundach od epoki Uniksa (1 stycznia 1970 UTC).
- `Temporal.TimeZone`: Reprezentuje strefę czasową.
- `Temporal.Duration`: Reprezentuje okres czasu (np. 2 godziny, 30 minut).
- `Temporal.YearMonth`: Reprezentuje rok i miesiąc.
- `Temporal.MonthDay`: Reprezentuje miesiąc i dzień.
Praca z datami
Tworzenie `Temporal.PlainDate`
Aby utworzyć `Temporal.PlainDate`, możesz użyć konstruktora:
const plainDate = new Temporal.PlainDate(2024, 10, 27); // Rok, Miesiąc (1-12), Dzień
console.log(plainDate.toString()); // Wynik: 2024-10-27
Możesz także użyć metody `from`, która akceptuje ciąg znaków w formacie ISO 8601:
const plainDateFromString = Temporal.PlainDate.from('2024-10-27');
console.log(plainDateFromString.toString()); // Wynik: 2024-10-27
Pobieranie składników daty
Możesz uzyskać dostęp do poszczególnych składników daty za pomocą właściwości takich jak `year`, `month` i `day`:
console.log(plainDate.year); // Wynik: 2024
console.log(plainDate.month); // Wynik: 10
console.log(plainDate.day); // Wynik: 27
Arytmetyka na datach
Aby dodać lub odjąć dni, tygodnie, miesiące lub lata, użyj metod `plus` i `minus`. Metody te zwracają nowy obiekt `Temporal.PlainDate`:
const nextWeek = plainDate.plus({ days: 7 });
console.log(nextWeek.toString()); // Wynik: 2024-11-03
const lastMonth = plainDate.minus({ months: 1 });
console.log(lastMonth.toString()); // Wynik: 2024-09-27
Porównywanie dat
Możesz porównywać daty za pomocą metody `compare`:
const date1 = new Temporal.PlainDate(2024, 10, 27);
const date2 = new Temporal.PlainDate(2024, 11, 15);
console.log(Temporal.PlainDate.compare(date1, date2)); // Wynik: -1 (date1 jest wcześniejsza niż date2)
Praca z czasem
Tworzenie `Temporal.PlainTime`
Aby utworzyć `Temporal.PlainTime`, użyj konstruktora:
const plainTime = new Temporal.PlainTime(10, 30, 0); // Godzina, Minuta, Sekunda
console.log(plainTime.toString()); // Wynik: 10:30:00
Lub użyj metody `from` z ciągiem znaków czasu w formacie ISO 8601:
const plainTimeFromString = Temporal.PlainTime.from('10:30:00');
console.log(plainTimeFromString.toString()); // Wynik: 10:30:00
Pobieranie składników czasu
console.log(plainTime.hour); // Wynik: 10
console.log(plainTime.minute); // Wynik: 30
console.log(plainTime.second); // Wynik: 0
Arytmetyka na czasie
const later = plainTime.plus({ minutes: 15 });
console.log(later.toString()); // Wynik: 10:45:00
Praca z datą i czasem jednocześnie
Tworzenie `Temporal.PlainDateTime`
Możesz utworzyć `Temporal.PlainDateTime` bezpośrednio lub łącząc `Temporal.PlainDate` i `Temporal.PlainTime`:
const plainDateTime = new Temporal.PlainDateTime(2024, 10, 27, 10, 30, 0);
console.log(plainDateTime.toString()); // Wynik: 2024-10-27T10:30:00
const date = new Temporal.PlainDate(2024, 10, 27);
const time = new Temporal.PlainTime(10, 30, 0);
const combinedDateTime = date.toPlainDateTime(time);
console.log(combinedDateTime.toString()); // Wynik: 2024-10-27T10:30:00
Strefy czasowe
Prawidłowa obsługa stref czasowych jest kluczowa dla aplikacji, które mają do czynienia z użytkownikami w różnych lokalizacjach. Temporal API zapewnia solidne wsparcie dla stref czasowych za pośrednictwem obiektów `Temporal.ZonedDateTime` i `Temporal.TimeZone`.
Tworzenie `Temporal.ZonedDateTime`
Aby utworzyć `Temporal.ZonedDateTime`, potrzebujesz `Temporal.PlainDateTime` oraz identyfikatora strefy czasowej. Identyfikatory stref czasowych opierają się na bazie danych stref czasowych IANA (np. `America/Los_Angeles`, `Europe/London`, `Asia/Tokyo`).
const plainDateTime = new Temporal.PlainDateTime(2024, 10, 27, 10, 30, 0);
const timeZone = 'America/Los_Angeles';
const zonedDateTime = plainDateTime.toZonedDateTime(timeZone);
console.log(zonedDateTime.toString()); // Wynik: 2024-10-27T10:30:00-07:00[America/Los_Angeles] (Przesunięcie będzie zależeć od zasad czasu letniego)
Alternatywnie, utwórz `Temporal.ZonedDateTime` z obiektu `Instant`.
const instant = Temporal.Instant.fromEpochSeconds(1666866600); // Przykładowy znacznik czasu
const zonedDateTimeFromInstant = instant.toZonedDateTimeISO(timeZone); // Strefa czasowa, np. 'America/Los_Angeles'
console.log(zonedDateTimeFromInstant.toString());
Konwersja między strefami czasowymi
Możesz przekonwertować `Temporal.ZonedDateTime` na inną strefę czasową za pomocą metody `withTimeZone`:
const newTimeZone = 'Europe/London';
const zonedDateTimeInLondon = zonedDateTime.withTimeZone(newTimeZone);
console.log(zonedDateTimeInLondon.toString()); // Wynik: 2024-10-27T18:30:00+01:00[Europe/London]
Praca z przesunięciami stref czasowych
Metoda `getOffsetStringFor` obiektu `Temporal.TimeZone` zwraca ciąg znaków przesunięcia dla danego `Temporal.Instant`:
const timeZoneObject = new Temporal.TimeZone(timeZone);
const offsetString = timeZoneObject.getOffsetStringFor(zonedDateTime.toInstant());
console.log(offsetString); // Wynik: -07:00 (W zależności od zasad czasu letniego)
Kluczowe jest używanie poprawnych identyfikatorów stref czasowych IANA w celu uzyskania dokładnych obliczeń. Identyfikatory te są regularnie utrzymywane i aktualizowane, aby odzwierciedlać zmiany w czasie letnim i granicach stref czasowych.
Okresy czasu (Durations)
Obiekt `Temporal.Duration` reprezentuje okres czasu. Może być używany do dodawania lub odejmowania od dat i czasów.
Tworzenie `Temporal.Duration`
Możesz utworzyć `Temporal.Duration` za pomocą konstruktora, określając lata, miesiące, dni, godziny, minuty, sekundy, milisekundy, mikrosekundy i nanosekundy:
const duration = new Temporal.Duration(1, 2, 3, 4, 5, 6, 7, 8, 9); // Lata, Miesiące, Dni, Godziny, Minuty, Sekundy, Milisekundy, Mikrosekundy, Nanosekundy
console.log(duration.toString()); // Wynik: P1Y2M3DT4H5M6.007008009S
Lub używając ciągu znaków okresu w formacie ISO 8601:
const durationFromString = Temporal.Duration.from('P1Y2M3DT4H5M6S');
console.log(durationFromString.toString()); // Wynik: P1Y2M3DT4H5M6S
Dodawanie okresów czasu do dat i czasów
const plainDate = new Temporal.PlainDate(2024, 10, 27);
const duration = new Temporal.Duration(0, 0, 7); // 7 dni
const newDate = plainDate.plus(duration);
console.log(newDate.toString()); // Wynik: 2024-11-03
Należy pamiętać, że dodawanie okresów czasu obejmujących miesiące lub lata do dat wymaga ostrożności, ponieważ liczba dni w miesiącu lub roku może się różnić.
Systemy kalendarzowe
Temporal API obsługuje różne systemy kalendarzowe poza kalendarzem gregoriańskim. Jest to kluczowe dla aplikacji, które muszą obsługiwać daty w różnych kontekstach kulturowych. Chociaż wsparcie wciąż się rozwija, stanowi to fundament dla przyszłej rozbudowy.
Używanie alternatywnych kalendarzy
Aby użyć określonego kalendarza, możesz go zdefiniować podczas tworzenia obiektów Temporal:
const hebrewDate = new Temporal.PlainDate(5785, 1, 1, { calendar: 'hebrew' });
console.log(hebrewDate.toString()); // Konkretny wynik może się różnić w zależności od implementacji i formatowania. W momencie pisania tego tekstu wymaga polyfilla w wielu środowiskach.
Ważne: Wsparcie dla kalendarzy innych niż gregoriański może wymagać polyfilli lub specyficznego wsparcia przeglądarki/środowiska. Sprawdź najnowsze tabele kompatybilności przeglądarek i dokumentację Temporal API, aby uzyskać aktualne informacje.
Formatowanie dat i czasu
Chociaż Temporal API koncentruje się na manipulacji datą i czasem, formatowanie jest zazwyczaj obsługiwane przez obiekt `Intl.DateTimeFormat`, który jest częścią Internationalization API. Obiekty Temporal bezproblemowo współpracują z `Intl.DateTimeFormat`.
Używanie `Intl.DateTimeFormat`
Oto jak sformatować `Temporal.PlainDate` za pomocą `Intl.DateTimeFormat`:
const plainDate = new Temporal.PlainDate(2024, 10, 27);
const formatter = new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
console.log(formatter.format(plainDate)); // Wynik: October 27, 2024
const formatterGerman = new Intl.DateTimeFormat('de-DE', { year: 'numeric', month: 'long', day: 'numeric' });
console.log(formatterGerman.format(plainDate)); // Wynik: 27. Oktober 2024
Możesz dostosować opcje formatowania do swoich potrzeb. Pierwszym argumentem `Intl.DateTimeFormat` jest lokalizacja (locale), która określa język i regionalne konwencje używane do formatowania. Używanie różnych lokalizacji (np. 'en-US', 'de-DE', 'fr-FR', 'ja-JP') daje różne formaty wyjściowe.
Formatowanie `Temporal.ZonedDateTime`
Formatowanie `Temporal.ZonedDateTime` jest podobne, ale możesz również uwzględnić informacje o strefie czasowej w wyniku:
const plainDateTime = new Temporal.PlainDateTime(2024, 10, 27, 10, 30, 0);
const timeZone = 'America/Los_Angeles';
const zonedDateTime = plainDateTime.toZonedDateTime(timeZone);
const formatter = new Intl.DateTimeFormat('en-US', { year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', timeZoneName: 'short' });
console.log(formatter.format(zonedDateTime)); // Wynik: October 27, 2024, 10:30 AM PDT (Skrót strefy czasowej zależy od zasad czasu letniego)
Dobre praktyki internacjonalizacji
Pracując z datami i czasem w kontekście globalnym, należy pamiętać o następujących dobrych praktykach:
- Używaj identyfikatorów stref czasowych IANA: Zawsze używaj identyfikatorów stref czasowych IANA (np. `America/Los_Angeles`, `Europe/London`) w celu dokładnej obsługi stref czasowych.
- Bądź świadomy czasu letniego: Czas letni (DST) może wpływać na przesunięcia stref czasowych. Temporal API automatycznie obsługuje przejścia DST.
- Używaj `Intl.DateTimeFormat` do formatowania: Używaj obiektu `Intl.DateTimeFormat` do formatowania dat i czasu zgodnie z lokalizacją użytkownika.
- Rozważ systemy kalendarzowe: Jeśli Twoja aplikacja musi obsługiwać użytkowników w różnych kontekstach kulturowych, rozważ użycie alternatywnych systemów kalendarzowych.
- Przechowuj daty i czas w UTC: Przechowując daty i czas w bazie danych, najlepszą praktyką jest przechowywanie ich w UTC (Coordinated Universal Time), aby uniknąć problemów ze strefami czasowymi. Następnie konwertuj je na czas lokalny w celu wyświetlenia. Temporal dostarcza metody do konwersji do i z UTC.
- Testuj dokładnie: Testuj swoją aplikację z różnymi strefami czasowymi, lokalizacjami i systemami kalendarzowymi, aby upewnić się, że działa poprawnie dla wszystkich użytkowników.
Porównanie Temporal API z przestarzałym obiektem Date
Oto tabela podkreślająca kluczowe różnice i zalety Temporal API w porównaniu z przestarzałym obiektem `Date`:
Cecha | Przestarzały obiekt `Date` | Temporal API |
---|---|---|
Mutowalność | Mutowalny (modyfikuje oryginalny obiekt) | Niemutowalny (zwraca nowe obiekty) |
Wsparcie dla stref czasowych | Ograniczone i często problematyczne | Solidne i dokładne, oparte na bazie danych stref czasowych IANA |
API | Niespójne i trudne w użyciu | Przejrzyste, spójne i intuicyjne |
Precyzja | Milisekunda | Nanosekunda |
Systemy kalendarzowe | Ograniczone do gregoriańskiego | Wspiera alternatywne systemy kalendarzowe (ze wsparciem w fazie rozwoju) |
Internacjonalizacja | Wymaga zewnętrznych bibliotek do solidnej internacjonalizacji | Wbudowane wsparcie i bezproblemowa integracja z `Intl.DateTimeFormat` |
Wsparcie przeglądarek i polyfille
Jako stosunkowo nowe API, wsparcie przeglądarek dla Temporal API wciąż się rozwija. Sprawdź najnowsze tabele kompatybilności przeglądarek (np. na MDN Web Docs), aby zobaczyć, które przeglądarki i środowiska obsługują je natywnie. W przypadku starszych przeglądarek lub środowisk bez natywnego wsparcia można użyć polyfilli, aby zapewnić funkcjonalność Temporal API. Wyszukaj w internecie "Temporal API polyfill", aby znaleźć odpowiednie opcje.
Podsumowanie
Temporal API w JavaScript stanowi znaczący krok naprzód w obsłudze dat i czasu w JavaScript. Jego niezmienność, przejrzyste API, solidne wsparcie dla stref czasowych i możliwości systemów kalendarzowych czynią go potężnym narzędziem dla deweloperów tworzących aplikacje, które muszą pracować z datami i czasem w sposób dokładny i niezawodny w różnorodnych kontekstach międzynarodowych. Chociaż wsparcie przeglądarek wciąż się rozwija, korzyści płynące z Temporal API sprawiają, że warto się go uczyć i wdrażać w nowych projektach. Przyjmując Temporal API i stosując dobre praktyki internacjonalizacji, możesz tworzyć aplikacje, które zapewniają bezproblemowe i dokładne doświadczenie z datą i czasem dla użytkowników na całym świecie.