DateFormatter — kelas Foundation yang dirancang untuk konversi dua arah antara objek Date dan representasi stringnya. Kelas ini mempertimbangkan locale, zona waktu, dan kalender pengguna, memastikan tampilan tanggal yang benar di wilayah mana pun di dunia. Menurut Apple Developer Documentation (2025), DateFormatter mendukung empat gaya tanggal dan waktu yang telah ditentukan sebelumnya, serta format yang sepenuhnya khusus melalui string pola. Tanpa DateFormatter, tidak mungkin menampilkan tanggal dengan benar kepada pengguna dalam aplikasi yang diinternasionalisasi.
Utama
DateFormatter — kelas dari framework Foundation yang mengimplementasikan konversi dua arah antara Date dan string. Ini muncul di OpenStep sebagai NSDateFormatter dan sejak itu tetap menjadi alat utama pemformatan tanggal di semua platform Apple. Kelas ini mewarisi dari Formatter dan menyediakan API yang nyaman untuk tampilan tanggal yang dilokalisasi.
Prinsip kerja DateFormatter didasarkan pada pola Unicode LDML — yang sama digunakan di ICU (International Components for Unicode). Pola ditentukan melalui properti dateFormat, di mana simbol y, M, d, H, m, s masing-masing sesuai dengan tahun, bulan, hari, jam, menit, dan detik. Pengulangan simbol menentukan format: “y” — tahun dua digit, “yyyy” — empat digit.
Membuat DateFormatter adalah operasi yang mahal, karena saat inisialisasi data locale dan kalender dimuat. Apple merekomendasikan untuk membuat formatter sekali untuk setiap jenis pemformatan dan menggunakannya kembali. Di SwiftUI dan UIKit, formatter sering di-cache di properti statis atau dibuat secara malas saat pertama kali diakses.
DateFormatter digunakan di banyak komponen sistem iOS. UIDatePicker secara internal menggunakan DateFormatter untuk menampilkan tanggal dalam mode countDownTimer. TextField dengan formatter di input dapat secara otomatis memvalidasi tanggal yang dimasukkan pengguna. Core Data mendukung atribut tipe Date, tetapi tampilan stringnya selalu dilakukan melalui DateFormatter.
Thread Safety — DateFormatter tidak aman untuk thread. Mengubah properti formatter dari thread yang berbeda menyebabkan perilaku yang tidak terdefinisi. Untuk penggunaan multi-thread, buat instance formatter terpisah untuk setiap thread atau gunakan sinkronisasi melalui NSLock atau serial queue.
dateStyle dan timeStyle — cara paling sederhana untuk mengatur tampilan tanggal. Setiap gaya memiliki empat varian: .short, .medium, .long, .full. Kombinasi dateStyle dan timeStyle memungkinkan konfigurasi format tanggal dan waktu secara independen, dan properti .none menonaktifkan bagian yang sesuai.
Untuk locale Amerika, gaya .short memformat tanggal sebagai “7/21/26”, dan untuk Indonesia — sebagai “21/07/2026”. Gaya .long untuk locale Indonesia menampilkan “21 Juli 2026”, dan .full — “Selasa, 21 Juli 2026” dengan menyebutkan hari dalam seminggu. Keempat gaya secara otomatis menyesuaikan dengan standar regional, termasuk urutan komponen dan pemisah.
RelativeDateFormatter di iOS 15+ menawarkan pendekatan alternatif melalui RelativeDateFormatter dan DateIntervalFormatter. RelativeDateFormatter menampilkan “hari ini”, “kemarin”, “3 hari lagi” untuk konteks saat ini. DateIntervalFormatter menampilkan rentang tanggal: “21–25 Juli 2026” — untuk pemesanan dan perencanaan.
| Gaya | Contoh (id_ID) | Contoh (en_US) |
|---|---|---|
| .short | 21/07/2026 | 7/21/26 |
| .medium | 21 Jul 2026 | Jul 21, 2026 |
| .long | 21 Juli 2026 | July 21, 2026 |
| .full | Selasa, 21 Juli 2026 | Tuesday, July 21, 2026 |
Saat menggabungkan gaya, DateFormatter secara otomatis memilih pemisah: untuk .short.date + .short.time hasilnya mungkin “21/07/2026, 14:30”. Untuk .full.date + .full.time — “Selasa, 21 Juli 2026, 14:30:00 MSK”. Pemisah dikendalikan oleh locale, bukan pengembang — ini menjamin kesesuaian dengan harapan regional pengguna.
dateFormat memungkinkan Anda menentukan pola pemformatan arbitrer menggunakan simbol spesifikasi Unicode LDML. Ini memberikan kontrol penuh atas tampilan: Anda dapat menampilkan hanya tahun dan bulan, hari dalam seminggu tanpa angka, atau waktu tanpa detik. Format kustom sangat diperlukan untuk kebutuhan desain tertentu.
Simbol dasar — yyyy (tahun: 2026), MM (bulan: 07), dd (hari: 21), HH (jam: 14), mm (menit: 30), ss (detik: 00). Untuk nama bulan lengkap gunakan MMMM (Juli), untuk singkatan — MMM (Jul). Hari dalam seminggu — EEEE (Selasa), singkatan — E (Sel).
Saat menggunakan dateFormat, penting untuk mengatur locale formatter. Jika locale tidak diatur, formatter menggunakan locale sistem, yang mungkin tidak diinginkan untuk format tetap di API. Apple merekomendasikan pengaturan locale = Locale(identifier: “en_US_POSIX”) untuk format antar-regional yang tetap, terutama saat menguraikan tanggal dari respons server.
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.dateFormat = "d MMMM yyyy"
let customString = formatter.string(from: Date())
// "21 July 2026"
// Parsing string khusus
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = formatter.date(from: "2026-07-21 14:30:00")!
Kesalahan di dateFormat — salah satu penyebab umum crash aplikasi. Jika format tidak cocok dengan string, metode date(from:) mengembalikan nil. Gunakan guard let atau ?? untuk mengekstrak nilai opsional dengan aman. Untuk validasi format, uji pada semua bahasa yang didukung — beberapa simbol LDML bekerja berbeda di locale yang berbeda.
Locale menentukan bagaimana nama bulan, hari dalam seminggu, dan pemisah ditampilkan. DateFormatter secara default menggunakan Locale.current, tetapi dalam beberapa skenario diperlukan penentuan locale tertentu: untuk format tetap di log gunakan en_US_POSIX, untuk tanggal server — locale yang identik dengan server.
Properti TimeZone menentukan zona waktu untuk tampilan. Secara default, zona waktu sistem digunakan, tetapi untuk aplikasi dengan audiens internasional sering diperlukan menampilkan tanggal di zona waktu pengguna atau di UTC. Mengubah timeZone hanya memengaruhi tampilan — nilai Date tetap tidak berubah.
Fitur penting: jika DateFormatter digunakan untuk mengurai string, dan string berisi indikasi zona waktu (misalnya, “2026-07-21T14:30:00Z” dengan Z untuk UTC), properti timeZone diabaikan — formatter menggunakan zona waktu dari string. Jika zona waktu tidak ada dalam string, timeZone formatter yang diterapkan.
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"
// Parsing tanpa zona waktu dalam string
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd HH:mm"
let utcDate = formatter.date(from: "2026-07-21 10:30")!
AutoupdatingCurrentLocale — tipe locale khusus yang secara otomatis diperbarui saat pengaturan sistem pengguna berubah. DateFormatter mendukungnya secara default. Jika aplikasi berjalan di latar belakang dan pengguna mengubah bahasa sistem, formatter yang dibuat sebelum perubahan akan terus menggunakan locale lama — untuk pembaruan perlu membuat instance baru.
ISO8601DateFormatter — formatter khusus untuk bekerja dengan tanggal dalam format ISO 8601. Format ini adalah standar de facto untuk REST API, JSON, dan pertukaran data. ISO8601DateFormatter bekerja jauh lebih cepat daripada DateFormatter karena tidak bergantung pada locale dan menggunakan tata bahasa parsing yang tetap.
Opsi utama formatter — .withInternetDateTime (2026-07-21T14:30:00Z), .withFractionalSeconds (menambahkan milidetik), .withTimeZone (menyertakan offset zona waktu). Dengan menggabungkan opsi, Anda bisa mendapatkan varian ISO 8601 apa pun: dengan milidetik, dengan zona waktu, dengan tanggal tanpa waktu.
JSONEncoder.DateEncodingStrategy memungkinkan Anda mengonfigurasi pengkodean tanggal secara global untuk semua model Codable. Varian — .iso8601 (menggunakan ISO8601DateFormatter), .formatted(DateFormatter), .millisecondsSince1970, .secondsSince1970. Pemilihan strategi memengaruhi seluruh siklus hidup serialisasi dan harus seragam untuk semua endpoint API.
// ISO8601DateFormatter
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let isoString = isoFormatter.string(from: Date())
// "2026-07-21T14:30:00.000Z"
// JSONEncoder dengan ISO8601
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
// Alternatif: JSONEncoder dengan formatter khusus
let customEncoder = JSONEncoder()
customEncoder.dateEncodingStrategy = .formatted(myFormatter)
DateFormatter vs ISO8601DateFormatter — pilih ISO8601DateFormatter untuk serialisasi dan parsing tanggal di API, karena bekerja 5-10 kali lebih cepat daripada DateFormatter dan tidak rentan terhadap kesalahan lokalisasi. Biarkan DateFormatter untuk antarmuka pengguna, di mana tampilan yang dilokalisasi dengan nama bulan dan hari dalam seminggu dalam bahasa ibu pengguna diperlukan.
Mari kita pertimbangkan skenario nyata penggunaan DateFormatter di aplikasi iOS: menampilkan di daftar berita, memasukkan tanggal lahir, dan mengekspor laporan dengan tanggal di zona waktu berbeda.
RelativeDateFormatter optimal untuk feed berita. Ini menampilkan “baru saja”, “5 menit yang lalu”, “kemarin” untuk berita terbaru dan beralih ke tanggal lengkap untuk yang lama. Ambang peralihan dikonfigurasi melalui calendar: untuk berita gunakan ambang 24 jam, untuk messenger — seminggu.
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)
}
Memasukkan tanggal lahir — skenario umum lainnya. DateFormatter dikonfigurasi dengan dateFormat tertentu “dd/MM/yyyy” dan locale “id_ID”. Saat mengurai string yang dimasukkan, penting untuk menangani kemungkinan kesalahan: formatter mengembalikan nil untuk string yang salah. Setelah parsing berhasil, tanggal diperiksa apakah berada dalam rentang yang diizinkan — tidak lebih awal dari 1900, tidak lebih lambat dari hari ini.
Mengekspor laporan dengan tanggal membutuhkan format tetap yang tidak tergantung pada locale pengguna. Gunakan dateFormat “yyyy-MM-dd HH:mm:ss” dengan locale en_US_POSIX dan zona waktu UTC. Pendekatan ini menjamin bahwa file akan terbuka dengan benar di negara mana pun terlepas dari pengaturan regional sistem.
| Skenario | Formatter | Pengaturan Kunci |
|---|---|---|
| Feed berita | RelativeDateFormatter | unitsStyle = .full |
| Input tanggal | DateFormatter | dateFormat + fallback |
| Serialisasi API | ISO8601DateFormatter | withInternetDateTime |
| Ekspor laporan | DateFormatter | en_US_POSIX + UTC |
Pertanyaan yang Sering Diajukan
Penyebab paling umum — ketidakcocokan dateFormat dengan format string. Misalnya, format “dd/MM/yyyy” tidak akan mengurai string “2026-07-21”. Penyebab kedua — ketidakcocokan locale: string “July 21, 2026” tidak akan diurai dengan locale id_ID. Ketiga — kesalahan ketik di simbol LDML: gunakan yyyy, bukan YYYY (berbeda arti).
Tidak. DateFormatter adalah objek berat, inisialisasinya mencakup memuat data locale. Buat satu instance per jenis pemformatan dan gunakan kembali. Di lingkungan multi-thread, gunakan Thread-local storage atau kumpulan formatter dengan serial queue untuk sinkronisasi.
DateFormatter menampilkan tanggal absolut (21 Juli 2026), sedangkan RelativeDateFormatter — tanggal relatif (hari ini, kemarin, 3 hari lagi). RelativeDateFormatter muncul di iOS 15+ dan menggunakan pola LDML yang sama, tetapi secara otomatis memilih tampilan relatif.
Atur timeZone formatter ke UTC sebelum parsing. Jika server mengembalikan tanggal dalam waktu lokal tanpa indikasi zona, periksa spesifikasi API — kemungkinan besar yang dimaksud adalah UTC. Untuk ISO 8601 dengan Z di akhir, timeZone tidak diperlukan — formatter mengurai offset dari string.
Jangan gunakan satu instance dari thread yang berbeda tanpa sinkronisasi. Buat instance baru di setiap thread atau gunakan Thread.current.threadDictionary untuk penyimpanan. Alternatif — NSLock dengan penguncian selama string(from:) dan date(from:).
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga