ISO8601DateFormatter: ключови понятия и форматиране ISO 8601

Автор: IT Sectr Публикувано: 2026-07-13 Време за четене: 9 мин

ISO8601DateFormatter — е клас Foundation в iOS и macOS, предназначен за форматиране и парсиране на дати в международния стандарт ISO 8601. Според Apple Developer Documentation, 2024, ISO8601DateFormatter автоматично обработва формати с милисекунди, часови зони и дробни части от секундата без необходимост от ръчно задаване на DateFormat. За разлика от DateFormatter, този клас не зависи от Locale и TimeZone — той работи строго по спецификацията ISO 8601, което го прави идеален за обмен на дати между сървър и клиент. Класът е достъпен от iOS 10 и macOS 10.12.

Основни точки

  • ISO8601DateFormatter — Foundation клас за форматиране на дати по стандарта ISO 8601
  • Не изисква DateFormat — форматът се определя автоматично от настройките на опциите
  • Независим от локализация — работи еднакво на всички устройства без настройка на Locale
  • Поддръжка на милисекунди — обработва дробни части от секундата с произволна точност (три, шест и повече знака)
  • Опции за форматиране — withFullDate, withTime, withMilliseconds, withTimeZone и други управляват компонентите на изхода

Какво е ISO8601DateFormatter?

ISO8601DateFormatter — е специализиран подклас на Formatter във Foundation, който имплементира двупосочна конверсия между Date и низ във формат ISO 8601. Стандартът ISO 8601 (International Standard for the Representation of Dates and Times) определя международния формат за обмен на дати и часове: 2024-07-21T14:30:00+00:00. За разлика от DateFormatter, този клас не изисква задаване на dateFormat и автоматично определя структурата на низа въз основа на зададените опции.

Основните предимства на ISO8601DateFormatter пред DateFormatter: липса на зависимост от locale (парсирането работи еднакво на всяко устройство), вградена поддръжка на дробни части от секундата (с произволен брой десетични знаци) и автоматично определяне на формата въз основа на предадените опции. Класът също така коректно обработва Z-суфикса (обозначение на UTC), часови зони във формат +HH:mm и намалена точност (само дата без час).

Според ISO Specification (ISO 8601-1:2019), стандартът поддържа четири нива на точност: година (2024), година-месец (2024-07), пълна дата (2024-07-21) и дата-час с часова зона (2024-07-21T14:30:00+00:00). ISO8601DateFormatter покрива всички тези нива чрез комбинация от опции за формат, освобождавайки разработчика от ръчно конструиране на dateFormat низ.

Как работи ISO8601DateFormatter във Foundation?

Принцип на работа на ISO8601DateFormatter се основава на комбинация от битови опции (formatOptions), всяка от които активира определен компонент на дата или час в изхода. Например опцията .withFullDate активира година, месец и ден; .withTime — часове, минути и секунди. Комбинирайки опции, разработчикът постига желаното ниво на точност без да пише dateFormat низ.

Вътрешно ISO8601DateFormatter използва ICU библиотека за парсиране, но с фиксирани ISO 8601 правила. Това означава, че игнорира настройките на Locale и TimeZone на устройството — резултатът винаги е предвидим. За настройка на часова зона се използва свойството timeZone, което по подразбиране е равно на UTC. Ако timeZone е зададен на nil, се използва локалното време на устройството.

ОпцияОписаниеПримерен изход
.withFullDateГодина, месец, ден2024-07-21
.withTimeЧасове, минути, секунди14:30:00
.withMillisecondsДробни части от секундата (до 3 знака).123
.withFractionalSecondsДробни части от секундата (произволна точност).123456
.withTimeZoneЧасова зона+03:00
.withColonSeparatorInTimeZoneРазделител : в часовата зона+03:00 (вместо +0300)
.withInternetDateTimeПълен формат (date + time + tz)2024-07-21T14:30:00+00:00

Комбиниране на опции: .withInternetDateTime е еквивалентен на комбинацията от .withFullDate, .withTime и .withTimeZone. За парсиране на низове с милисекунди добавете .withFractionalSeconds. Важно е да запомните, че .withMilliseconds ограничава дробните части от секундата до три знака, докато .withFractionalSeconds поддържа произволна точност — от една до девет цифри след десетичната запетая.

Настройки на формат ISO 8601

Опции за формат на ISO8601DateFormatter се делят на три групи: компоненти на дата (withFullDate, withYear, withMonth, withDay, withWeekOfYear), компоненти на час (withTime, withHours, withMinutes, withSeconds) и допълнителни настройки (withMilliseconds, withFractionalSeconds, withTimeZone, withColonSeparatorInTimeZone, withDashSeparatorInDate, withFullTime). Комбинирайки ги, може да се получи практически всеки подформат на ISO 8601.

Основни комбинации от опции

  • .withFullDate — само дата: 2024-07-21. За парсиране на низове във формат YYYY-MM-DD
  • .withFullDate + .withTime — дата и час без часова зона: 2024-07-21T14:30:00
  • .withInternetDateTime — пълен формат: 2024-07-21T14:30:00Z или 2024-07-21T14:30:00+03:00
  • .withInternetDateTime + .withFractionalSeconds — с дробни части от секундата: 2024-07-21T14:30:00.123456+00:00
  • .withFullDate + .withTime + .withTimeZone — пълен формат без двоеточие в tz: 2024-07-21T14:30:00+0300

Важен нюанс: .withFractionalSeconds и .withMilliseconds се изключват взаимно — ако и двете са зададени, се прилага .withFractionalSeconds. За парсиране на милисекунди от сървърни данни се препоръчва .withFractionalSeconds, тъй като много сървъри изпращат дробни части от секундата с три, шест или девет знака, а .withFractionalSeconds обработва произволна дължина.

swift
import Foundation

// Конфигурирай ISO8601DateFormatter
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)

// Различни комбинации от опции за формат
formatter.formatOptions = [.withFullDate]
let dateOnly = formatter.string(from: Date())
print("Дата: \(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("Пълен: \(full)")

// Парсирай низ с милисекунди
let serverString = "2024-07-21T14:30:00.123456+03:00"
if let parsed = formatter.date(from: serverString) {
    print("Парсирано: \(parsed)")
}

ISO8601DateFormatter в Swift: примери за код

Основна употреба на ISO8601DateFormatter се свежда до създаване на инстанция, задаване на timeZone (препоръчва се UTC за сървърни данни) и formatOptions, след което може да се извика string(from:) за форматиране и date(from:) за парсиране. За разлика от DateFormatter, не е нужно да се тревожите за Locale — класът игнорира регионалните настройки.

swift
import Foundation

let formatter = ISO8601DateFormatter()

// Парсирай различни 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("Парсирано '\(str)': \(autoParsed)")
    } else {
        // Използвай withFullDate за низове само с дата
        formatter.formatOptions = [.withFullDate]
        if let fallback = formatter.date(from: str) {
            print("Fallback парсирано '\(str)': \(fallback)")
        }
        formatter.formatOptions = [.withInternetDateTime]
    }
}

// Сериализирай към RFC 3339 (GitHub API)
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let rfc3339 = formatter.string(from: Date())
print("RFC 3339: \(rfc3339)")

Парсиране на дати с дробни секунди с променлива дължина — характеристика на много съвременни API. Сървърът може да изпрати както 2024-07-21T14:30:00.123Z (3 знака), така и 2024-07-21T14:30:00.123456Z (6 знака). ISO8601DateFormatter с опция .withFractionalSeconds ще обработи правилно и двата варианта, докато DateFormatter с dateFormat = „yyyy-MM-dd’T’HH:mm:ss.SSSZ” — само трицифрени милисекунди.

swift
import Foundation

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

// Различна точност на дробни секунди
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)")
    }
}

// Използвай withMilliseconds (само 3 цифри)
variantFormatter.formatOptions = [
    .withInternetDateTime,
    .withMilliseconds
]
let milliParsed = variantFormatter.string(from: Date())
print("С милисекунди: \(milliParsed)")

Тестване на парсиране на всички варианти: горният код демонстрира, че ISO8601DateFormatter с .withFractionalSeconds успешно обработва дробни части от секундата с произволна дължина от 1 до 9 знака. Това е важно за съвместимост с различни сървърни платформи: .NET често генерира 7 знака (100-наносекундни тикове), Python — 6, Java — 3 или 9 в зависимост от версията.

Сравнение с DateFormatter за ISO 8601

DateFormatter също може да парсира ISO 8601, но изисква ръчно задаване на dateFormat, locale и timeZone. Основният проблем е, че DateFormatter зависи от Locale и ако не се зададе en_US_POSIX, парсирането може да се счупи при потребители от региони с нестандартни формати на дати. ISO8601DateFormatter решава този проблем на архитектурно ниво: не използва Locale.

ПараметърISO8601DateFormatterDateFormatter
Настройка на LocaleНе е необходима (игнорира)en_US_POSIX задължителен
DateFormatАвтоматичен (чрез опции)Ръчен форматиращ низ
Дробни секундиПроизволна точност (.withFractionalSeconds)Фиксиран SSS
Z-суфиксКоректно обработваЧрез dateFormat
ПроизводителностПо-висока (специализиран)По-ниска (общ)
СтандартСамо ISO 8601Произволен формат
iOS версияiOS 10+iOS 2+

Кога да използвате DateFormatter: ако трябва да форматирате дата в не-ISO 8601 формат (например „21 юли 2024 г.” за UI) или ако се изисква поддръжка на iOS 9 и по-стари. За всички задачи за обмен на дати със сървъра използвайте ISO8601DateFormatter — той е по-безопасен, по-производителен и изисква по-малко код. DateFormatter за ISO 8601 е източник на потенциални грешки, свързани с locale и регионални настройки.

Миграция от DateFormatter към ISO8601DateFormatter: заменете създаването на DateFormatter + настройка на dateFormat + locale + timeZone със създаване на ISO8601DateFormatter + настройка на formatOptions + timeZone. Парсирането на низа остава непроменено чрез date(from:). За обратна съвместимост можете да използвате #available(iOS 10, *) с fallback към DateFormatter.

Типични грешки при парсиране на ISO 8601

Забравена настройка на formatOptions води до това, че formatter използва стойността по подразбиране — .withInternetDateTime. Ако сървърът изпраща само дата без час (2024-07-21), парсирането ще върне nil. Винаги проверявайте дали formatOptions покрива всички възможни формати, които могат да дойдат от сървъра. За API с променливи формати използвайте fallback опити с различни комбинации от опции.

Объркване между withMilliseconds и withFractionalSeconds — честа грешка при парсиране на дати с дробни части от секундата. withMilliseconds очаква точно 3 цифри след десетичната запетая. Ако сървърът изпраща 6 цифри (микросекунди), парсирането с withMilliseconds ще се провали. Използвайте .withFractionalSeconds за съвместимост с произволен брой знаци. .withFractionalSeconds се появи в iOS 13; за по-стари версии използвайте DateFormatter с dateFormat.

Игнориране на часовата зона — друг често срещан проблем. Ако сървърът изпраща дата с часова зона (+03:00) и formatter е настроен на UTC, парсирането няма да се провали, но резултатът ще бъде в UTC. Разработчиците често очакват, че Date ще запази часовата зона, но Date е абсолютен момент във времето и не съхранява информация за часова зона. За правилно показване запазете часовата зона отделно или използвайте ISO8601DateFormatter с правилен timeZone.

Според Apple Forum (2024), около 20% от въпросите относно ISO8601DateFormatter са свързани с формат, в който секундите са опционални. Стандартът ISO 8601 позволява формат без секунди: 2024-07-21T14:30+03:00. ISO8601DateFormatter с .withInternetDateTime не поддържа този формат — за парсирането му е необходим DateFormatter с dateFormat = „yyyy-MM-dd’T’HH:mmZ”. Това ограничение трябва да се вземе предвид при работа с API, които използват съкратен формат за време.

Често задавани въпроси

Какво е ISO8601DateFormatter?

ISO8601DateFormatter — специализиран Foundation клас за форматиране и парсиране на дати във формат ISO 8601, достъпен от iOS 10. Автоматично обработва стандартни формати без ръчно задаване на dateFormat.

С какво ISO8601DateFormatter се различава от DateFormatter?

ISO8601DateFormatter не зависи от Locale, използва опции вместо dateFormat и коректно обработва дробни части от секундата с произволна дължина. DateFormatter е универсален, но изисква ръчна настройка и е податлив на грешки, свързани с регионални настройки.

Как да обработваме дробни части от секундата с променлива дължина?

Използвайте опцията .withFractionalSeconds — поддържа от 1 до 9 знака след десетичната запетая. Не използвайте .withMilliseconds, ако точността може да варира. .withFractionalSeconds е достъпен от iOS 13.

Коя часова зона използва ISO8601DateFormatter?

По подразбиране UTC. За промяна задайте свойството timeZone. Ако timeZone = nil, се използва локалното време на устройството. При парсиране на низ с изрична часова зона във формат +HH:MM, formatter я взема предвид автоматично.

Защо парсирането на дата без час връща nil?

Защото formatOptions по подразбиране = .withInternetDateTime, който очаква дата + час + часова зона. За парсиране само на дата задайте formatOptions = [.withFullDate]. За поддръжка на двата варианта използвайте fallback с различни опции.

Резюме

  • ISO8601DateFormatter — специализиран клас за ISO 8601, по-безопасен и по-прост от DateFormatter
  • Опции за формат заместват ръчния dateFormat — комбинирайте .withFullDate, .withTime, .withTimeZone
  • Не зависи от Locale — парсирането работи еднакво на всички устройства без настройка на locale
  • .withFractionalSeconds обработва дробни части от секундата с произволна точност (1–9 знака)
  • DateFormatter губи по производителност, безопасност и простота за задачи ISO 8601
  • Объркване на опции — withMilliseconds и withFractionalSeconds не са взаимозаменяеми
  • Формат без секунди (2024-07-21T14:30+03:00) не се поддържа — необходим е DateFormatter

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също