ISO8601DateFormatter — adalah kelas Foundation di iOS dan macOS, yang dirancang untuk memformat dan mem-parsing tanggal dalam standar internasional ISO 8601. Menurut Apple Developer Documentation, 2024, ISO8601DateFormatter secara otomatis memproses format dengan milidetik, zona waktu, dan pecahan detik tanpa perlu mengatur DateFormat secara manual. Berbeda dengan DateFormatter, kelas ini tidak bergantung pada Locale dan TimeZone — ia bekerja secara ketat sesuai spesifikasi ISO 8601, yang membuatnya ideal untuk pertukaran tanggal antara server dan klien. Kelas ini tersedia mulai iOS 10 dan macOS 10.12.
Poin utama
ISO8601DateFormatter — adalah subkelas khusus dari Formatter di Foundation yang mengimplementasikan konversi dua arah antara Date dan string dalam format ISO 8601. Standar ISO 8601 (International Standard for the Representation of Dates and Times) mendefinisikan format internasional untuk pertukaran tanggal dan waktu: 2024-07-21T14:30:00+00:00. Berbeda dengan DateFormatter, kelas ini tidak memerlukan penentuan dateFormat dan secara otomatis menentukan struktur string berdasarkan opsi yang diberikan.
Keuntungan utama ISO8601DateFormatter dibandingkan DateFormatter: tidak adanya ketergantungan pada locale (parsing bekerja sama di perangkat apa pun), dukungan bawaan untuk pecahan detik (dengan jumlah desimal berapa pun) dan penentuan format secara otomatis berdasarkan opsi yang diberikan. Kelas ini juga menangani dengan benar sufiks Z (penunjukan UTC), zona waktu dalam format +HH:mm dan presisi yang dikurangi (hanya tanggal tanpa waktu).
Menurut ISO Specification (ISO 8601-1:2019), standar mendukung empat tingkat presisi: tahun (2024), tahun-bulan (2024-07), tanggal lengkap (2024-07-21) dan tanggal-waktu dengan zona waktu (2024-07-21T14:30:00+00:00). ISO8601DateFormatter mencakup semua tingkat ini melalui kombinasi opsi format, membebaskan pengembang dari pembuatan string dateFormat secara manual.
Prinsip kerja ISO8601DateFormatter didasarkan pada kombinasi opsi bit (formatOptions), yang masing-masing mengaktifkan komponen tanggal atau waktu tertentu dalam keluaran. Misalnya, opsi .withFullDate mengaktifkan tahun, bulan, dan hari; .withTime — jam, menit, dan detik. Dengan menggabungkan opsi, pengembang mendapatkan tingkat presisi yang diinginkan tanpa menulis string dateFormat.
Secara internal, ISO8601DateFormatter menggunakan pustaka ICU untuk parsing, tetapi dengan aturan ISO 8601 yang tetap. Ini berarti ia mengabaikan pengaturan Locale dan TimeZone yang diatur di perangkat — hasilnya selalu dapat diprediksi. Untuk mengatur zona waktu, digunakan properti timeZone, yang secara default sama dengan UTC. Jika timeZone diatur ke nil, waktu lokal perangkat digunakan.
| Opsi | Deskripsi | Contoh keluaran |
|---|---|---|
| .withFullDate | Tahun, bulan, hari | 2024-07-21 |
| .withTime | Jam, menit, detik | 14:30:00 |
| .withMilliseconds | Pecahan detik (hingga 3 karakter) | .123 |
| .withFractionalSeconds | Pecahan detik (presisi apa pun) | .123456 |
| .withTimeZone | Zona waktu | +03:00 |
| .withColonSeparatorInTimeZone | Pemisah : di zona waktu | +03:00 (bukan +0300) |
| .withInternetDateTime | Format lengkap (date + time + tz) | 2024-07-21T14:30:00+00:00 |
Menggabungkan opsi: .withInternetDateTime setara dengan menggabungkan .withFullDate, .withTime dan .withTimeZone. Untuk mem-parsing string dengan milidetik, tambahkan .withFractionalSeconds. Penting untuk diingat bahwa .withMilliseconds membatasi pecahan detik hingga tiga karakter, sementara .withFractionalSeconds mendukung presisi apa pun — dari satu hingga sembilan digit setelah koma.
Opsi format ISO8601DateFormatter dibagi menjadi tiga kelompok: komponen tanggal (withFullDate, withYear, withMonth, withDay, withWeekOfYear), komponen waktu (withTime, withHours, withMinutes, withSeconds) dan pengaturan tambahan (withMilliseconds, withFractionalSeconds, withTimeZone, withColonSeparatorInTimeZone, withDashSeparatorInDate, withFullTime). Dengan menggabungkannya, Anda bisa mendapatkan hampir semua subformat ISO 8601.
Nuansa penting: .withFractionalSeconds dan .withMilliseconds saling eksklusif — jika keduanya diatur, .withFractionalSeconds yang diterapkan. Untuk mem-parsing milidetik dari data server, disarankan menggunakan .withFractionalSeconds, karena banyak server mengirim pecahan detik dengan tiga, enam, atau sembilan karakter, dan .withFractionalSeconds menangani panjang berapa pun.
import Foundation
// Konfigurasi ISO8601DateFormatter
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)
// Berbagai kombinasi opsi format
formatter.formatOptions = [.withFullDate]
let dateOnly = formatter.string(from: Date())
print("Tanggal: \(dateOnly)")
formatter.formatOptions = [.withFullDate, .withTime]
let dateTime = formatter.string(from: Date())
print("DateTime: \(dateTime)")
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let full = formatter.string(from: Date())
print("Lengkap: \(full)")
// Parsing string dengan milidetik
let serverString = "2024-07-21T14:30:00.123456+03:00"
if let parsed = formatter.date(from: serverString) {
print("Di-parsing: \(parsed)")
}
Penggunaan dasar ISO8601DateFormatter meliputi pembuatan instance, pengaturan timeZone (disarankan UTC untuk data server) dan formatOptions, setelah itu dapat memanggil string(from:) untuk pemformatan dan date(from:) untuk parsing. Berbeda dengan DateFormatter, tidak perlu khawatir tentang Locale — kelas ini mengabaikan pengaturan regional.
import Foundation
let formatter = ISO8601DateFormatter()
// Parsing berbagai format ISO 8601
let strings: [String] = [
"2024-07-21T14:30:00Z",
"2024-07-21T14:30:00+03:00",
"2024-07-21T14:30:00.123Z",
"2024-07-21"
]
for str in strings {
if let autoParsed = formatter.date(from: str) {
print("Di-parsing '\(str)': \(autoParsed)")
} else {
// Gunakan withFullDate untuk string hanya tanggal
formatter.formatOptions = [.withFullDate]
if let fallback = formatter.date(from: str) {
print("Fallback di-parsing '\(str)': \(fallback)")
}
formatter.formatOptions = [.withInternetDateTime]
}
}
// Serialisasi ke RFC 3339 (API GitHub)
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let rfc3339 = formatter.string(from: Date())
print("RFC 3339: \(rfc3339)")
Mem-parsing tanggal dengan detik pecahan dengan panjang variabel — fitur dari banyak API modern. Server dapat mengirim baik 2024-07-21T14:30:00.123Z (3 karakter) maupun 2024-07-21T14:30:00.123456Z (6 karakter). ISO8601DateFormatter dengan opsi .withFractionalSeconds akan menangani kedua varian dengan benar, sementara DateFormatter dengan dateFormat = “yyyy-MM-dd’T’HH:mm:ss.SSSZ” hanya akan memproses milidetik tiga digit.
import Foundation
let variantFormatter = ISO8601DateFormatter()
variantFormatter.formatOptions = [
.withInternetDateTime,
.withFractionalSeconds
]
// Presisi detik pecahan yang berbeda
let variants: [String] = [
"2024-07-21T14:30:00.1Z",
"2024-07-21T14:30:00.12Z",
"2024-07-21T14:30:00.123Z",
"2024-07-21T14:30:00.123456Z",
"2024-07-21T14:30:00.123456789Z"
]
for variant in variants {
if let parsed = variantFormatter.date(from: variant) {
print("OK: \(variant) -> \(parsed)")
} else {
print("FAIL: \(variant)")
}
}
// Gunakan withMilliseconds (hanya 3 digit)
variantFormatter.formatOptions = [
.withInternetDateTime,
.withMilliseconds
]
let milliParsed = variantFormatter.string(from: Date())
print("Dengan milidetik: \(milliParsed)")
Menguji parsing semua varian: kode di atas menunjukkan bahwa ISO8601DateFormatter dengan .withFractionalSeconds berhasil memproses pecahan detik dengan panjang berapa pun dari 1 hingga 9 karakter. Ini penting untuk kompatibilitas dengan berbagai platform server: .NET sering menghasilkan 7 karakter (tik 100-nanodetik), Python — 6, Java — 3 atau 9 tergantung versinya.
DateFormatter juga dapat mem-parsing ISO 8601, tetapi memerlukan pengaturan manual dateFormat, locale dan timeZone. Masalah utamanya adalah DateFormatter bergantung pada Locale, dan jika en_US_POSIX tidak diatur, parsing dapat rusak pada pengguna dari wilayah dengan format tanggal yang tidak standar. ISO8601DateFormatter menyelesaikan masalah ini di tingkat arsitektur: ia tidak menggunakan Locale.
| Parameter | ISO8601DateFormatter | DateFormatter |
|---|---|---|
| Pengaturan Locale | Tidak diperlukan (mengabaikan) | en_US_POSIX wajib |
| DateFormat | Otomatis (melalui opsi) | String format manual |
| Detik pecahan | Presisi apa pun (.withFractionalSeconds) | SSS tetap |
| Sufiks Z | Menangani dengan benar | Melalui dateFormat |
| Kinerja | Lebih tinggi (khusus) | Lebih rendah (umum) |
| Standar | Hanya ISO 8601 | Format apa pun |
| Versi iOS | iOS 10+ | iOS 2+ |
Kapan menggunakan DateFormatter: jika perlu memformat tanggal dalam format non-ISO 8601 (misalnya, „21 Juli 2024” untuk UI) atau jika diperlukan dukungan untuk iOS 9 dan yang lebih lama. Untuk semua tugas pertukaran tanggal dengan server, gunakan ISO8601DateFormatter — lebih aman, lebih berkinerja, dan memerlukan lebih sedikit kode. DateFormatter untuk ISO 8601 adalah sumber potensi bug yang terkait dengan locale dan pengaturan regional.
Migrasi dari DateFormatter ke ISO8601DateFormatter: ganti pembuatan DateFormatter + pengaturan dateFormat + locale + timeZone dengan pembuatan ISO8601DateFormatter + pengaturan formatOptions + timeZone. Parsing string tetap tidak berubah melalui date(from:). Untuk kompatibilitas mundur, dapat menggunakan #available(iOS 10, *) dengan fallback ke DateFormatter.
Pengaturan formatOptions yang terlupakan menyebabkan formatter menggunakan nilai default — .withInternetDateTime. Jika server hanya mengirim tanggal tanpa waktu (2024-07-21), parsing akan mengembalikan nil. Selalu periksa bahwa formatOptions mencakup semua format yang mungkin datang dari server. Untuk API dengan format variabel, gunakan percobaan fallback dengan kombinasi opsi yang berbeda.
Kebingungan antara withMilliseconds dan withFractionalSeconds — kesalahan umum saat mem-parsing tanggal dengan pecahan detik. withMilliseconds mengharapkan tepat 3 digit setelah koma. Jika server mengirim 6 digit (mikrodetik), parsing dengan withMilliseconds akan gagal. Gunakan .withFractionalSeconds untuk kompatibilitas dengan jumlah karakter berapa pun. .withFractionalSeconds muncul di iOS 13; untuk versi yang lebih lama, gunakan DateFormatter dengan dateFormat.
Mengabaikan zona waktu — masalah umum lainnya. Jika server mengirim tanggal dengan zona waktu (+03:00) dan formatter diatur ke UTC, parsing tidak akan gagal, tetapi hasilnya akan dalam UTC. Pengembang sering berharap Date mempertahankan zona waktu, tetapi Date adalah momen waktu absolut dan tidak menyimpan informasi zona waktu. Untuk tampilan yang benar, simpan zona waktu secara terpisah atau gunakan ISO8601DateFormatter dengan timeZone yang benar.
Menurut Apple Forum (2024), sekitar 20% pertanyaan tentang ISO8601DateFormatter terkait dengan format di mana detik bersifat opsional. Standar ISO 8601 mengizinkan format tanpa detik: 2024-07-21T14:30+03:00. ISO8601DateFormatter dengan .withInternetDateTime tidak mendukung format ini — untuk mem-parsingnya diperlukan DateFormatter dengan dateFormat = “yyyy-MM-dd’T’HH:mmZ”. Keterbatasan ini harus dipertimbangkan saat bekerja dengan API yang menggunakan format waktu yang diperpendek.
Pertanyaan yang sering diajukan
ISO8601DateFormatter — kelas Foundation khusus untuk memformat dan mem-parsing tanggal dalam format ISO 8601, tersedia sejak iOS 10. Secara otomatis memproses format standar tanpa pengaturan dateFormat manual.
ISO8601DateFormatter tidak bergantung pada Locale, menggunakan opsi sebagai pengganti dateFormat, dan menangani dengan benar pecahan detik dengan panjang berapa pun. DateFormatter bersifat universal tetapi memerlukan konfigurasi manual dan rentan terhadap bug terkait pengaturan regional.
Gunakan opsi .withFractionalSeconds — mendukung 1 hingga 9 karakter setelah koma. Jangan gunakan .withMilliseconds jika presisi dapat bervariasi. .withFractionalSeconds tersedia sejak iOS 13.
Default UTC. Untuk mengubahnya, atur properti timeZone. Jika timeZone = nil, waktu lokal perangkat digunakan. Saat mem-parsing string dengan zona waktu eksplisit dalam format +HH:MM, formatter akan memperhitungkannya secara otomatis.
Karena formatOptions default = .withInternetDateTime, yang mengharapkan tanggal + waktu + zona waktu. Untuk mem-parsing hanya tanggal, atur formatOptions = [.withFullDate]. Untuk mendukung kedua varian, gunakan fallback dengan opsi yang berbeda.
Ringkasan
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