DateComponents adalah struktur Foundation yang menyimpan komponen tanggal kalender sebagai bidang terpisah: tahun, bulan, hari, jam, menit, detik, dan lainnya. Berbeda dengan Date yang mewakili momen absolut dalam waktu, DateComponents berisi nilai yang dapat dibaca manusia, tergantung pada kalender dan zona waktu. Menurut Apple Developer Documentation (2025), DateComponents digunakan sebagai penghubung antara Date dan Calendar – melalui komponen ini, tanggal kalender diekstrak dan dibangun, perhitungan dan pergeseran tanggal dilakukan tanpa aritmetika manual.
Poin utama
DateComponents adalah tipe nilai Foundation yang dirancang untuk menyimpan komponen kalender waktu. Setiap komponen direpresentasikan sebagai bidang Int opsional: year, month, day, hour, minute, second, nanosecond, weekday, weekOfMonth, weekOfYear, quarter, yearForWeekOfYear, dan lainnya.
Perbedaan utama dari Date adalah keterkaitan dengan kalender. Date menyimpan waktu absolut (jumlah detik dari tanggal referensi), sedangkan DateComponents adalah representasi yang dapat dibaca manusia yang hanya bermakna dalam konteks Calendar tertentu. Date yang sama dapat direpresentasikan dengan DateComponents yang berbeda dalam kalender dan zona waktu yang berbeda.
DateComponents bukanlah tipe waktu mandiri, melainkan wadah data. Untuk menafsirkan DateComponents sebagai tanggal, diperlukan Calendar yang memahami bagaimana komponen terkait dengan sistem kalender. Calendar.dateComponents(from: Date) melakukan ekstraksi komponen, Calendar.date(from: DateComponents) – perakitan terbalik.
Setiap bidang DateComponents bersifat opsional (Int?), yang fundamental untuk bekerja dengan tanggal yang tidak lengkap. Jika Anda hanya menentukan tahun dan bulan, Calendar akan melengkapi bidang yang hilang dengan nilai default: hari = 1, jam = 0, menit = 0. Ini nyaman untuk membuat tanggal awal periode – Anda hanya perlu menentukan komponen yang diminati.
Saat membandingkan DateComponents dengan operator ==, hanya bidang yang ditentukan (tidak nil) yang dibandingkan. Dua struktur DateComponents dengan tahun 2026 tetapi bulan berbeda dianggap berbeda. isEqual dari NSObjectProtocol tidak berlaku untuk DateComponents – DateComponents tidak mewarisi NSObject.
Bidang dasar DateComponents mencakup year, month, day, hour, minute, second, nanosecond. Setiap bidang menyimpan nilai numerik dalam unit yang sesuai: tahun – 2026, bulan – 1..12, hari – 1..31, jam – 0..23, menit – 0..59, detik – 0..59. Nanodetik dapat mengambil nilai 0..999999999.
Bidang minggu – weekday (1..7, di mana 1 = Minggu dalam kalender Gregorian), weekOfMonth, weekOfYear. Bidang-bidang ini tergantung pada Calendar dan tidak bermakna di luar konteksnya. weekday tergantung pada pengaturan firstWeekday kalender: dalam lokal Indonesia, minggu dimulai pada hari Senin (weekday = 2 dalam sistem Gregorian), sedangkan dalam lokal Amerika – pada hari Minggu (weekday = 1).
Bidang khusus – quarter (1..4), yearForWeekOfYear (tahun di mana minggu tersebut berada), isLeapMonth (bendera logis untuk bulan kabisat dalam kalender Ibrani atau Cina). Bidang calendar dan timeZone menyimpan referensi ke objek terkait dengan mana struktur dibuat.
| Kategori | Bidang | Rentang |
|---|---|---|
| Kalender | year, month, day | 1..∞, 1..12, 1..31 |
| Waktu | hour, minute, second, nanosecond | 0..23, 0..59, 0..59, 0..999999999 |
| Mingguan | weekday, weekOfMonth, weekOfYear | 1..7, 1..5, 1..53 |
| Khusus | quarter, yearForWeekOfYear | 1..4, tergantung |
Saat mengekstrak komponen melalui Calendar.dateComponents, penting untuk hanya meminta bidang yang diperlukan demi performa. Calendar mengekstrak semua bidang yang diminta dalam satu lintasan – ini jauh lebih cepat daripada memanggil Calendar.component untuk setiap bidang secara terpisah.
Inisialisasi DateComponents – cara termudah: Anda membuat struktur kosong dan mengisi bidang yang diperlukan. Semua bidang yang tidak ditentukan secara otomatis menerima nil. Tanggal yang dibuat dari komponen parsial tidak divalidasi pada tahap inisialisasi – kesalahan hanya dapat terjadi saat konversi ke Date melalui Calendar.
Inisialisator DateComponents(calendar:timeZone:era:year:month:day:hour:minute:second:nanosecond:weekday:…) memungkinkan pengaturan semua bidang dalam satu panggilan. Inisialisator ini nyaman untuk membuat tanggal lengkap dari nilai yang sudah siap, tetapi jarang digunakan dengan lebih dari 5-6 argumen karena keterbacaan.
Calendar.dateComponents(_:from:) – cara utama untuk mendapatkan DateComponents dari Date yang ada. Argumen kedua adalah kumpulan komponen yang akan diekstrak. Calendar melakukan perhitungan kalender dengan mempertimbangkan zona waktu dan mengembalikan struktur hanya dengan bidang yang diminta, bidang lainnya tetap nil.
import Foundation
// Membuat melalui inisialisator bidang
var components = DateComponents()
components.year = 2026
components.month = 7
components.day = 21
// Mengekstrak dari Date
let now = Date()
let extracted = Calendar.current.dateComponents(
[.year, .month, .day],
from: now
)
print("Today: \(extracted.day!).\(extracted.month!).\(extracted.year!)")
// Membuat melalui inisialisator diperluas
let birthday = DateComponents(
calendar: Calendar.current,
year: 1990, month: 5, day: 15
)
Saat membuat DateComponents melalui bidang secara manual, selalu periksa Calendar sebelum konversi ke Date. Calendar saat konversi date(from:) dapat mengembalikan nil jika komponen membentuk tanggal yang tidak ada – misalnya, 31 Februari atau 30 Februari di tahun non-kabisat. Validasi tanggal adalah tanggung jawab Calendar, bukan DateComponents.
Calendar.date(from:) – metode utama konversi DateComponents ke Date. Calendar menafsirkan komponen sesuai dengan kalender dan zona waktunya. Jika beberapa bidang tidak diatur (nil), Calendar menggunakan nilai default: hari = 1, jam = 0, menit = 0, detik = 0.
Metode mengembalikan Date opsional – nil terjadi ketika komponen saling bertentangan atau membentuk tanggal yang tidak valid. Penyebab umum nil: tanggal yang tidak ada (32 Januari, 29 Februari 2023), bidang yang bertentangan (weekday=1, day=5 dalam satu set), tahun yang tidak mungkin untuk kalender tertentu (tahun 0 dalam kalender Gregorian).
DateComponents dengan timeZone – jika DateComponents berisi timeZone, Calendar menggunakannya saat konversi. Jika timeZone tidak ditentukan, Calendar menggunakan timeZone saat ini. Jika Calendar.timeZone tidak sesuai dengan zona waktu yang diharapkan dari tanggal, hasilnya mungkin berbeda beberapa jam – pastikan timeZone secara eksplisit ditetapkan di salah satu objek.
let calendar = Calendar(identifier: .gregorian)
// Membuat Date dari DateComponents
var comps = DateComponents()
comps.year = 2026
comps.month = 12
comps.day = 25
comps.hour = 10
if let date = calendar.date(from: comps) {
print("Christmas: \(date)")
}
// Membuat dengan menentukan timeZone
calendar.timeZone = TimeZone(identifier: "UTC")!
let utcComps = DateComponents(
calendar: calendar, year: 2026, month: 7, day: 21,
hour: 12
)
let utcDate = calendar.date(from: utcComps)!
Calendar.dateComponents untuk selisih tanggal – skenario lain penggunaan DateComponents. Calendar.dateComponents([.year, .month, .day], from: Date(), to: futureDate) mengembalikan selisih dalam tahun, bulan, dan hari antara dua tanggal. Ini adalah cara yang benar untuk menghitung usia daripada membagi TimeInterval dengan jumlah detik dalam setahun, karena Calendar memperhitungkan tahun kabisat.
Calendar – kelas sentral yang bekerja dengan DateComponents. Semua operasi ekstraksi, perakitan, dan perbandingan tanggal melewati Calendar. Tanpa Calendar, DateComponents hanyalah kumpulan angka tanpa makna temporal. Calendar memberikan interpretasi pada komponen: menentukan bahwa bulan 2 adalah Februari, dan weekday 2 adalah Senin.
Calendar.nextDate dan Calendar.enumerateDates – dua metode yang didasarkan pada DateComponents. nextDate(after: Date(), matching: DateComponents) menemukan tanggal berikutnya yang sesuai dengan komponen yang ditentukan – misalnya, Senin berikutnya setelah hari ini. enumerateDates(startingAfter:matching:matchingPolicy:using:) mengulangi semua tanggal yang sesuai dengan pola hingga batas yang ditentukan.
Calendar.dateInterval – metode yang mengembalikan DateInterval untuk komponen yang ditentukan. dateInterval(of: .month, for: Date()) mengembalikan awal dan akhir bulan saat ini. Secara internal, metode ini menggunakan DateComponents untuk menemukan batas periode: membuat DateComponents dengan hari pertama dan terakhir bulan, mengonversinya ke Date melalui Calendar.
let calendar = Calendar.current
// Senin depan
let nextMonday = calendar.nextDate(
after: Date(),
matching: DateComponents(weekday: 2),
matchingPolicy: .nextTime
)!
// Selisih antara tanggal dalam hari
let diff = calendar.dateComponents(
[.day], from: Date(), to: nextMonday
)
// Rentang bulan
let monthInterval = calendar.dateInterval(
of: .month, for: Date()
)!
let startOfMonth = monthInterval.start
let endOfMonth = monthInterval.end
MatchingPolicy – parameter penting dari metode Calendar saat bekerja dengan DateComponents. strictPolicy memerlukan pencocokan tepat semua komponen, nextTimePolicy memilih pencocokan berikutnya dalam waktu, nextTimePreservingSmallerComponents mempertahankan komponen yang lebih kecil (menit, detik) dari tanggal asli. Pilihan kebijakan memengaruhi hasil pencarian tanggal, terutama saat pergeseran melalui perubahan waktu musim panas/musim dingin.
Kami akan meninjau skenario praktis penggunaan DateComponents dalam aplikasi. Setiap contoh mendemonstrasikan tugas tipikal yang dihadapi pengembang iOS saat bekerja dengan tanggal kalender.
Calendar.nextDate dengan DateComponents(day: 1) menemukan hari pertama bulan berikutnya. Calendar secara otomatis menentukan jumlah hari dalam bulan saat ini dan beralih ke bulan berikutnya. Untuk notifikasi berulang, gunakan enumerateDates atau Combine.Timer dengan kunci Calendar.
func firstDayOfNextMonth(from date: Date) -> Date {
let calendar = Calendar.current
let comps = DateComponents(day: 1)
return calendar.nextDate(
after: date,
matching: comps,
matchingPolicy: .nextTime
)!
}
// Menghitung usia dalam tahun
func ageInYears(from birthDate: Date) -> Int {
let calendar = Calendar.current
let ageComponents = calendar.dateComponents(
[.year], from: birthDate, to: Date()
)
return ageComponents.year ?? 0
}
// Mengelompokkan peristiwa berdasarkan tahun dan bulan
func groupEventsByMonth(_ events: [Event]) -> [String: [Event]] {
let calendar = Calendar.current
return Dictionary(grouping: events) { event in
let comps = calendar.dateComponents(
[.year, .month], from: event.date
)
return "\(comps.year!)-\(comps.month!)"
}
}
Menghitung usia melalui Calendar.dateComponents([.year], from:to:) – satu-satunya cara yang benar yang memperhitungkan tahun kabisat. Perhitungan berbasis TimeInterval (detik / 31536000) memberikan kesalahan untuk orang yang lahir pada 29 Februari. Calendar dengan benar menentukan apakah ulang tahun telah terjadi di tahun berjalan dan mengembalikan usia yang tepat.
Pengelompokan berdasarkan tahun dan bulan – tugas umum untuk layar dengan riwayat atau kalender. DateComponents berfungsi sebagai kunci pengelompokan: Anda mengekstrak tahun dan bulan dari tanggal peristiwa, membentuk kunci string, dan mengelompokkan melalui Dictionary(grouping:). Untuk tampilan, gunakan DateFormatter dengan templat “LLLL yyyy” untuk nama bulan yang dilokalkan.
| Tugas | Metode Calendar | Peran DateComponents |
|---|---|---|
| Hari pertama bulan | nextDate(after:matching:) | day: 1 |
| Menghitung usia | dateComponents(from:to:) | [.year] dari selisih |
| Mengelompokkan tanggal | dateComponents(_:from:) | year + month kunci |
| Mencari hari dalam minggu | nextDate(after:matching:) | weekday: N |
Pertanyaan yang sering diajukan
Penyebab: tanggal yang tidak ada (31 April), bidang yang bertentangan (weekday=1 dengan day=5), kombinasi bidang yang tidak valid untuk kalender yang dipilih. Calendar mencoba menafsirkan komponen dalam sistemnya – jika kombinasi tidak mungkin, hasilnya nil. Selalu gunakan guard let atau if let saat konversi.
Ya, melalui operator ==. DateComponents mengimplementasikan Equatable, membandingkan semua bidang. Dua struktur sama jika semua bidangnya sama (nil == nil dianggap benar). Untuk membandingkan hanya sebagian bidang – ekstrak set yang sama melalui Calendar.dateComponents.
Date – momen absolut dalam waktu tanpa keterkaitan dengan kalender. DateComponents – kumpulan angka yang dapat dibaca manusia (tahun, bulan, hari) yang hanya bermakna dalam konteks Calendar. Date dapat dibandingkan, dikurangkan, diserialisasi ke ISO 8601. DateComponents – representasi perantara untuk interaksi dengan kalender.
Atur hanya bidang year dan month, biarkan sisanya nil. Saat konversi ke Date melalui Calendar.date(from:), Calendar akan secara otomatis mengatur hari = 1, jam = 0, menit = 0. Hasilnya – Date yang sesuai dengan hari pertama bulan yang ditentukan pada tengah malam.
DateComponents tidak menyimpan informasi tentang zona waktu di bidang – nilai bidang (tahun, bulan, hari) sendiri tergantung pada timeZone di mana mereka diekstrak. Komponen “21 Juli 2026 14:00 MSK” dan “21 Juli 2026 10:00 UTC” mewakili Date yang sama, tetapi bidang DateComponents 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