TimeZone — що це, клас Foundation та часові пояси

Автор: IT Sectr Опубліковано: 2026-07-12 Час читання: 9 хв

TimeZone — це клас Foundation в iOS та macOS, який абстрагує інформацію про часові пояси для коректного перетворення часу між географічними регіонами. За даними Apple Developer Documentation, 2024, TimeZone надає методи для роботи з ідентифікаторами часових поясів (IANA Time Zone Database), зміщеннями відносно UTC та правилами переходу на літній час. Клас інтегрований з DateFormatter та Calendar, забезпечуючи автоматичне застосування правильного часового поясу при форматуванні дат. На відміну від ручного розрахунку зміщення, TimeZone автоматично оновлює дані при зміні часового поясу пристрою.

Головне

  • TimeZone — клас Foundation для роботи з часовими поясами в iOS та macOS
  • IANA Time Zone Database — основне джерело ідентифікаторів часових поясів (America/New_York, Europe/Moscow)
  • Автоматична корекція — TimeZone враховує перехід на літній час без додаткового коду
  • Інтеграція з DateFormatter — часовий пояс застосовується автоматично при форматуванні дат
  • Три типи — локальний (поточний), фіксований (заданий ідентифікатором) та UTC

Що таке TimeZone в Foundation?

TimeZone — це value-тип в Swift, який надає інформацію про географічний часовий пояс: зміщення відносно UTC, назву, абревіатуру та правила переходу на літній час. В Objective-C клас називається NSTimeZone. Обидва класи спираються на IANA Time Zone Database (також відому як база даних Olson), яка містить історію змін часових поясів з 1970 року.

Кожен екземпляр TimeZone зберігає ідентифікатор часового поясу (наприклад, Europe/Moscow), поточне зміщення в секундах від UTC, прапорець isDaylightSavingTime та дату наступного переходу. Ідентифікатор є первинним ключем: при ініціалізації TimeZone(identifier:) система завантажує відповідний запис з бази даних часових поясів пристрою.

За даними IANA (2024), база даних містить понад 600 унікальних ідентифікаторів часових поясів. Apple постачає знімок цієї бази даних в складі кожної версії iOS та macOS, що гарантує єдність розрахунків на всіх пристроях без необхідності мережевих запитів.

Як працює TimeZone в iOS та macOS?

Архітектура TimeZone в Foundation побудована на дворівневій системі: ідентифікатор часового поясу (людиночитана назва) та його числове представлення (зміщення від UTC). Система автоматично вибирає поточний часовий пояс з налаштувань пристрою, але розробник може перевизначити його для конкретних операцій форматування.

TimeZone тісно пов’язаний з Calendar та DateFormatter. При форматуванні дати DateFormatter використовує властивість timeZone екземпляра TimeZone для перетворення абсолютного моменту часу (Date) у рядкове представлення в потрібному часовому поясі. Якщо timeZone не задано, використовується системний часовий пояс за замовчуванням — TimeZone.current.

Типи екземплярів TimeZone

ТипІніціалізаціяОсобливості
ПоточнийTimeZone.currentАвтоматично оновлюється при зміні регіону в налаштуваннях, відстежує перехід на літній час
ФіксованийTimeZone(identifier:)Не залежить від регіону пристрою. Постійно застосовує вибраний ідентифікатор
UTCTimeZone(secondsFromGMT: 0)Часовий пояс без корекції. Ідентифікатор: GMT
З довільним зміщеннямTimeZone(secondsFromGMT: 10800)Фіксоване зміщення в секундах. Не враховує літній час

Важливий нюанс: TimeZone(identifier:) повертає nil для невідомих ідентифікаторів. Це часта причина падіння додатку — розробники забувають обробити опціональне значення, передаючи невірний ідентифікатор з користувацького вводу. Для ідентифікаторів IANA регістр має значення: Europe/Moscow — коректно, europe/moscow — nil.

Формати ідентифікаторів часових поясів

IANA Time Zone Database використовує формат «Регіон/Місто» (Continent/City), де регіон — один з континентів (Africa, America, Asia, Atlantic, Australia, Europe, Indian, Pacific) або океан, а місто — найбільший населений пункт в зоні дії часового поясу. Цей формат гарантує унікальність та читабельність ідентифікатора.

Крім основного формату, TimeZone підтримує три додаткових способи ідентифікації: абревіатури (MSK, EST, PST), трибуквені коди часових зон (GMT, UTC) та числові зміщення (+0300, -0500). Однак абревіатури неоднозначні: EST може означати як Eastern Standard Time (GMT-5), так і Eastern Summer Time (GMT+10) в Австралії. Apple рекомендує використовувати виключно IANA-ідентифікатори.

swift
import Foundation

// Отримати всі відомі ідентифікатори часових поясів
let allIdentifiers: [String] = TimeZone.knownTimeZoneIdentifiers
print("Всього часових поясів: \(allIdentifiers.count)")

// Фільтрувати за регіоном
let europeZones = allIdentifiers.filter { $0.hasPrefix("Europe/") }
print("Європейські часові пояси: \(europeZones)")

// Абревіатури (не рекомендовано для продакшну)
if let moscowTimeZone = TimeZone(abbreviation: "MSK") {
    print("Секунд MSK від GMT: \(moscowTimeZone.secondsFromGMT())")
}

// Знайти ідентифікатор за зміщенням
let utcPlus3 = TimeZone(secondsFromGMT: 10800)
print("Ідентифікатор: \(utcPlus3.identifier)")

Абревіатури в TimeZone.abbreviationDictionary містять скорочення для всіх відомих часових поясів, але цей словник не гарантує унікальність: ключ PST може відповідати як America/Los_Angeles, так і Pacific/Pago_Pago. Для production-коду завжди використовуйте ідентифікатори IANA.

Перехід на літній час та TimeZone

TimeZone автоматично враховує перехід на літній та зимовий час (DST — Daylight Saving Time) для всіх регіонів, де це прийнято. Система використовує історичні дані з IANA Time Zone Database, які включають точні дати переходів для кожного часового поясу. Властивість isDaylightSavingTime повертає true, якщо часовий пояс в даний момент знаходиться в літньому часі.

Метод nextDaylightSavingTimeTransition дозволяє дізнатися дату наступного переходу, що корисно для планування подій в майбутньому. Особливо важлива ця функціональність для регіонів з частими змінами правил DST, таких як Бразилія чи Марокко — до 2024 року Бразилія щорічно змінювала дати переходу, і ручний розрахунок призводив до помилок в додатках.

За даними Apple WWDC 2023, бібліотека ICU (International Components for Unicode), що лежить в основі Foundation, оновлює дані DST при кожному оновленні iOS. Додатки не повинні кешувати дані про літній час довше, ніж на один день після оновлення системи — база IANA може змінитися навіть без оновлення версії ОС через коригування часових поясів.

swift
import Foundation

// Перевірити DST для Europe/Moscow
let moscow = TimeZone(identifier: "Europe/Moscow")!
let now = Date()
let isMoscowDST = moscow.isDaylightSavingTime(for: now)
print("Москва зараз у DST: \(isMoscowDST)")

// Отримати дату наступного переходу DST
if let nextTransition = moscow.nextDaylightSavingTimeTransition(
    after: now
) {
    let dstOffset = moscow.daylightSavingTimeOffset(
        for: nextTransition
    )
    print("Наступний перехід: \(nextTransition), зміщення DST: \(dstOffset)s")
}

// Безпечне перетворення з урахуванням DST
let newYork = TimeZone(identifier: "America/New_York")!
let offsetNY = newYork.secondsFromGMT(for: now)
print("Поточне зміщення NY: \(offsetNY / 3600)h")

Критичний нюанс: secondsFromGMT(for:) враховує DST для вказаної дати, а secondsFromGMT() — тільки для поточного часу. При форматуванні історичних дат завжди використовуйте версію з параметром Date: secondsFromGMT(for: someHistoricalDate). Різниця може досягати 1–2 годин, що критично для логів або історичних даних.

TimeZone в Swift: приклади коду

Форматування дати з конкретним часовим поясом — найбільш часта задача при роботі з TimeZone. DateFormatter використовує властивість timeZone для перетворення Date в рядок. Якщо не задати timeZone явно, форматер використовує TimeZone.current — часовий пояс, встановлений на пристрої користувача, що може призвести до неочікуваних результатів для серверних даних.

swift
import Foundation

// Форматувати дату в конкретному часовому поясі
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

let tokyo = TimeZone(identifier: "Asia/Tokyo")!
formatter.timeZone = tokyo
let tokyoTime = formatter.string(from: Date())
print("Час у Токіо: \(tokyoTime)")

// Доступні ідентифікатори для вибору користувача
let displayNames: [(String, String)] = TimeZone.knownTimeZoneIdentifiers
    .prefix(20)
    .map { ($0, TimeZone(identifier: $0)!.localizedName(
        for: .generic, locale: .current
    )) }

// Порівняти два часові пояси
let london = TimeZone(identifier: "Europe/London")!
let difference = tokyo.secondsFromGMT(for: Date())
    - london.secondsFromGMT(for: Date())
print("Різниця Токіо-Лондон: \(difference / 3600)h")

// Працювати зі словником абревіатур
let knownAbbrevs = TimeZone.abbreviationDictionary
for (abbr, ident) in knownAbbrevs.sorted(by: { $0.key < $1.key }).prefix(5) {
    print("\(abbr) -> \(ident)")
}

Локалізована назва часового поясу через localizedName(for:locale:) повертає людиночитану назву вказаною мовою. Наприклад, для Europe/Moscow з російською локаллю метод поверне російську назву «Moskva», а з англійською — «Moscow Time». Доступні стилі: .standard (стандартна назва), .daylightSaving (літній час) та .shortGeneric (коротка).

swift
import Foundation

let paris = TimeZone(identifier: "Europe/Paris")!
let nameRU = paris.localizedName(
    for: .standard,
    locale: Locale(identifier: "ru_RU")
)
print("Назва російською: \(nameRU)")

// Перевірити, чи регіон в тому самому дні
let isSameDay = Calendar.current.isDate(
    Date(),
    equalTo: Date(),
    toGranularity: .day
)
print("Той самий день у різних часових поясах: \(isSameDay)")

Серіалізація ідентифікатора часового поясу — найкраща практика для зберігання TimeZone в базах даних або UserDefaults. Зберігайте ідентифікатор (рядок типу Europe/Moscow), а не зміщення в секундах або абревіатуру. Зміщення може змінюватися при зміні DST, а абревіатура неоднозначна. Відновлення: TimeZone(identifier: savedString).

Типові помилки при роботі з TimeZone

Використання фіксованого зміщення замість ідентифікатора часового поясу — найпоширеніша помилка. TimeZone(secondsFromGMT: 10800) не враховує DST, тому для Europe/Moscow влітку ця конструкція дає невірне зміщення на 1 годину. Завжди використовуйте ідентифікатор IANA для регіонів з літнім часом.

Забута обробка nil при ініціалізації TimeZone(identifier:) — друга за частотою помилка. Якщо користувач ввів ідентифікатор з помилкою (наприклад, «moscow» замість «Europe/Moscow»), конструктор повертає nil. Без обробки опціонального значення додаток падає з runtime error. Використовуйте guard let або TimeZone(identifier:) з відомим fallback.

Ігнорування DST при роботі з майбутніми датами. TimeZone.secondsFromGMT(for:) — єдиний коректний спосіб отримати зміщення для конкретної дати. Використання secondsFromGMT() без параметра для історичних або майбутніх дат дає зміщення для поточного моменту, що може не відповідати реальному зміщенню у вказану дату, особливо для регіонів зі скасуванням або введенням DST.

За даними Stack Overflow (2024), близько 15% питань по DateFormatter пов’язані з неправильним налаштуванням timeZone. Типовий сценарій: сервер надсилає дату в UTC, розробник форматує її без встановлення timeZone форматера, і дата відображається в часовому поясі пристрою, створюючи плутанину у користувачів з різних регіонів. Правило: завжди явно задавати timeZone форматера для серверних даних.

Часті запитання

Що таке TimeZone в Foundation?

TimeZone — клас Foundation для роботи з часовими поясами в iOS та macOS. Він надає інформацію про зміщення відносно UTC, правила переходу на літній час та ідентифікатори часових поясів на основі IANA Time Zone Database.

Які формати ідентифікаторів підтримує TimeZone?

Три формати: IANA ідентифікатори (Europe/Moscow), абревіатури (MSK, EST) та числові зміщення (+0300). Apple рекомендує використовувати IANA-ідентифікатори як єдиний однозначний формат для production-коду.

Як TimeZone враховує літній час?

Автоматично через методи secondsFromGMT(for:) та isDaylightSavingTime(for:). TimeZone використовує історичні дані IANA, що оновлюються при кожному релізі iOS, що гарантує коректні переходи на DST для будь-якої дати.

В чому різниця між TimeZone.current та TimeZone.system?

TimeZone.current повертає часовий пояс, вибраний користувачем в налаштуваннях (може відрізнятися від географічного). TimeZone.system повертає часовий пояс пристрою, який автоматично визначається за геопозицією і не може бути перевизначений користувачем.

Як отримати поточний часовий пояс в Swift?

TimeZone.current повертає поточний часовий пояс пристрою. Для отримання ідентифікатора використовуйте властивість identifier: TimeZone.current.identifier. Для локалізованої назви викличте localizedName(for:locale:).

Підсумки

  • TimeZone — фундаментальний клас Foundation для роботи з часовими поясами в iOS та macOS
  • IANA ідентифікатори — єдиний надійний спосіб вказання часового поясу (Europe/Moscow, America/New_York)
  • Автоматичний облік DST — TimeZone коректно обробляє перехід на літній час через secondsFromGMT(for:)
  • Інтеграція з DateFormatter — обов’язкове встановлення timeZone запобігає некоректному відображенню дат
  • Локалізовані назви — метод localizedName(for:locale:) повертає назву часового поясу потрібною мовою
  • Обробка помилок — ініціалізація TimeZone(identifier:) повертає nil для невірних ідентифікаторів
  • Зберігання ідентифікаторів — зберігайте рядок IANA для серіалізації, а не зміщення або абревіатуру

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також