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 database), которая содержит историю изменений часовых поясов с 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

// Get all known timezone identifiers
let allIdentifiers: [String] = TimeZone.knownTimeZoneIdentifiers
print("Total timezones: \(allIdentifiers.count)")

// Filter by region
let europeZones = allIdentifiers.filter { $0.hasPrefix("Europe/") }
print("European timezones: \(europeZones)")

// Abbreviations (not recommended for production)
if let moscowTimeZone = TimeZone(abbreviation: "MSK") {
    print("MSK seconds from GMT: \(moscowTimeZone.secondsFromGMT())")
}

// Find identifier by offset
let utcPlus3 = TimeZone(secondsFromGMT: 10800)
print("Identifier: \(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

// Check DST for Europe/Moscow
let moscow = TimeZone(identifier: "Europe/Moscow")!
let now = Date()
let isMoscowDST = moscow.isDaylightSavingTime(for: now)
print("Moscow currently in DST: \(isMoscowDST)")

// Get next DST transition date
if let nextTransition = moscow.nextDaylightSavingTimeTransition(
    after: now
) {
    let dstOffset = moscow.daylightSavingTimeOffset(
        for: nextTransition
    )
    print("Next transition: \(nextTransition), DST offset: \(dstOffset)s")
}

// Safe conversion with DST awareness
let newYork = TimeZone(identifier: "America/New_York")!
let offsetNY = newYork.secondsFromGMT(for: now)
print("NY current offset: \(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

// Format date in specific timezone
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("Tokyo time: \(tokyoTime)")

// Available identifiers for user selection
let displayNames: [(String, String)] = TimeZone.knownTimeZoneIdentifiers
    .prefix(20)
    .map { ($0, TimeZone(identifier: $0)!.localizedName(
        for: .generic, locale: .current
    )) }

// Compare two timezones
let london = TimeZone(identifier: "Europe/London")!
let difference = tokyo.secondsFromGMT(for: Date())
    - london.secondsFromGMT(for: Date())
print("Tokyo-London difference: \(difference / 3600)h")

// Work with abbreviation dictionary
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 с русской локалью метод вернёт «Москва», а с английской — «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("Russian name: \(nameRU)")

// Check if region is in same day
let isSameDay = Calendar.current.isDate(
    Date(),
    equalTo: Date(),
    toGranularity: .day
)
print("Same day across timezones: \(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 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

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