TimeZone — je třída Foundation v iOS a macOS, která abstrahuje informace o časových pásmech pro správnou konverzi času mezi geografickými regiony. Podle Apple Developer Documentation, 2024, TimeZone poskytuje metody pro práci s identifikátory časových pásem (IANA Time Zone Database), odchylkami vůči UTC a pravidly pro přechod na letní čas. Třída je integrována s DateFormatter a Calendar a zajišťuje automatické použití správného časového pásma při formátování dat. Na rozdíl od ručního výpočtu odchylky TimeZone automaticky aktualizuje data při změně časového pásma zařízení.
Hlavní body
TimeZone — je hodnotový typ v Swift, který poskytuje informace o geografickém časovém pásmu: odchylku vůči UTC, název, zkratku a pravidla pro přechod na letní čas. V Objective-C se třída nazývá NSTimeZone. Obě třídy se opírají o IANA Time Zone Database (také známou jako Olsonova databáze), která obsahuje historii změn časových pásem od roku 1970.
Každá instance TimeZone ukládá identifikátor časového pásma (např. Europe/Moscow), aktuální odchylku v sekundách od UTC, příznak isDaylightSavingTime a datum příští změny. Identifikátor je primární klíč: při inicializaci TimeZone(identifier:) systém načte odpovídající záznam z databáze časových pásem zařízení.
Podle údajů IANA (2024) databáze obsahuje více než 600 jedinečných identifikátorů časových pásem. Apple dodává část této databáze v každé verzi iOS a macOS, což zaručuje jednotnost výpočtů na všech zařízeních bez potřeby síťových požadavků.
Architektura TimeZone ve Foundation je postavena na dvouúrovňovém systému: identifikátor časového pásma (člověkem čitelný název) a jeho číselná reprezentace (odchylka od UTC). Systém automaticky vybírá aktuální časové pásmo z nastavení zařízení, ale vývojář jej může přepsat pro konkrétní operace formátování.
TimeZone je úzce spojen s Calendar a DateFormatter. Při formátování data DateFormatter používá vlastnost timeZone instance TimeZone k převedení absolutního časového okamžiku (Date) na textovou reprezentaci v příslušném časovém pásmu. Pokud timeZone není nastaveno, použije se výchozí systémové časové pásmo — TimeZone.current.
| Typ | Inicializace | Vlastnosti |
|---|---|---|
| Aktuální | TimeZone.current | Automaticky se aktualizuje při změně regionu v nastavení, sleduje letní čas |
| Pevný | TimeZone(identifier:) | Nezávisí na regionu zařízení. Trvale aplikuje vybraný identifikátor |
| UTC | TimeZone(secondsFromGMT: 0) | Časové pásmo bez korekce. Identifikátor: GMT |
| S libovolnou odchylkou | TimeZone(secondsFromGMT: 10800) | Pevná odchylka v sekundách. Nezohledňuje letní čas |
Důležitý nuance: TimeZone(identifier:) vrátí nil pro neznámé identifikátory. To je častá příčina pádu aplikace — vývojáři zapomínají zpracovat volitelnou hodnotu a předávají chybný identifikátor z uživatelského vstupu. U IANA identifikátorů záleží na velikosti písmen: Europe/Moscow — správně, europe/moscow — nil.
IANA Time Zone Database používá formát „Region/Město” (Continent/City), kde region je jeden z kontinentů (Africa, America, Asia, Atlantic, Australia, Europe, Indian, Pacific) nebo oceán a město je největší sídlo v zóně časového pásma. Tento formát zaručuje jedinečnost a čitelnost identifikátoru.
Kromě hlavního formátu TimeZone podporuje tři další způsoby identifikace: zkratky (MSK, EST, PST), třípísmenkové kódy časových pásem (GMT, UTC) a číselné odchylky (+0300, -0500). Zkratky jsou však nejednoznačné: EST může znamenat jak Eastern Standard Time (GMT-5), tak Eastern Summer Time (GMT+10) v Austrálii. Apple doporučuje výhradní používání IANA identifikátorů.
import Foundation
// Získat všechny známé identifikátory časových pásem
let allIdentifiers: [String] = TimeZone.knownTimeZoneIdentifiers
print("Celkem časových pásem: \(allIdentifiers.count)")
// Filtrovat podle regionu
let europeZones = allIdentifiers.filter { $0.hasPrefix("Europe/") }
print("Evropská časová pásma: \(europeZones)")
// Zkratky (nedoporučuje se pro produkci)
if let moscowTimeZone = TimeZone(abbreviation: "MSK") {
print("MSK sekund od GMT: \(moscowTimeZone.secondsFromGMT())")
}
// Najít identifikátor podle odchylky
let utcPlus3 = TimeZone(secondsFromGMT: 10800)
print("Identifikátor: \(utcPlus3.identifier)")
Zkratky v TimeZone.abbreviationDictionary obsahují zkratky pro všechna známá časová pásma, ale tento slovník nezaručuje jedinečnost: klíč PST může odpovídat jak America/Los_Angeles, tak Pacific/Pago_Pago. V produkčním kódu vždy používejte IANA identifikátory.
TimeZone automaticky zohledňuje přechod na letní a zimní čas (DST — Daylight Saving Time) pro všechny regiony, kde je běžný. Systém používá historická data z IANA Time Zone Database, která obsahují přesná data přechodů pro každé časové pásmo. Vlastnost isDaylightSavingTime vrátí true, pokud se časové pásmo právě nachází v letním čase.
Metoda nextDaylightSavingTimeTransition umožňuje zjistit datum příštího přechodu, což je užitečné pro plánování budoucích událostí. Tato funkcionalita je obzvláště důležitá pro regiony s častými změnami pravidel DST, jako je Brazílie nebo Maroko — do roku 2024 Brazílie každoročně měnila data přechodů a ruční výpočet vedl k chybám v aplikacích.
Podle údajů Apple WWDC 2023 knihovna ICU (International Components for Unicode), která je základem Foundation, aktualizuje data DST při každé aktualizaci iOS. Aplikace by neměly ukládat data o letním čase do mezipaměti déle než jeden den po aktualizaci systému — databáze IANA se může změnit i bez aktualizace verze OS prostřednictvím úprav časových pásem.
import Foundation
// Zkontrolovat DST pro Europe/Moscow
let moscow = TimeZone(identifier: "Europe/Moscow")!
let now = Date()
let isMoscowDST = moscow.isDaylightSavingTime(for: now)
print("Moskva momentálně v DST: \(isMoscowDST)")
// Získat datum příštího přechodu DST
if let nextTransition = moscow.nextDaylightSavingTimeTransition(
after: now
) {
let dstOffset = moscow.daylightSavingTimeOffset(
for: nextTransition
)
print("Příští přechod: \(nextTransition), odchylka DST: \(dstOffset)s")
}
// Bezpečná konverze s uvědoměním DST
let newYork = TimeZone(identifier: "America/New_York")!
let offsetNY = newYork.secondsFromGMT(for: now)
print("Aktuální odchylka NY: \(offsetNY / 3600)h")
Kritický nuance: secondsFromGMT(for:) zohledňuje DST pro zadané datum, zatímco secondsFromGMT() pouze pro aktuální čas. Při formátování historických dat vždy používejte verzi s parametrem Date: secondsFromGMT(for: someHistoricalDate). Rozdíl může činit 1–2 hodiny, což je kritické pro protokoly nebo historická data.
Formátování data s konkrétním časovým pásmem — nejčastější úkol při práci s TimeZone. DateFormatter používá vlastnost timeZone k převedení Date na text. Pokud timeZone není explicitně nastaveno, formátovač použije TimeZone.current — časové pásmo nastavené na zařízení uživatele, což může vést k neočekávaným výsledkům pro serverová data.
import Foundation
// Formátovat datum v konkrétním časovém pásmu
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("Čas v Tokiu: \(tokyoTime)")
// Dostupné identifikátory pro výběr uživatele
let displayNames: [(String, String)] = TimeZone.knownTimeZoneIdentifiers
.prefix(20)
.map { ($0, TimeZone(identifier: $0)!.localizedName(
for: .generic, locale: .current
)) }
// Porovnat dvě časová pásma
let london = TimeZone(identifier: "Europe/London")!
let difference = tokyo.secondsFromGMT(for: Date())
- london.secondsFromGMT(for: Date())
print("Rozdíl Tokio-Londýn: \(difference / 3600)h")
// Práce se slovníkem zkratek
let knownAbbrevs = TimeZone.abbreviationDictionary
for (abbr, ident) in knownAbbrevs.sorted(by: { $0.key < $1.key }).prefix(5) {
print("\(abbr) -> \(ident)")
}
Lokalizovaný název časového pásma prostřednictvím localizedName(for:locale:) vrátí člověkem čitelný název v zadaném jazyce. Například pro Europe/Moscow s ruskou lokalizací metoda vrátí „Moskva”, s anglickou — „Moscow Time”. Dostupné styly: .standard (standardní název), .daylightSaving (letní čas) a .shortGeneric (krátký).
import Foundation
let paris = TimeZone(identifier: "Europe/Paris")!
let nameRU = paris.localizedName(
for: .standard,
locale: Locale(identifier: "ru_RU")
)
print("Ruský název: \(nameRU)")
// Zkontrolovat, zda je region ve stejném dni
let isSameDay = Calendar.current.isDate(
Date(),
equalTo: Date(),
toGranularity: .day
)
print("Stejný den v různých časových pásmech: \(isSameDay)")
Serializace identifikátoru časového pásma — nejlepší praxe pro ukládání TimeZone v databázích nebo UserDefaults. Ukládejte identifikátor (řetězec typu Europe/Moscow), nikoli odchylku v sekundách nebo zkratku. Odchylka se může měnit při změně DST a zkratka je nejednoznačná. Obnovení: TimeZone(identifier: savedString).
Použití pevné odchylky místo identifikátoru časového pásma — nejčastější chyba. TimeZone(secondsFromGMT: 10800) nezohledňuje DST, proto pro Europe/Moscow v létě tato konstrukce dává chybnou odchylku o 1 hodinu. Vždy používejte IANA identifikátor pro regiony s letním časem.
Zapomenuté ošetření nil při inicializaci TimeZone(identifier:) — druhá nejčastější chyba. Pokud uživatel zadá identifikátor s chybou (např. „moscow” místo „Europe/Moscow”), konstruktor vrátí nil. Bez ošetření volitelné hodnoty aplikace spadne s runtime error. Použijte guard let nebo TimeZone(identifier:) se známým fallbackem.
Ignorování DST při práci s budoucími daty. TimeZone.secondsFromGMT(for:) — jediný správný způsob, jak získat odchylku pro konkrétní datum. Použití secondsFromGMT() bez parametru pro historická nebo budoucí data dává odchylku pro aktuální okamžik, což nemusí odpovídat skutečné odchylce v daném datu, zejména pro regiony se zrušením nebo zavedením DST.
Podle údajů Stack Overflow (2024) přibližně 15% otázek týkajících se DateFormatter souvisí s nesprávným nastavením timeZone. Typický scénář: server pošle datum v UTC, vývojář jej formátuje bez nastavení timeZone formátovače a datum se zobrazí v časovém pásmu zařízení, což způsobuje zmatek u uživatelů z různých regionů. Pravidlo: vždy explicitně nastavte timeZone formátovače pro serverová data.
Často kladené otázky
TimeZone — třída Foundation pro práci s časovými pásmy v iOS a macOS. Poskytuje informace o odchylce vůči UTC, pravidlech přechodu na letní čas a identifikátorech časových pásem na základě IANA Time Zone Database.
Tři formáty: IANA identifikátory (Europe/Moscow), zkratky (MSK, EST) a číselné odchylky (+0300). Apple doporučuje používání IANA identifikátorů jako jediného jednoznačného formátu pro produkční kód.
Automaticky prostřednictvím metod secondsFromGMT(for:) a isDaylightSavingTime(for:). TimeZone používá historická data IANA, aktualizovaná při každém vydání iOS, což zaručuje správné přechody DST pro libovolné datum.
TimeZone.current vrátí časové pásmo vybrané uživatelem v nastavení (může se lišit od geografického). TimeZone.system vrátí časové pásmo zařízení, které je automaticky určeno na základě geolokace a nemůže být uživatelem přepsáno.
TimeZone.current vrátí aktuální časové pásmo zařízení. Pro získání identifikátoru použijte vlastnost identifier: TimeZone.current.identifier. Pro lokalizovaný název zavolejte localizedName(for:locale:).
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také