Mobil geliştirmede tarih ve saat — mobil mühendisliğin önemli konularından biridir. iOS, DateFormatter ve ISO8601DateFormatter kullanır, Android ise java.time'dan DateTimeFormatter ve LocalDate kullanır. Android Developer Docs'a göre, tarih ve saat biçimlendirme için doğru mobil API'yi seçmek, farklı saat dilimlerinde performansı ve doğru görüntülemeyi doğrudan etkiler.
Önemli Noktalar
iOS'ta tarih ve saat geleneksel olarak Foundation'daki DateFormatter aracılığıyla biçimlendirilir. Bu sınıf, belirtilen bir desen, yerel ayar ve saat dilimini kullanarak Date'i dizeye ve geri dönüştürür. DateFormatter'ın temel sorunu — iş parçacığı güvenli değildir ve yavaş oluşturulur, bu nedenle mobil kodda örnekler önbelleğe alınmalıdır. iOS'ta mobil geliştirmede tarih, doğru biçimlendiriciyi gerektirir.
DateFormatter oluşturmak, dateFormat desenini ayrıştırma, yerel ayarı yükleme ve saat dilimini belirleme nedeniyle yaklaşık 1 milisaniye sürer. Yüzlerce tarihten oluşan bir listeyi biçimlendirirken, tekrarlanan oluşturma kullanıcı arayüzünde gözle görülür gecikmelere yol açar. Çözüm — biçimlendiriciyi tüm ekran için bir kez oluşturun ve yeniden kullanın. Çok iş parçacıklı erişim için DispatchQueue ile senkronizasyon kullanın.
import Foundation
// Önbelleğe alınmış DateFormatter — bir kez oluşturulur
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 — hafif alternatif
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 biçimi için ISO8601DateFormatter kullanın — desen belirtmeyi gerektirmez ve DateFormatter'dan daha hızlı çalışır. iOS 10+'da bu sınıf, sunucu tarihleriyle çalışmak için tercih edilir. Eski biçimler için DateFormatter'ı koruyun ancak örneği statik bir özellik veya singleton olarak önbelleğe aldığınızdan emin olun.
Android'de tarih ve saat, API 26'dan itibaren kullanılabilen java.time paketi aracılığıyla işlenir. Ana sınıflar: LocalDate (yalnızca tarih), LocalTime (yalnızca saat), LocalDateTime (saat dilimi olmayan tarih ve saat) ve ZonedDateTime (saat dilimi ile). DateTimeFormatter — Android mobil platformu için iş parçacığı güvenli biçimlendirici. Mobil uygulamalarda tarih, performans kaybı olmadan DateTimeFormatter ve LocalDate aracılığıyla biçimlendirilir.
LocalDate, zaman olmadan tarihi saklar — doğum günleri için idealdir. ZonedDateTime, saat dilimi ile tam bilgiyi saklar. DateTimeFormatter, önceden tanımlanmış desenleri (ISO_LOCAL_DATE, ISO_DATE_TIME) ve ofPattern aracılığıyla özel desenleri destekler. Tüm java.time sınıfları değişmez ve iş parçacığı güvenlidir, bu da birden çok iş parçacığında çalışırken yarış koşullarını ortadan kaldırır.
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.time.ZoneId
// Geçerli tarihi oluşturma ve biçimlendirme
val today = LocalDate.now()
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
val formatted = today.format(formatter)
// Saat dilimleriyle çalışma
val utcTime = ZonedDateTime.now(ZoneId.of("UTC"))
val moscowTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/Moscow"))
DateTimeFormatter, her çağrıda deseni ayrıştırmadığı için SimpleDateFormat'ten önemli ölçüde daha verimlidir. Biçimlendirici sabitlerinin sınıf veya eşlik eden nesne düzeyinde oluşturulması önerilir. Bir Unix Timestamp'ını dönüştürmek için Instant.ofEpochSecond kullanın, ardından saat dilimi aracılığıyla LocalDateTime veya ZonedDateTime'ye dönüştürün.
Kullanıcının ekranında doğru tarih ve saat, saat dilimlerinin doğru şekilde işlenmesine bağlıdır. Android için mobil geliştirmede tarih ve saat, cihazın saat diliminin dikkate alınmasını gerektirir. Altın kural: zamanı UTC'de saklayın, yalnızca görüntüleme için yerel saat dilimine dönüştürün. iOS, Foundation'dan TimeZone sağlar, Android, java.time'dan ZoneId sağlar. Mobil platformlar için her iki API de cihazın geçerli saat dilimini otomatik olarak algılamayı destekler. Mobil uygulamada tarih, ZoneId ve TimeZone'a bağlıdır.
Yaz saati uygulaması belirsizlik yaratır: zamandaki bir an, iki farklı yerel saatle temsil edilebilir. java.time ve Foundation, DST'yi otomatik olarak işler. IANA tanımlayıcılarını (Europe/Moscow, America/New_York) kullanın, kısaltmaları (MSK, EST) değil — kısaltmalar belirsizdir ve yaz saati uygulaması geçişini yok sayar.
import Foundation
// UTC'yi iOS'ta yerel saate dönüştürme
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)
}
// Cihaz saat dilimini belirleme
let localTimeZone = TimeZone.current
let isDST = localTimeZone.isDaylightSavingTime()
let secondsFromGMT = localTimeZone.secondsFromGMT()
Android'de, cihazın saat dilimini almak için ZoneId.systemDefault() kullanın. UTC'yi yerel saate dönüştürürken ZoneOffset.UTC ile bir ZonedDateTime oluşturun ve withZoneSameInstant uygulayın. java.time olmayan eski API'ler için TimeZone.getDefault() ve Calendar kullanın — ancak doğrudan ThreeTenABP eklemek daha iyidir.
import java.time.Instant
import java.time.ZonedDateTime
import java.time.ZoneId
// Unix Timestamp'ı yerel saate dönüştür
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 altına taşıyan bir bağdaştırıcı kitaplığıdır. Aynı sınıfları sağlar: LocalDate, LocalTime, ZonedDateTime, DateTimeFormatter, Instant. Uygulama Android 5 veya 6'yı (API 21-25) destekliyorsa, ThreeTenABP, eski Calendar'a geçmeden modern bir mobil API kullanmanın tek yoludur. Eski cihazlar için mobil geliştirmede tarih ve saat bu kitaplık aracılığıyla uygulanır. Eski cihazlar için tarih ve saat ThreeTenABP aracılığıyla uygulanır.
Kitaplık, Application.onCreate() yönteminde AndroidThreeTen.init() çağrılarak başlatılma gerektirir. Bu, varlıklardan saat dilimi verilerini yükler. Başlatmadan sonra API, java.time ile tamamen aynıdır — API 26+ ve API 21+ için kod aynı olacaktır. Kitaplık boyutu yaklaşık 400 KB'dir ve çoğu mobil uygulama için kabul edilebilir.
import org.threeten.bp.LocalDate
import org.threeten.bp.format.DateTimeFormatter
// Application'da başlatma
class App : Application() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
}
}
// API java.time ile aynıdır
val today = LocalDate.now()
val formatted = today.format(DateTimeFormatter.ISO_LOCAL_DATE)
ThreeTenABP'nin performansı, modern cihazlarda orijinal java.time ile karşılaştırılabilir. Eski cihazlarda, saat dilimi verilerinin yüklenmesi nedeniyle ilk çağrıda gecikme olabilir. Mevcut kodu Calendar'dan ThreeTenABP'ye kademeli olarak geçirin: yeni modüllerde Date ve Calendar'ı Instant ve LocalDate ile değiştirin, eski kodu değiştirmeden bırakın.
Unix Timestamp — 1 Ocak 1970 00:00 UTC'den bu yana geçen saniye sayısıdır. Bu, sunucu ve istemci arasında zamanı depolamak ve değiş tokuş etmek için evrensel bir biçimdir. Ancak, cihazdaki saat, kullanıcı ayarları nedeniyle gerçek saatten farklı olabilir. Senkronizasyon için NTP kullanılır — UDP üzerinden hassas zaman protokolü. Unix Timestamp, sunucuda tarih ve saatin depolandığı biçimdir.
iOS'ta Date().timeIntervalSince1970, 1970'ten bu yana saniyeleri döndürür. Android'de System.currentTimeMillis() milisaniyeleri döndürür. Hassasiyet için NTP kullanın: iOS için TrueTime kitaplığı ve Android için AndroidNtp, bir NTP sunucusuna istek gönderir ve zaman farkını hesaplar. NTP hassasiyeti yerel ağda 1-10 ms ve internet üzerinden 10-100 ms'dir.
import Foundation
// iOS'ta Unix Timestamp alma
let seconds = Date().timeIntervalSince1970
let milliseconds = Int64(seconds * 1000)
// TrueTime ile NTP senkronizasyonu
TrueTime.shared.start { result in
switch result {
case .success:
let ntpTime = TrueTime.shared.now()
print("Tam saat: \(ntpTime)")
case .failure(let error):
print("NTP hatası: \(error)")
}
}
Mobil uygulamada senkronizasyon olmadan hatalar mümkündür: yanlış olay zaman damgaları, sunucuyla senkronizasyon kaybı. Mobil geliştirmede zaman, uygulama başlatılırken bir kez NTP ile senkronize edilir, ardından hesaplanan fark kullanılır. Hassasiyet açısından kritik mobil uygulamalar (finans, lojistik) için, sunucuya veri göndermeden önce NTP protokolü zorunludur.
Sıkça Sorulan Sorular
DateFormatter, her örnek oluşturulduğunda biçimlendirme desenini ayrıştırır, yerel ayarı yükler ve saat dilimini belirler. Biçimlendiriciyi statik bir sabit olarak önbelleğe alın veya ISO 8601 için ISO8601DateFormatter kullanın — daha hafif ve hızlıdır.
java.time paketinden DateTimeFormatter — iş parçacığı güvenli ve verimli. API 26'dan itibaren kullanılabilir. Eski sürümler için aynı API'yi sağlayan ThreeTenABP kullanın.
ThreeTenABP ekleyin — Android API 21+ için java.time portu. Application.onCreate() içinde AndroidThreeTen.init() ile başlatın. API, orijinal java.time ile tamamen aynıdır.
Evet, sunucuda ve yerel veritabanında zamanı UTC'de saklayın. Yalnızca görüntüleme aşamasında kullanıcının yerel saat dilimine dönüştürün. Bu, saat dilimi değişikliği veya seyahat sırasında hataları ortadan kaldırır.
Date().timeIntervalSince1970, 1 Ocak 1970'ten bu yana saniye sayısını döndürür. Milisaniye için 1000 ile çarpın ve Int64'e dönüştürün. Hassas senkronizasyon için bir NTP sunucusuyla TrueTime kitaplığını kullanın.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.