TimeZone — یک کلاس Foundation در iOS و macOS است که اطلاعات مناطق زمانی را برای تبدیل درست زمان بین مناطق جغرافیایی ابستراکت میکند. به گزارش Apple Developer Documentation, 2024، TimeZone روشهایی برای کار با شناسههای منطقه زمانی (IANA Time Zone Database)، انحرافات نسبت به UTC و قوانین تغییر به زمان تابستانی ارائه میدهد. این کلاس با DateFormatter و Calendar یکپارچه شده و اعمال خودکار منطقه زمانی درست را در طول فرماتبندی تاریخها تامین میکند. بر خلاف محاسبه دستی انحراف، TimeZone با تغییر منطقه زمانی دستگاه دادهها را خودکار بهروز میکند.
نکات کلیدی
TimeZone — یک نوع مقداری در 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 در Foundation بر یک سیستم دو سطحی ساخته شده است: شناسه منطقه زمانی (نام قابل خواندن توسط انسان) و نمایش عددی آن (انحراف از UTC). سیستم بهطور خودکار منطقه زمانی فعلی را از تنظیمات دستگاه انتخاب میکند، اما توسعهدهنده میتواند آن را برای عملیات فرماتبندی مشخص تغییر دهد.
TimeZone با Calendar و DateFormatter ارتباط نزدیکی دارد. در طول فرماتبندی تاریخ، DateFormatter از ویژگی timeZone یک نمونه TimeZone برای تبدیل لحظه مطلق زمان (Date) به نمایش متنی در منطقه زمانی مورد نظر استفاده میکند. اگر timeZone تنظیم نشده باشد، از منطقه زمانی پیشفرض سیستم — TimeZone.current استفاده میشود.
| نوع | اهلیاسازی | ویژگیها |
|---|---|---|
| جاری | TimeZone.current | با تغییر منطقه در تنظیمات خودکار بهروز میشود، زمان تابستانی را ردیابی میکند |
| ثابت | TimeZone(identifier:) | به منطقه دستگاه بستگی ندارد. شناسه انتخابی را دائماً اعمال میکند |
| UTC | TimeZone(secondsFromGMT: 0) | منطقه زمانی بدون تصحیح. شناسه: GMT |
| با انحراف دلخواه | TimeZone(secondsFromGMT: 10800) | انحراف ثابت به ثانیه. زمان تابستانی را در نظر نمیگیرد |
نکته مهم: TimeZone(identifier:) برای شناسههای ناشناخته nil بازمیگرداند. این یک علت رایج سقوط برنامه است — توسعهدهندگان فراموش میکنند مقدار اختیاری را مدیریت کنند و شناسه نامناسبی از ورودی کاربر ارسال میکنند. برای شناسههای IANA حروف بزرگ و کوچک مهم است: Europe/Moscow — درست، europe/moscow — nil.
IANA Time Zone Database از فرمات «Region/City» (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 را داشته باشید.
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 مطابقت داشته باشد. در کد تولیدی همیشه از شناسههای IANA استفاده کنید.
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 میتواند حتی بدون بهروزرسانی نسخه سیستمعامل از طریق تنظیمات منطقه زمانی تغییر کند.
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 است. DateFormatter از ویژگی timeZone برای تبدیل Date به متن استفاده میکند. اگر timeZone بهصورت صریح تنظیم نشده باشد، فرماتدهنده از TimeZone.current — منطقه زمانی تنظیم شده در دستگاه کاربر استفاده میکند که میتواند برای دادههای سرور نتایج غیرمنتظره ایجاد کند.
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 با لوکیل روسی، روش «مسکو» و با لوکیل انگلیسی، «Moscow Time» را بازمیگرداند. سبکهای موجود: .standard (نام استاندارد)، .daylightSaving (زمان تابستانی) و .shortGeneric (کوتاه).
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(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 برای کار با مناطق زمانی در iOS و macOS. اطلاعاتی درباره انحراف نسبت به UTC، قوانین تغییر به زمان تابستانی و شناسههای منطقه زمانی بر اساس IANA Time Zone Database فراهم میکند.
سه فرمات: شناسههای IANA (Europe/Moscow)، کوتاهنویسها (MSK، EST) و انحرافات عددی (+0300). Apple استفاده از شناسههای IANA را تنها فرمات یکتا و بدون ابهام برای کد تولیدی توصیه میکند.
بهطور خودکار از طریق روشهای secondsFromGMT(for:) و isDaylightSavingTime(for:). TimeZone از دادههای تاریخی IANA استفاده میکند که در هر نسخه iOS بهروز میشود و تغییرات درست DST را برای هر تاریخی تضمین میکند.
TimeZone.current منطقه زمانی انتخاب شده توسط کاربر در تنظیمات را بازمیگرداند (ممکن است با منطقه جغرافیایی متفاوت باشد). TimeZone.system منطقه زمانی دستگاه را بازمیگرداند که بهطور خودکار بر اساس مکان تعیین میشود و قابل تغییر توسط کاربر نیست.
TimeZone.current منطقه زمانی فعلی دستگاه را بازمیگرداند. برای دریافت شناسه از ویژگی identifier استفاده کنید: TimeZone.current.identifier. برای نام محلیشده، روش localizedName(for:locale:) را صدا بزنید.
نتیجه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید