تاریخ و زمان در توسعه موبایل — یکی از موضوعات کلیدی در مهندسی موبایل است. iOS از DateFormatter و ISO8601DateFormatter استفاده میکند، Android از DateTimeFormatter و LocalDate از java.time استفاده میکند. به گفته Android Developer Docs، انتخاب صحیح API موبایل برای قالببندی تاریخ و زمان به طور مستقیم بر عملکرد و نمایش صحیح در مناطق زمانی مختلف تأثیر میگذارد.
نکات اصلی
در iOS، تاریخ و زمان به طور سنتی از طریق DateFormatter از Foundation قالببندی میشوند. این کلاس با استفاده از یک الگو، locale و منطقه زمانی مشخص، Date را به رشته و بالعکس تبدیل میکند. مشکل اصلی DateFormatter — امن برای نخ نیست و به کندی ایجاد میشود، بنابراین در کد موبایل نمونهها باید کش شوند. تاریخ در توسعه موبایل در iOS به قالببند صحیح نیاز دارد.
ایجاد DateFormatter حدود 1 میلیثانیه طول میکشد به دلیل تجزیه الگوی dateFormat، بارگذاری locale و تعیین منطقه زمانی. هنگام قالببندی فهرستی از صدها تاریخ، ایجاد مکرر باعث تأخیر قابل توجه در UI میشود. راه حل — قالببند را یک بار برای کل صفحه ایجاد کرده و مجدداً استفاده کنید. برای دسترسی چند نخی، از همگامسازی از طریق DispatchQueue استفاده کنید.
import Foundation
// DateFormatter کش شده — یک بار ایجاد میشود
private let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "dd.MM.yyyy HH:mm"
formatter.locale = Locale(identifier: "ru_RU")
formatter.timeZone = TimeZone(identifier: "Europe/Moscow")
return formatter
}()
// ISO8601DateFormatter — جایگزین سبک
private let isoFormatter: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
return formatter
}()
let now = Date()
let formattedDate = dateFormatter.string(from: now)
// "01.07.2026 14:30"
let isoDate = isoFormatter.string(from: now)
// "2026-07-01T14:30:00.000Z"
برای فرمت ISO 8601، از ISO8601DateFormatter استفاده کنید — نیازی به مشخص کردن الگو ندارد و سریعتر از DateFormatter کار میکند. در iOS 10+، این کلاس برای کار با تاریخهای سرور ارجحیت دارد. برای فرمتهای قدیمی، DateFormatter را نگه دارید اما حتماً نمونه را به عنوان یک ویژگی استاتیک یا singleton کش کنید.
در Android، تاریخ و زمان از طریق بسته java.time پردازش میشود که از API 26 در دسترس است. کلاسهای اصلی: LocalDate (فقط تاریخ)، LocalTime (فقط زمان)، LocalDateTime (تاریخ و زمان بدون منطقه زمانی) و ZonedDateTime (با منطقه زمانی). DateTimeFormatter — یک قالببند امن برای نخ برای پلتفرم موبایل Android. تاریخ در برنامههای موبایل از طریق DateTimeFormatter و LocalDate بدون افت عملکرد قالببندی میشود.
LocalDate تاریخ را بدون زمان ذخیره میکند — ایدهآل برای تولدها. ZonedDateTime اطلاعات کامل را با منطقه زمانی ذخیره میکند. DateTimeFormatter از الگوهای از پیش تعریف شده (ISO_LOCAL_DATE، ISO_DATE_TIME) و سفارشی از طریق ofPattern پشتیبانی میکند. همه کلاسهای java.time تغییرناپذیر و امن برای نخ هستند، که شرایط رقابتی را هنگام کار در چندین نخ از بین میبرد.
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.ZoneId
// ایجاد و قالببندی تاریخ جاری
val today = LocalDate.now()
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
val formatted = today.format(formatter)
// کار با مناطق زمانی
val utcTime = ZonedDateTime.now(ZoneId.of("UTC"))
val moscowTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/Moscow"))
DateTimeFormatter به طور قابل توجهی کارآمدتر از SimpleDateFormat است زیرا الگو را در هر فراخوانی تجزیه نمیکند. توصیه میشود ثابتهای قالببند را در سطح کلاس یا شی همراه ایجاد کنید. برای تبدیل Unix Timestamp، از Instant.ofEpochSecond استفاده کنید، سپس از طریق منطقه زمانی به LocalDateTime یا ZonedDateTime تبدیل کنید.
تاریخ و زمان صحیح روی صفحه کاربر به پردازش مناسب مناطق زمانی بستگی دارد. تاریخ و زمان در توسعه موبایل برای Android نیاز به در نظر گرفتن منطقه زمانی دستگاه دارد. قانون طلایی: زمان را در UTC ذخیره کنید، فقط برای نمایش به منطقه زمانی محلی تبدیل کنید. iOS TimeZone را از Foundation فراهم میکند، Android ZoneId را از java.time فراهم میکند. هر دو API برای پلتفرمهای موبایل از تشخیص خودکار منطقه زمانی فعلی دستگاه پشتیبانی میکنند. تاریخ در یک برنامه موبایل به ZoneId و TimeZone بستگی دارد.
ساعت تابستانی ابهام ایجاد میکند: یک لحظه در زمان میتواند با دو ساعت محلی متفاوت نمایش داده شود. java.time و Foundation به طور خودکار DST را مدیریت میکنند. از شناسههای IANA (Europe/Moscow، America/New_York) استفاده کنید، نه از اختصارات (MSK، EST) — اختصارات مبهم هستند و انتقال ساعت تابستانی را نادیده میگیرند.
import Foundation
// تبدیل UTC به زمان محلی در iOS
func formatToLocalTime(utcDate: Date, timeZoneId: String) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "dd.MM.yyyy HH:mm"
formatter.timeZone = TimeZone(identifier: timeZoneId)
return formatter.string(from: utcDate)
}
// تعیین منطقه زمانی دستگاه
let localTimeZone = TimeZone.current
let isDST = localTimeZone.isDaylightSavingTime()
let secondsFromGMT = localTimeZone.secondsFromGMT()
در Android، از ZoneId.systemDefault() برای دریافت منطقه زمانی دستگاه استفاده کنید. هنگام تبدیل UTC به زمان محلی، یک ZonedDateTime با ZoneOffset.UTC ایجاد کنید و withZoneSameInstant را اعمال کنید. برای APIهای قدیمی بدون java.time، از TimeZone.getDefault() و Calendar استفاده کنید — اما بهتر است مستقیماً ThreeTenABP را اضافه کنید.
import java.time.Instant
import java.time.ZonedDateTime
import java.time.ZoneId
// تبدیل Unix Timestamp به زمان محلی
fun toLocalDisplay(unixSeconds: Long): String {
val instant = Instant.ofEpochSecond(unixSeconds)
val local = instant.atZone(ZoneId.systemDefault())
return local.format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm"))
}
ThreeTenABP — یک کتابخانه آداپتور که java.time را به Android API پایینتر از 26 منتقل میکند. همان کلاسها را فراهم میکند: LocalDate، LocalTime، ZonedDateTime، DateTimeFormatter، Instant. اگر برنامه از Android 5 یا 6 (API 21-25) پشتیبانی میکند، ThreeTenABP تنها راه استفاده از API موبایل مدرن بدون مهاجرت به Calendar منسوخ است. تاریخ و زمان در توسعه موبایل برای دستگاههای قدیمی از طریق این کتابخانه پیادهسازی میشود. برای دستگاههای قدیمی، تاریخ و زمان از طریق ThreeTenABP پیادهسازی میشود.
کتابخانه نیاز به مقداردهی اولیه در متد Application.onCreate() با فراخوانی AndroidThreeTen.init() دارد. این کار دادههای مناطق زمانی را از assets بارگذاری میکند. پس از مقداردهی اولیه، API کاملاً مشابه java.time است — کد برای API 26+ و API 21+ یکسان خواهد بود. اندازه کتابخانه حدود 400 کیلوبایت است که برای اکثر برنامههای موبایل قابل قبول است.
import org.threeten.bp.LocalDate
import org.threeten.bp.format.DateTimeFormatter
// مقداردهی اولیه در Application
class App : Application() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
// API مشابه java.time است
val today = LocalDate.now()
val formatted = today.format(DateTimeFormatter.ISO_LOCAL_DATE)
عملکرد ThreeTenABP در دستگاههای مدرن قابل مقایسه با java.time اصلی است. در دستگاههای قدیمی، به دلیل بارگذاری دادههای مناطق زمانی، ممکن است در اولین فراخوانی تأخیر وجود داشته باشد. کد موجود را به تدریج از Calendar به ThreeTenABP منتقل کنید: Date و Calendar را با Instant و LocalDate در ماژولهای جدید جایگزین کنید، کد قدیمی را بدون تغییر بگذارید.
Unix Timestamp — تعداد ثانیههای سپری شده از 1 ژانویه 1970 00:00 UTC. این یک فرمت جهانی برای ذخیره و تبادل زمان بین سرور و کلاینت است. با این حال، زمان روی دستگاه ممکن است به دلیل تنظیمات کاربر با زمان واقعی متفاوت باشد. برای همگامسازی از NTP استفاده میشود — یک پروتکل زمان دقیق از طریق UDP. Unix Timestamp فرمتی است که در آن تاریخ و زمان روی سرور ذخیره میشود.
Date().timeIntervalSince1970 در iOS ثانیههای از 1970 را برمیگرداند. در Android، System.currentTimeMillis() میلیثانیه را برمیگرداند. برای دقت، از NTP استفاده کنید: کتابخانه TrueTime برای iOS و AndroidNtp برای Android یک درخواست به سرور NTP ارسال میکنند و افست زمانی را محاسبه میکنند. دقت NTP در شبکه محلی 1-10 میلیثانیه و از طریق اینترنت 10-100 میلیثانیه است.
import Foundation
// دریافت Unix Timestamp در iOS
let seconds = Date().timeIntervalSince1970
let milliseconds = Int64(seconds * 1000)
// همگامسازی NTP با TrueTime
TrueTime.shared.start { result in
switch result {
case .success:
let ntpTime = TrueTime.shared.now()
print("زمان دقیق: \(ntpTime)")
case .failure(let error):
print("خطای NTP: \(error)")
}
}
بدون همگامسازی در یک برنامه موبایل، خطاها ممکن است: مهرهای زمانی نادرست رویدادها، عدم همگامسازی با سرور. زمان در توسعه موبایل یک بار در شروع برنامه از طریق NTP همگامسازی میشود، پس از آن از افست محاسبه شده استفاده میشود. برای برنامههای موبایل حیاتی از نظر دقت (مالی، لجستیک)، پروتکل NTP قبل از ارسال داده به سرور اجباری است.
سوالات متداول
DateFormatter هر بار که یک نمونه ایجاد میشود، الگوی قالببندی را تجزیه میکند، locale را بارگذاری میکند و منطقه زمانی را تعیین میکند. قالببند را به عنوان یک ثابت استاتیک کش کنید یا برای ISO 8601 از ISO8601DateFormatter استفاده کنید — سبکتر و سریعتر است.
DateTimeFormatter از بسته java.time — امن برای نخ و کارآمد. از API 26 در دسترس است. برای نسخههای قدیمی، از ThreeTenABP استفاده کنید که API یکسانی را فراهم میکند.
ThreeTenABP را اضافه کنید — backport از java.time برای Android API 21+. مقداردهی اولیه از طریق AndroidThreeTen.init() در Application.onCreate(). API کاملاً مشابه java.time اصلی است.
بله، زمان را در UTC روی سرور و در پایگاه داده محلی ذخیره کنید. فقط در مرحله نمایش به منطقه زمانی محلی کاربر تبدیل کنید. این کار خطاها را هنگام تغییر منطقه زمانی یا سفر از بین میبرد.
Date().timeIntervalSince1970 تعداد ثانیهها از 1 ژانویه 1970 را برمیگرداند. برای میلیثانیه، در 1000 ضرب کنید و به Int64 تبدیل کنید. برای همگامسازی دقیق، از کتابخانه TrueTime با سرور NTP استفاده کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.