DateFormatter, Date nesneleri ile bunların dize temsilleri arasında çift yönlü dönüşüm için tasarlanmış bir Foundation sınıfıdır. Sınıf, kullanıcının yerel ayarını, saat dilimini ve takvimini dikkate alarak dünyanın herhangi bir bölgesinde tarihlerin doğru görüntülenmesini sağlar. Apple Developer Documentation'a (2025) göre DateFormatter, dört önceden ayarlanmış tarih ve saat stilinin yanı sıra bir şablon dizesi aracılığıyla tamamen özel biçimleri destekler. DateFormatter olmadan, uluslararasılaştırılmış bir uygulamada kullanıcıya bir tarihi doğru şekilde görüntülemek imkansızdır.
Önemli Çıkarımlar
DateFormatter, Foundation framework'ünün Date ve dize arasında çift yönlü dönüşüm uygulayan bir sınıfıdır. İlk olarak OpenStep'te NSDateFormatter olarak ortaya çıkmış ve o zamandan beri tüm Apple platformlarında tarih biçimlendirme için birincil araç olarak kalmıştır. Sınıf, Formatter'dan miras alır ve yerelleştirilmiş tarih görüntüleme için kullanışlı bir API sağlar.
DateFormatter, Unicode LDML kalıplarına dayalı olarak çalışır — ICU'da (International Components for Unicode) kullanılanlarla aynı. Kalıp, dateFormat özelliği aracılığıyla ayarlanır ve y, M, d, H, m, s sembolleri yıl, ay, gün, saat, dakika, saniyeye karşılık gelir. Bir sembolün tekrarı biçimi belirler: “y” — iki basamaklı yıl, “yyyy” — dört basamaklı yıl.
DateFormatter oluşturmak pahalı bir işlemdir, çünkü başlatma sırasında yerel ayar ve takvim verileri yüklenir. Apple, her biçimlendirme türü için bir kez biçimlendirici oluşturmayı ve yeniden kullanmayı önerir. SwiftUI ve UIKit'te, biçimlendiriciler genellikle statik özelliklerde önbelleğe alınır veya ilk erişimde tembelce oluşturulur.
DateFormatter, birçok iOS sistem bileşeninde kullanılır. UIDatePicker, countDownTimer modunda tarihleri görüntülemek için dahili olarak DateFormatter'ı kullanır. Bir biçimlendiriciye sahip TextField, kullanıcı tarafından girilen tarihleri otomatik olarak doğrulayabilir. Core Data, Date türündeki nitelikleri destekler, ancak bunların dize temsili her zaman DateFormatter aracılığıyla gerçekleştirilir.
İş Parçacığı Güvenliği — DateFormatter iş parçacığı güvenli değildir. Farklı iş parçacıklarından biçimlendirici özelliklerini değiştirmek tanımsız davranışa yol açar. Çok iş parçacıklı kullanım için, her iş parçacığı için ayrı biçimlendirici örnekleri oluşturun veya NSLock veya seri kuyruk aracılığıyla senkronizasyon kullanın.
dateStyle ve timeStyle, tarih görüntülemeyi yapılandırmanın en basit yollarıdır. Her stilin dört çeşidi vardır: .short, .medium, .long, .full. dateStyle ve timeStyle'ın kombinasyonu, tarih ve saat biçiminin bağımsız olarak yapılandırılmasına olanak tanır ve .none özelliği ilgili kısmı devre dışı bırakır.
ABD yerel ayarı için .short, tarihi “7/21/26” olarak biçimlendirir ve Rus yerel ayarı için “21.07.2026” olarak. Rus yerel ayarı için .long stili “21 Temmuz 2026” çıktısını verir ve .full, haftanın günüyle birlikte “Salı, 21 Temmuz 2026” çıktısını verir. Dört stilin tümü, bileşen sırası ve ayırıcılar dahil olmak üzere otomatik olarak bölgesel standartlara uyum sağlar.
iOS 15+ içindeki SFDateFormatter, RelativeDateFormatter ve DateIntervalFormatter aracılığıyla alternatif bir yaklaşım sunar. RelativeDateFormatter, anlık bağlam için “bugün”, “dün”, “3 gün içinde” çıktısını verir. DateIntervalFormatter, tarih aralıklarını görüntüler: “21–25 Temmuz 2026” — rezervasyonlar ve planlama için.
| Stil | Örnek (ru_RU) | Örnek (en_US) |
|---|---|---|
| .short | 21.07.2026 | 7/21/26 |
| .medium | 21 Tem 2026 | Jul 21, 2026 |
| .long | 21 Temmuz 2026 | July 21, 2026 |
| .full | Salı, 21 Temmuz 2026 | Tuesday, July 21, 2026 |
Stilleri birleştirirken, DateFormatter otomatik olarak ayırıcıyı seçer: .short.date + .short.time için sonuç “21.07.2026, 14:30” olabilir. .full.date + .full.time için — “Salı, 21 Temmuz 2026, 14:30:00 MSK”. Ayırıcı, geliştirici tarafından değil, yerel ayar tarafından yönetilir — bu, kullanıcının bölgesel beklentilerine uygunluğu garanti eder.
dateFormat, Unicode LDML belirtim sembollerini kullanarak isteğe bağlı bir biçimlendirme kalıbı ayarlamaya olanak tanır. Bu, görüntüleme üzerinde tam kontrol sağlar: yalnızca yıl ve ayı veya tarihsiz haftanın gününü veya saniyesiz saati görüntüleyebilirsiniz. Özel biçim, belirli tasarım gereksinimleri için vazgeçilmezdir.
Ana semboller — yyyy (yıl: 2026), MM (ay: 07), dd (gün: 21), HH (saat: 14), mm (dakika: 30), ss (saniye: 00). Tam ay adı için MMMM (Temmuz), kısaltılmış için — MMM (Tem) kullanın. Haftanın günü — EEEE (Salı), kısaltılmış — E (Sal).
dateFormat kullanırken biçimlendiricinin yerel ayarını ayarlamak önemlidir. Yerel ayar ayarlanmazsa, biçimlendirici sistem yerel ayarını kullanır, bu bir API'de sabit bir biçim için istenmeyebilir. Apple, özellikle sunucu yanıtlarından tarihleri ayrıştırırken, sabit bir bölgeler arası biçim için locale = Locale(identifier: “en_US_POSIX”) ayarlamayı önerir.
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.dateFormat = "d MMMM yyyy"
let customString = formatter.string(from: Date())
// "21 July 2026"
// Özel bir dizeyi ayrıştırma
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = formatter.date(from: "2026-07-21 14:30:00")!
dateFormat'taki bir hata, uygulama çökmelerinin yaygın nedenlerinden biridir. Biçim dizeyle eşleşmezse, date(from:) yöntemi nil döndürür. Güvenli isteğe bağlı açma için guard let veya ?? kullanın. Biçimi doğrulamak için, desteklenen tüm dillerde test edin — bazı LDML sembolleri farklı yerel ayarlarda farklı çalışır.
Locale, ay adlarının, haftanın günü adlarının ve ayırıcıların nasıl görüntüleneceğini belirler. DateFormatter varsayılan olarak Locale.current kullanır, ancak bazı senaryolarda belirli bir yerel ayar belirtilmesi gerekir: günlüklerde sabit bir biçim için en_US_POSIX kullanın, sunucu tarihleri için — sunucuyla eşleşen yerel ayarı kullanın.
TimeZone özelliği, görüntüleme için saat dilimini belirler. Varsayılan olarak sistem saat dilimi kullanılır, ancak uluslararası kitleye sahip uygulamalar için genellikle tarihlerin kullanıcının saat diliminde veya UTC'de görüntülenmesi gerekir. TimeZone'u değiştirmek yalnızca görüntülemeyi etkiler — Date değeri değişmez.
Önemli bir özellik: DateFormatter bir dizeyi ayrıştırmak için kullanılırsa ve dize bir saat dilimi göstergesi içeriyorsa (örneğin, UTC için Z ile “2026-07-21T14:30:00Z”), timeZone özelliği yok sayılır — biçimlendirici dizedeki saat dilimini kullanır. Dizede saat dilimi yoksa, biçimlendiricinin timeZone'u uygulanır.
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.timeZone = TimeZone(identifier: "Europe/Moscow")
formatter.dateStyle = .long
formatter.timeStyle = .short
let moscowTime = formatter.string(from: Date())
// "21 July 2026, 14:30"
// Dizede saat dilimi olmadan ayrıştırma
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd HH:mm"
let utcDate = formatter.date(from: "2026-07-21 10:30")!
AutoupdatingCurrentLocale — kullanıcının sistem ayarları değiştiğinde otomatik olarak güncellenen özel bir yerel ayar türüdür. DateFormatter varsayılan olarak bunu destekler. Uygulama arka planda çalışırken kullanıcı sistem dilini değiştirirse, değişiklikten önce oluşturulan bir biçimlendirici eski yerel ayarı kullanmaya devam eder — güncellemek için yeni bir örnek oluşturulması gerekir.
ISO8601DateFormatter, ISO 8601 biçimindeki tarihlerle çalışmak için özel bir biçimlendiricidir. Bu biçim, REST API'leri, JSON ve veri alışverişi için fiili standarttır. ISO8601DateFormatter, yerel ayara bağlı olmadığı ve sabit bir ayrıştırma dil bilgisi kullandığı için DateFormatter'dan önemli ölçüde daha hızlı çalışır.
Ana biçimlendirici seçenekleri — .withInternetDateTime (2026-07-21T14:30:00Z), .withFractionalSeconds (milisaniye ekler), .withTimeZone (saat dilimi farkını içerir). Seçenekleri birleştirerek herhangi bir ISO 8601 çeşidini elde edebilirsiniz: milisaniyeli, saat dilimli, yalnızca tarihli.
JSONEncoder.DateEncodingStrategy, tüm Codable modelleri için küresel olarak tarih kodlamasını yapılandırmaya olanak tanır. Seçenekler — .iso8601 (ISO8601DateFormatter kullanır), .formatted(DateFormatter), .millisecondsSince1970, .secondsSince1970. Strateji seçimi, tüm serileştirme yaşam döngüsünü etkiler ve tüm API uç noktalarında tutarlı olmalıdır.
// ISO8601DateFormatter
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let isoString = isoFormatter.string(from: Date())
// "2026-07-21T14:30:00.000Z"
// ISO8601 ile JSONEncoder
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
// Alternatif: Özel biçimlendirici ile JSONEncoder
let customEncoder = JSONEncoder()
customEncoder.dateEncodingStrategy = .formatted(myFormatter)
DateFormatter vs ISO8601DateFormatter — API'de tarihleri serileştirmek ve ayrıştırmak için ISO8601DateFormatter'ı seçin, çünkü DateFormatter'dan 5-10 kat daha hızlıdır ve yerelleştirme hatalarına eğilimli değildir. Kullanıcının ana dilinde ay ve gün adlarıyla yerelleştirilmiş görüntülemenin gerektiği kullanıcı arabirimi için DateFormatter'ı kullanın.
Bir iOS uygulamasında DateFormatter kullanımının gerçek dünya senaryolarına bakalım: haber akışında tarih görüntüleme, doğum tarihi girme ve farklı saat dilimlerinde tarihler içeren bir raporu dışa aktarma.
RelativeDateFormatter, haber akışları için idealdir. Yeni haberler için “şimdi”, “5 dakika önce”, “dün” görüntüler ve eskileri için tam tarihe geçer. Geçiş eşiği takvim aracılığıyla yapılandırılır: haberler için 24 saatlik bir eşik kullanın, mesajlaşma uygulamaları için — bir hafta.
func formatRelativeDate(_ date: Date) -> String {
let relative = RelativeDateFormatter()
relative.unitsStyle = .full
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let daysDiff = Calendar.current.dateComponents(
[.day], from: date, to: Date()
).day ?? 0
return daysDiff < 1
? relative.localizedString(for: date, relativeTo: Date())
: formatter.string(from: date)
}
Doğum tarihi girme — başka bir yaygın senaryo. DateFormatter, belirli bir dateFormat “dd.MM.yyyy” ve locale “ru_RU” ile yapılandırılır. Girilen dizeyi ayrıştırırken olası hataları ele almak önemlidir: biçimlendirici geçersiz bir dize için nil döndürür. Başarılı ayrıştırmadan sonra, tarihin kabul edilebilir bir aralıkta olduğu kontrol edilir — 1900'den önce değil, bugünden sonra değil.
Tarihler içeren bir raporu dışa aktarma, kullanıcının yerel ayarından bağımsız sabit bir biçim gerektirir. locale en_US_POSIX ve saat dilimi UTC ile dateFormat “yyyy-MM-dd HH:mm:ss” kullanın. Bu yaklaşım, dosyanın sistemin bölgesel ayarlarından bağımsız olarak herhangi bir ülkede do\uğru şekilde açılmasını garanti eder.
| Senaryo | Biçimlendirici | Anahtar Ayar |
|---|---|---|
| Haber akışı | RelativeDateFormatter | unitsStyle = .full |
| Tarih girişi | DateFormatter | dateFormat + yedek |
| API serileştirme | ISO8601DateFormatter | withInternetDateTime |
| Rapor dışa aktarma | DateFormatter | en_US_POSIX + UTC |
Sıkça Sorulan Sorular
En yaygın neden — dateFormat ile dize biçimi arasındaki uyuşmazlık. Örne\uğin, “dd.MM.yyyy” biçimi “2026-07-21” dizesini ayrıştırmaz. İkinci neden — yerel ayar uyuşmazlığı: “July 21, 2026” dizesi ru_RU yerel ayarıyla ayrıştırılmaz. Üçüncüsü — LDML sembollerinde yazım hatası: yyyy kullanın, YYYY değil (farklı anlam).
Hayır. DateFormatter ağır bir nesnedir, başlatılması yerel ayar verilerinin yüklenmesini içerir. Her biçimlendirme türü için bir örnek oluşturun ve yeniden kullanın. Çok iş parçacıklı bir ortamda, iş parçacığı yerel depolamasını veya senkronizasyon için seri kuyruklu bir biçimlendirici havuzu kullanın.
DateFormatter mutlak bir tarih görüntüler (21 Temmuz 2026), RelativeDateFormatter ise göreli bir tarih görüntüler (bugün, dün, 3 gün içinde). RelativeDateFormatter iOS 15+ ile tanıtıldı ve aynı LDML şablonunu kullanır ancak otomatik olarak göreli görüntülemeyi seçer.
Biçimlendiricinin timeZone'unu ayrıştırmadan önce UTC olarak ayarlayın. Sunucu, saat dilimi belirtmeden yerel saatte bir tarih döndürürse, API belirtimini kontrol edin — büyük olasılıkla UTC kastedilmiştir. Sonunda Z olan ISO 8601 için timeZone gerekmez — biçimlendirici dizeden farkı ayrıştırır.
Senkronizasyon olmadan farklı iş parçacıklarından tek bir örnek kullanmayın. Her iş parçacığında yeni bir örnek oluşturun veya depolama için Thread.current.threadDictionary kullanın. Bir alternatif, string(from:) ve date(from:) süresince kilitlemeli NSLock'tur.
Ö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.
Ayrıca okuyun