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: одсуство зависности од локалитета (парсирање ради исто на било ком уређају), уграђена подршка за разломке секунди (са било којим бројем децимала) и аутоматско одређивање формата на основу прослеђених опција. Класа такође коректно обрађује 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Аутоматски (кроз опције)Ручни низ format
Разломци секундиБило која прецизност (.withFractionalSeconds)Фиксни SSS
Z-суфиксКоректно обрађујеКроз dateFormat
ПерформансеВише (специјализован)Мање (општи)
СтандардСамо ISO 8601Било који формат
iOS верзијаiOS 10+iOS 2+

Када користити DateFormatter: ако је потребно форматирати датум у не-ISO 8601 формату (на пример, „21. јул 2024.” за UI) или ако је потребна подршка за iOS 9 и старије. За све задатке размене датума са сервером користите ISO8601DateFormatter — сигурнији је, перформантнији и захтева мање кода. DateFormatter за ISO 8601 је извор потенцијалних грешака везаних за локалитет и регионална подешавања.

Миграција са 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 — парсирање ради исто на свим уређајима без подешавања локалитета
  • .withFractionalSeconds обрађује разломке секунди било које прецизности (1–9 знакова)
  • DateFormatter губи у перформансама, сигурности и једноставности за ISO 8601 задатке
  • Мешање опција — withMilliseconds и withFractionalSeconds нису заменљиви
  • Формат без секунди (2024-07-21T14:30+03:00) није подржан — потребан је DateFormatter

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође