ISO8601DateFormatter: kluczowe pojęcia i formatowanie ISO 8601

Autor: IT Sectr Opublikowano: 2026-07-13 Czas czytania: 9 min

ISO8601DateFormatter — to klasa Foundation w iOS i macOS, przeznaczona do formatowania i parsowania dat w międzynarodowym standardzie ISO 8601. Według Apple Developer Documentation, 2024, ISO8601DateFormatter automatycznie obsługuje formaty z milisekundami, strefami czasowymi i ułamkami sekund bez konieczności ręcznego ustawiania DateFormat. W przeciwieństwie do DateFormatter, ta klasa nie zależy od Locale i TimeZone — działa ściśle według specyfikacji ISO 8601, co czyni ją idealną do wymiany dat między serwerem a klientem. Klasa jest dostępna od iOS 10 i macOS 10.12.

Najważniejsze

  • ISO8601DateFormatter — klasa Foundation do formatowania dat według standardu ISO 8601
  • Nie wymaga DateFormat — format jest określany automatycznie na podstawie ustawień opcji
  • Niezależny od lokalizacji — działa tak samo na wszystkich urządzeniach bez konfiguracji Locale
  • Obsługa milisekund — przetwarza ułamki sekund o dowolnej precyzji (trzy, sześć i więcej znaków)
  • Opcje formatowania — withFullDate, withTime, withMilliseconds, withTimeZone i inne zarządzają składowymi wyniku

Czym jest ISO8601DateFormatter?

ISO8601DateFormatter — to wyspecjalizowana podklasa Formatter w Foundation, implementująca dwukierunkową konwersję między Date a ciągiem znaków w formacie ISO 8601. Standard ISO 8601 (International Standard for the Representation of Dates and Times) określa międzynarodowy format wymiany dat i czasu: 2024-07-21T14:30:00+00:00. W przeciwieństwie do DateFormatter, ta klasa nie wymaga podawania dateFormat i automatycznie określa strukturę ciągu na podstawie zadanych opcji.

Główne zalety ISO8601DateFormatter w porównaniu z DateFormatter: brak zależności od locale (parsowanie działa tak samo na każdym urządzeniu), wbudowana obsługa ułamków sekund (z dowolną liczbą znaków po przecinku) i automatyczne określanie formatu na podstawie przekazanych opcji. Klasa poprawnie obsługuje również sufiks Z (oznaczenie UTC), strefy czasowe w formacie +HH:mm oraz zmniejszoną precyzję (tylko data bez czasu).

Według ISO Specification (ISO 8601-1:2019), standard obsługuje cztery poziomy precyzji: rok (2024), rok-miesiąc (2024-07), pełna data (2024-07-21) i data-czas ze strefą czasową (2024-07-21T14:30:00+00:00). ISO8601DateFormatter pokrywa wszystkie te poziomy poprzez kombinację opcji formatu, zwalniając programistę z ręcznego konstruowania ciągu dateFormat.

Jak działa ISO8601DateFormatter w Foundation?

Zasada działania ISO8601DateFormatter opiera się na kombinacji opcji bitowych (formatOptions), z których każda włącza określony komponent daty lub czasu w wyniku. Na przykład opcja .withFullDate włącza rok, miesiąc i dzień; .withTime — godziny, minuty i sekundy. Łącząc opcje, programista uzyskuje potrzebny poziom precyzji bez pisania ciągu dateFormat.

Wewnętrznie ISO8601DateFormatter używa biblioteki ICU do parsowania, ale ze stałymi regułami ISO 8601. Oznacza to, że ignoruje ustawienia Locale i TimeZone zainstalowane na urządzeniu — wynik jest zawsze przewidywalny. Do ustawienia strefy czasowej służy właściwość timeZone, która domyślnie równa się UTC. Jeśli timeZone jest ustawiony na nil, używany jest lokalny czas urządzenia.

OpcjaOpisPrzykład wyniku
.withFullDateRok, miesiąc, dzień2024-07-21
.withTimeGodziny, minuty, sekundy14:30:00
.withMillisecondsUłamki sekund (do 3 znaków).123
.withFractionalSecondsUłamki sekund (dowolna precyzja).123456
.withTimeZoneStrefa czasowa+03:00
.withColonSeparatorInTimeZoneSeparator : w strefie czasowej+03:00 (zamiast +0300)
.withInternetDateTimePełny format (date + time + tz)2024-07-21T14:30:00+00:00

Łączenie opcji: .withInternetDateTime jest równoważny połączeniu .withFullDate, .withTime i .withTimeZone. Do parsowania ciągów z milisekundami dodaj .withFractionalSeconds. Ważne jest, aby pamiętać, że .withMilliseconds ogranicza ułamki sekund do trzech znaków, a .withFractionalSeconds obsługuje dowolną precyzję — od jednej do dziewięciu cyfr po przecinku.

Ustawienia formatu ISO 8601

Opcje formatu ISO8601DateFormatter dzielą się na trzy grupy: komponenty daty (withFullDate, withYear, withMonth, withDay, withWeekOfYear), komponenty czasu (withTime, withHours, withMinutes, withSeconds) i dodatkowe ustawienia (withMilliseconds, withFractionalSeconds, withTimeZone, withColonSeparatorInTimeZone, withDashSeparatorInDate, withFullTime). Łącząc je, można uzyskać praktycznie dowolny podformat ISO 8601.

Podstawowe kombinacje opcji

  • .withFullDate — tylko data: 2024-07-21. Do parsowania ciągów w formacie YYYY-MM-DD
  • .withFullDate + .withTime — data i czas bez strefy czasowej: 2024-07-21T14:30:00
  • .withInternetDateTime — pełny format: 2024-07-21T14:30:00Z lub 2024-07-21T14:30:00+03:00
  • .withInternetDateTime + .withFractionalSeconds — z ułamkami sekund: 2024-07-21T14:30:00.123456+00:00
  • .withFullDate + .withTime + .withTimeZone — pełny format bez dwukropków w tz: 2024-07-21T14:30:00+0300

Ważny niuans: .withFractionalSeconds i .withMilliseconds wzajemnie się wykluczają — jeśli ustawione są obie, stosowana jest .withFractionalSeconds. Do parsowania milisekund z danych serwerowych zaleca się .withFractionalSeconds, ponieważ wiele serwerów wysyła ułamki sekund z trzema, sześcioma lub dziewięcioma znakami, a .withFractionalSeconds obsługuje dowolną długość.

swift
import Foundation

// Konfiguruj ISO8601DateFormatter
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)

// Różne kombinacje opcji formatu
formatter.formatOptions = [.withFullDate]
let dateOnly = formatter.string(from: Date())
print("Data: \(dateOnly)")

formatter.formatOptions = [.withFullDate, .withTime]
let dateTime = formatter.string(from: Date())
print("DateTime: \(dateTime)")

formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let full = formatter.string(from: Date())
print("Pełny: \(full)")

// Parsuj string z milisekundami
let serverString = "2024-07-21T14:30:00.123456+03:00"
if let parsed = formatter.date(from: serverString) {
    print("Sparsowano: \(parsed)")
}

ISO8601DateFormatter w Swift: przykłady kodu

Podstawowe użycie ISO8601DateFormatter sprowadza się do utworzenia instancji, ustawienia timeZone (zaleca się UTC dla danych serwerowych) i formatOptions, po czym można wywołać string(from:) do formatowania i date(from:) do parsowania. W przeciwieństwie do DateFormatter, nie trzeba martwić się o Locale — klasa ignoruje ustawienia regionalne.

swift
import Foundation

let formatter = ISO8601DateFormatter()

// Parsuj różne formaty ISO 8601
let strings: [String] = [
    "2024-07-21T14:30:00Z",
    "2024-07-21T14:30:00+03:00",
    "2024-07-21T14:30:00.123Z",
    "2024-07-21"
]

for str in strings {
    if let autoParsed = formatter.date(from: str) {
        print("Sparsowano '\(str)': \(autoParsed)")
    } else {
        // Użyj withFullDate dla stringów tylko z datą
        formatter.formatOptions = [.withFullDate]
        if let fallback = formatter.date(from: str) {
            print("Fallback sparsowano '\(str)': \(fallback)")
        }
        formatter.formatOptions = [.withInternetDateTime]
    }
}

// Serializuj do RFC 3339 (API GitHub)
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let rfc3339 = formatter.string(from: Date())
print("RFC 3339: \(rfc3339)")

Parsowanie dat z ułamkowymi sekundami o zmiennej długości — cecha wielu nowoczesnych API. Serwer może przesłać zarówno 2024-07-21T14:30:00.123Z (3 znaki), jak i 2024-07-21T14:30:00.123456Z (6 znaków). ISO8601DateFormatter z opcją .withFractionalSeconds poprawnie obsłuży oba warianty, a DateFormatter z dateFormat = „yyyy-MM-dd’T’HH:mm:ss.SSSZ” — tylko trzycyfrowe milisekundy.

swift
import Foundation

let variantFormatter = ISO8601DateFormatter()
variantFormatter.formatOptions = [
    .withInternetDateTime,
    .withFractionalSeconds
]

// Różna precyzja ułamków sekund
let variants: [String] = [
    "2024-07-21T14:30:00.1Z",
    "2024-07-21T14:30:00.12Z",
    "2024-07-21T14:30:00.123Z",
    "2024-07-21T14:30:00.123456Z",
    "2024-07-21T14:30:00.123456789Z"
]

for variant in variants {
    if let parsed = variantFormatter.date(from: variant) {
        print("OK: \(variant) -> \(parsed)")
    } else {
        print("FAIL: \(variant)")
    }
}

// Użyj withMilliseconds (tylko 3 cyfry)
variantFormatter.formatOptions = [
    .withInternetDateTime,
    .withMilliseconds
]
let milliParsed = variantFormatter.string(from: Date())
print("Z milisekundami: \(milliParsed)")

Testowanie parsowania wszystkich wariantów: powyższy kod demonstruje, że ISO8601DateFormatter z .withFractionalSeconds skutecznie przetwarza ułamki sekund o dowolnej długości od 1 do 9 znaków. Jest to ważne dla kompatybilności z różnymi platformami serwerowymi: .NET często generuje 7 znaków (tiki 100-nanosekundowe), Python — 6, Java — 3 lub 9 w zależności od wersji.

Porównanie z DateFormatter dla ISO 8601

DateFormatter również może parsować ISO 8601, ale wymaga ręcznego ustawienia dateFormat, locale i timeZone. Główny problem polega na tym, że DateFormatter zależy od Locale, a jeśli nie ustawisz en_US_POSIX, parsowanie może się zepsuć u użytkowników z regionów o niestandardowych formatach dat. ISO8601DateFormatter rozwiązuje ten problem na poziomie architektury: nie używa Locale.

ParametrISO8601DateFormatterDateFormatter
Konfiguracja LocaleNie wymagana (ignoruje)Wymagany en_US_POSIX
DateFormatAutomatyczny (przez opcje)Ręczny ciąg format
Ułamkowe sekundyDowolna precyzja (.withFractionalSeconds)Stała SSS
Sufiks ZPoprawnie obsługujePrzez dateFormat
WydajnośćWyższa (wyspecjalizowany)Niższa (ogólny)
StandardTylko ISO 8601Dowolny format
Wersja iOSiOS 10+iOS 2+

Kiedy używać DateFormatter: jeśli potrzebujesz sformatować datę w formacie innym niż ISO 8601 (na przykład „21 lipca 2024 r.” dla UI) lub jeśli wymagane jest wsparcie dla iOS 9 i starszych. Do wszystkich zadań wymiany dat z serwerem używaj ISO8601DateFormatter — jest bezpieczniejszy, wydajniejszy i wymaga mniej kodu. DateFormatter dla ISO 8601 to źródło potencjalnych błędów związanych z locale i ustawieniami regionalnymi.

Migracja z DateFormatter na ISO8601DateFormatter: zastąp utworzenie DateFormatter + konfigurację dateFormat + locale + timeZone utworzeniem ISO8601DateFormatter + konfiguracją formatOptions + timeZone. Parsowanie ciągu pozostaje niezmienne przez date(from:). Dla kompatybilności wstecznej można użyć #available(iOS 10, *) z fallback na DateFormatter.

Typowe błędy przy parsowaniu ISO 8601

Zapomniane ustawienie formatOptions powoduje, że formatter używa wartości domyślnej — .withInternetDateTime. Jeśli serwer przysyła tylko datę bez czasu (2024-07-21), parsowanie zwróci nil. Zawsze sprawdzaj, czy formatOptions pokrywają wszystkie możliwe formaty, które mogą nadejść z serwera. Dla API ze zmiennymi formatami używaj prób fallback z różnymi kombinacjami opcji.

Mylenie withMilliseconds z withFractionalSeconds — częsty błąd przy parsowaniu dat z ułamkami sekund. withMilliseconds oczekuje dokładnie 3 cyfr po przecinku. Jeśli serwer przysyła 6 cyfr (mikrosekundy), parsowanie z withMilliseconds zakończy się błędem. Używaj .withFractionalSeconds dla kompatybilności z dowolną liczbą znaków. .withFractionalSeconds pojawił się w iOS 13; dla starszych wersji używaj DateFormatter z dateFormat.

Ignorowanie strefy czasowej — kolejny częsty problem. Jeśli serwer przysyła datę ze strefą czasową (+03:00), a formatter jest ustawiony na UTC, parsowanie nie ulegnie awarii, ale wynik będzie w UTC. Deweloperzy często oczekują, że Date zachowa strefę czasową, ale Date to absolutny moment w czasie, nie przechowuje informacji o strefie czasowej. Do poprawnego wyświetlania zapisuj strefę czasową osobno lub używaj ISO8601DateFormatter z prawidłowym timeZone.

Według Apple Forum (2024), około 20% pytań dotyczących ISO8601DateFormatter dotyczy formatu, w którym sekundy są opcjonalne. Standard ISO 8601 dopuszcza format bez sekund: 2024-07-21T14:30+03:00. ISO8601DateFormatter z .withInternetDateTime nie obsługuje tego formatu — do jego parsowania potrzebny będzie DateFormatter z dateFormat = „yyyy-MM-dd’T’HH:mmZ”. To ograniczenie należy uwzględnić podczas pracy z API używającymi skróconego formatu czasu.

Często zadawane pytania

Czym jest ISO8601DateFormatter?

ISO8601DateFormatter — wyspecjalizowana klasa Foundation do formatowania i parsowania dat w formacie ISO 8601, dostępna od iOS 10. Automatycznie obsługuje standardowe formaty bez ręcznego podawania dateFormat.

Czym ISO8601DateFormatter różni się od DateFormatter?

ISO8601DateFormatter nie zależy od Locale, używa opcji zamiast dateFormat i poprawnie obsługuje ułamki sekund o dowolnej długości. DateFormatter jest uniwersalny, ale wymaga ręcznej konfiguracji i jest podatny na błędy związane z ustawieniami regionalnymi.

Jak obsługiwać ułamki sekund o zmiennej długości?

Użyj opcji .withFractionalSeconds — obsługuje od 1 do 9 znaków po przecinku. Nie używaj .withMilliseconds, jeśli precyzja może się różnić. .withFractionalSeconds jest dostępny od iOS 13.

Jakiej strefy czasowej używa ISO8601DateFormatter?

Domyślnie UTC. Aby ją zmienić, ustaw właściwość timeZone. Jeśli timeZone = nil, używany jest lokalny czas urządzenia. Podczas parsowania ciągu z jawną strefą czasową w formacie +HH:MM formatter uwzględnia ją automatycznie.

Dlaczego parsowanie daty bez czasu zwraca nil?

Ponieważ formatOptions domyślnie = .withInternetDateTime, który oczekuje daty + czasu + strefy czasowej. Do parsowania tylko daty ustaw formatOptions = [.withFullDate]. Aby obsłużyć oba warianty, użyj fallback z różnymi opcjami.

Podsumowanie

  • ISO8601DateFormatter — wyspecjalizowana klasa dla ISO 8601, bezpieczniejsza i prostsza niż DateFormatter
  • Opcje formatu zastępują ręczny dateFormat — łącz .withFullDate, .withTime, .withTimeZone
  • Nie zależy od Locale — parsowanie działa tak samo na wszystkich urządzeniach bez konfiguracji locale
  • .withFractionalSeconds obsługuje ułamki sekund o dowolnej precyzji (1–9 znaków)
  • DateFormatter traci na wydajności, bezpieczeństwie i prostocie dla zadań ISO 8601
  • Mylenie opcji — withMilliseconds i withFractionalSeconds nie są wymienne
  • Format bez sekund (2024-07-21T14:30+03:00) nie jest obsługiwany — potrzebny DateFormatter

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również