DateComponents είναι μια δομή Foundation που αποθηκεύει τα στοιχεία μιας ημερολογιακής ημερομηνίας ως ξεχωριστά πεδία: έτος, μήνας, ημέρα, ώρα, λεπτό, δευτερόλεπτο και άλλα. Σε αντίθεση με το Date, που αντιπροσωπεύει μια απόλυτη χρονική στιγμή, το DateComponents περιέχει τιμές αναγνώσιμες από τον άνθρωπο, εξαρτώμενες από το ημερολόγιο και τη ζώνη ώρας. Σύμφωνα με το Apple Developer Documentation (2025), το DateComponents χρησιμοποιείται ως ενδιάμεσος κρίκος μεταξύ Date και Calendar – μέσω αυτού εξάγονται και κατασκευάζονται ημερολογιακές ημερομηνίες, εκτελούνται υπολογισμοί και μετατοπίσεις ημερομηνιών χωρίς χειροκίνητη αριθμητική.
Κύρια σημεία
DateComponents είναι ένας τύπος τιμής Foundation που προορίζεται για την αποθήκευση ημερολογιακών στοιχείων χρόνου. Κάθε στοιχείο αναπαρίσταται ως προαιρετικό πεδίο Int: year, month, day, hour, minute, second, nanosecond, weekday, weekOfMonth, weekOfYear, quarter, yearForWeekOfYear και άλλα.
Η κύρια διαφορά από το Date είναι η σύνδεση με το ημερολόγιο. Το Date αποθηκεύει απόλυτο χρόνο (αριθμό δευτερολέπτων από την ημερομηνία αναφοράς), ενώ το DateComponents είναι μια αναγνώσιμη από τον άνθρωπο αναπαράσταση που έχει νόημα μόνο στο πλαίσιο ενός συγκεκριμένου Calendar. Η ίδια Date μπορεί να αναπαρασταθεί με διαφορετικά DateComponents σε διαφορετικά ημερολόγια και ζώνες ώρας.
Το DateComponents δεν είναι ανεξάρτητος τύπος χρόνου, αλλά ένα δοχείο δεδομένων. Για την ερμηνεία του DateComponents ως ημερομηνίας απαιτείται ένα Calendar που κατανοεί πώς τα στοιχεία σχετίζονται με το ημερολογιακό σύστημα. Το Calendar.dateComponents(from: Date) εκτελεί εξαγωγή στοιχείων, το Calendar.date(from: DateComponents) – αντίστροφη συναρμολόγηση.
Κάθε πεδίο DateComponents είναι προαιρετικό (Int?), κάτι που είναι θεμελιώδες για την εργασία με ελλιπείς ημερομηνίες. Εάν καθορίσετε μόνο το έτος και τον μήνα, το Calendar θα συμπληρώσει τα πεδία που λείπουν με προεπιλεγμένες τιμές: ημέρα = 1, ώρα = 0, λεπτό = 0. Αυτό είναι βολικό για τη δημιουργία ημερομηνιών έναρξης περιόδου – χρειάζεται να καθορίσετε μόνο τα σχετικά στοιχεία.
Κατά τη σύγκριση DateComponents με τον τελεστή ==, συγκρίνονται μόνο τα καθορισμένα (μη nil) πεδία. Δύο δομές DateComponents με έτος 2026 αλλά διαφορετικούς μήνες θεωρούνται διαφορετικές. Το isEqual από το NSObjectProtocol δεν εφαρμόζεται για DateComponents – το DateComponents δεν κληρονομεί από το NSObject.
Βασικά πεδία των DateComponents περιλαμβάνουν year, month, day, hour, minute, second, nanosecond. Κάθε πεδίο αποθηκεύει μια αριθμητική τιμή στην αντίστοιχη μονάδα: έτος – 2026, μήνας – 1..12, ημέρα – 1..31, ώρα – 0..23, λεπτό – 0..59, δευτερόλεπτο – 0..59. Τα νανοδευτερόλεπτα μπορούν να λάβουν τιμές 0..999999999.
Πεδία εβδομάδας – weekday (1..7, όπου 1 = Κυριακή στο Γρηγοριανό ημερολόγιο), weekOfMonth, weekOfYear. Αυτά τα πεδία εξαρτώνται από το Calendar και δεν έχουν νόημα εκτός του πλαισίου του. Το weekday εξαρτάται από τη ρύθμιση firstWeekday του ημερολογίου: στο ελληνικό locale η εβδομάδα ξεκινά από τη Δευτέρα (weekday = 2 στο Γρηγοριανό σύστημα), ενώ στο αμερικανικό – από την Κυριακή (weekday = 1).
Εξειδικευμένα πεδία – quarter (1..4), yearForWeekOfYear (το έτος στο οποίο ανήκει η εβδομάδα), isLeapMonth (λογική σημαία για δίσεκτους μήνες στο Εβραϊκό ή Κινεζικό ημερολόγιο). Τα πεδία calendar και timeZone αποθηκεύουν αναφορές στα αντίστοιχα αντικείμενα με τα οποία δημιουργήθηκε η δομή.
| Κατηγορία | Πεδία | Εύρος |
|---|---|---|
| Ημερολογιακά | year, month, day | 1..∞, 1..12, 1..31 |
| Χρονικά | hour, minute, second, nanosecond | 0..23, 0..59, 0..59, 0..999999999 |
| Εβδομαδιαία | weekday, weekOfMonth, weekOfYear | 1..7, 1..5, 1..53 |
| Ειδικά | quarter, yearForWeekOfYear | 1..4, εξαρτώμενο |
Κατά την εξαγωγή στοιχείων μέσω Calendar.dateComponents, είναι σημαντικό να ζητάτε μόνο τα απαραίτητα πεδία για απόδοση. Το Calendar εξάγει όλα τα ζητούμενα πεδία σε ένα πέρασμα – αυτό είναι σημαντικά ταχύτερο από την κλήση του Calendar.component για κάθε πεδίο ξεχωριστά.
Αρχικοποίηση DateComponents – ο απλούστερος τρόπος: δημιουργείτε μια κενή δομή και συμπληρώνετε τα απαραίτητα πεδία. Όλα τα μη καθορισμένα πεδία λαμβάνουν αυτόματα nil. Η ημερομηνία που δημιουργείται από μερικά στοιχεία δεν επικυρώνεται στο στάδιο αρχικοποίησης – σφάλμα μπορεί να προκύψει μόνο κατά τη μετατροπή σε Date μέσω Calendar.
Ο αρχικοποιητής DateComponents(calendar:timeZone:era:year:month:day:hour:minute:second:nanosecond:weekday:…) επιτρέπει τον ορισμό όλων των πεδίων σε μία κλήση. Αυτός ο αρχικοποιητής είναι βολικός για τη δημιουργία πλήρους ημερομηνίας από έτοιμες τιμές, αλλά σπάνια χρησιμοποιείται με περισσότερα από 5-6 ορίσματα λόγω αναγνωσιμότητας.
Calendar.dateComponents(_:from:) – ο κύριος τρόπος λήψης DateComponents από μια υπάρχουσα Date. Το δεύτερο όρισμα είναι το σύνολο στοιχείων που πρέπει να εξαχθούν. Το Calendar εκτελεί ημερολογιακούς υπολογισμούς λαμβάνοντας υπόψη τη ζώνη ώρας και επιστρέφει μια δομή μόνο με τα ζητούμενα πεδία, τα υπόλοιπα πεδία παραμένουν nil.
import Foundation
// Δημιουργία μέσω αρχικοποιητή πεδίων
var components = DateComponents()
components.year = 2026
components.month = 7
components.day = 21
// Εξαγωγή από Date
let now = Date()
let extracted = Calendar.current.dateComponents(
[.year, .month, .day],
from: now
)
print("Today: \(extracted.day!).\(extracted.month!).\(extracted.year!)")
// Δημιουργία μέσω εκτεταμένου αρχικοποιητή
let birthday = DateComponents(
calendar: Calendar.current,
year: 1990, month: 5, day: 15
)
Κατά τη δημιουργία DateComponents μέσω χειροκίνητων πεδίων, ελέγχετε πάντα το Calendar πριν από τη μετατροπή σε Date. Το Calendar κατά τη μετατροπή date(from:) μπορεί να επιστρέψει nil εάν τα στοιχεία σχηματίζουν μια ανύπαρκτη ημερομηνία – για παράδειγμα, 31 Φεβρουαρίου ή 30 Φεβρουαρίου σε μη δίσεκτο έτος. Η επικύρωση ημερομηνίας είναι ευθύνη του Calendar, όχι του DateComponents.
Calendar.date(from:) – η κύρια μέθοδος μετατροπής DateComponents σε Date. Το Calendar ερμηνεύει τα στοιχεία σύμφωνα με το ημερολόγιο και τη ζώνη ώρας του. Εάν ορισμένα πεδία δεν έχουν οριστεί (nil), το Calendar χρησιμοποιεί προεπιλεγμένες τιμές: ημέρα = 1, ώρα = 0, λεπτό = 0, δευτερόλεπτο = 0.
Η μέθοδος επιστρέφει μια προαιρετική Date – nil συμβαίνει όταν τα στοιχεία αντιφάσκουν μεταξύ τους ή σχηματίζουν μη έγκυρη ημερομηνία. Τυπικές αιτίες nil: ανύπαρκτη ημερομηνία (32 Ιανουαρίου, 29 Φεβρουαρίου 2023), αντιφατικά πεδία (weekday=1, day=5 στο ίδιο σύνολο), αδύνατο έτος για το δεδομένο ημερολόγιο (έτος 0 στο Γρηγοριανό ημερολόγιο).
DateComponents με timeZone – εάν το DateComponents περιέχει timeZone, το Calendar το χρησιμοποιεί κατά τη μετατροπή. Εάν το timeZone δεν έχει οριστεί, το Calendar χρησιμοποιεί τη δική του τρέχουσα timeZone. Εάν το Calendar.timeZone δεν συμπίπτει με την αναμενόμενη ζώνη ώρας της ημερομηνίας, το αποτέλεσμα μπορεί να διαφέρει κατά μερικές ώρες – βεβαιωθείτε ότι η timeZone έχει οριστεί ρητά σε ένα από τα αντικείμενα.
let calendar = Calendar(identifier: .gregorian)
// Δημιουργία Date από 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)")
}
// Δημιουργία με καθορισμό 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 για διαφορά ημερομηνιών – ένα άλλο σενάριο χρήσης DateComponents. Το Calendar.dateComponents([.year, .month, .day], from: Date(), to: futureDate) επιστρέφει τη διαφορά σε έτη, μήνες και ημέρες μεταξύ δύο ημερομηνιών. Αυτός είναι ο σωστός τρόπος υπολογισμού ηλικίας αντί της διαίρεσης του TimeInterval με τον αριθμό δευτερολέπτων σε ένα έτος, επειδή το Calendar λαμβάνει υπόψη τα δίσεκτα έτη.
Calendar – η κεντρική κλάση που εργάζεται με DateComponents. Όλες οι λειτουργίες εξαγωγής, συναρμολόγησης και σύγκρισης ημερομηνιών περνούν μέσω του Calendar. Χωρίς Calendar, το DateComponents είναι απλώς μια συλλογή αριθμών χωρίς χρονική σημασία. Το Calendar δίνει ερμηνεία στα στοιχεία: καθορίζει ότι ο μήνας 2 είναι Φεβρουάριος και το weekday 2 είναι Δευτέρα.
Calendar.nextDate και Calendar.enumerateDates – δύο μέθοδοι που βασίζονται σε DateComponents. Η nextDate(after: Date(), matching: DateComponents) βρίσκει την επόμενη ημερομηνία που αντιστοιχεί στα καθορισμένα στοιχεία – για παράδειγμα, την επόμενη Δευτέρα μετά από σήμερα. Η enumerateDates(startingAfter:matching:matchingPolicy:using:) επαναλαμβάνει όλες τις ημερομηνίες που ταιριάζουν με το μοτίβο μέχρι ένα καθορισμένο όριο.
Calendar.dateInterval – μια μέθοδος που επιστρέφει DateInterval για το καθορισμένο στοιχείο. Η dateInterval(of: .month, for: Date()) επιστρέφει την αρχή και το τέλος του τρέχοντος μήνα. Εσωτερικά, αυτή η μέθοδος χρησιμοποιεί DateComponents για να βρει τα όρια της περιόδου: δημιουργεί DateComponents με την πρώτη και την τελευταία ημέρα του μήνα, τα μετατρέπει σε Date μέσω Calendar.
let calendar = Calendar.current
// Επόμενη Δευτέρα
let nextMonday = calendar.nextDate(
after: Date(),
matching: DateComponents(weekday: 2),
matchingPolicy: .nextTime
)!
// Διαφορά μεταξύ ημερομηνιών σε ημέρες
let diff = calendar.dateComponents(
[.day], from: Date(), to: nextMonday
)
// Εύρος μήνα
let monthInterval = calendar.dateInterval(
of: .month, for: Date()
)!
let startOfMonth = monthInterval.start
let endOfMonth = monthInterval.end
MatchingPolicy – μια σημαντική παράμετρος των μεθόδων Calendar κατά την εργασία με DateComponents. Η strictPolicy απαιτεί ακριβή αντιστοίχιση όλων των στοιχείων, η nextTimePolicy επιλέγει την επόμενη χρονική αντιστοίχιση, η nextTimePreservingSmallerComponents διατηρεί τα μικρότερα στοιχεία (λεπτά, δευτερόλεπτα) από την αρχική ημερομηνία. Η επιλογή πολιτικής επηρεάζει το αποτέλεσμα αναζήτησης ημερομηνιών, ειδικά κατά τη μετατόπιση μέσω αλλαγής θερινής/χειμερινής ώρας.
Θα εξετάσουμε πρακτικά σενάρια χρήσης DateComponents σε μια εφαρμογή. Κάθε παράδειγμα δείχνει μια τυπική εργασία που αντιμετωπίζει ένας προγραμματιστής iOS κατά την εργασία με ημερολογιακές ημερομηνίες.
Η Calendar.nextDate με DateComponents(day: 1) βρίσκει την πρώτη ημέρα του επόμενου μήνα. Το Calendar καθορίζει αυτόματα τον αριθμό ημερών στον τρέχοντα μήνα και μεταβαίνει στον επόμενο μήνα. Για επαναλαμβανόμενες ειδοποιήσεις, χρησιμοποιήστε το enumerateDates ή το Combine.Timer με κλειδί 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
)!
}
// Υπολογισμός ηλικίας σε έτη
func ageInYears(from birthDate: Date) -> Int {
let calendar = Calendar.current
let ageComponents = calendar.dateComponents(
[.year], from: birthDate, to: Date()
)
return ageComponents.year ?? 0
}
// Ομαδοποίηση συμβάντων κατά έτος και μήνα
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!)"
}
}
Υπολογισμός ηλικίας μέσω Calendar.dateComponents([.year], from:to:) – ο μόνος σωστός τρόπος που λαμβάνει υπόψη τα δίσεκτα έτη. Ο υπολογισμός βάσει TimeInterval (δευτερόλεπτα / 31536000) δίνει σφάλμα για άτομα που γεννήθηκαν στις 29 Φεβρουαρίου. Το Calendar καθορίζει σωστά εάν τα γενέθλια ήταν στο τρέχον έτος και επιστρέφει την ακριβή ηλικία.
Ομαδοποίηση κατά έτος και μήνα – μια συνηθισμένη εργασία για οθόνες με ιστορικό ή ημερολόγιο. Το DateComponents χρησιμεύει ως κλειδί ομαδοποίησης: εξάγετε το έτος και τον μήνα από την ημερομηνία του συμβάντος, σχηματίζετε ένα κλειδί συμβολοσειράς και ομαδοποιείτε μέσω Dictionary(grouping:). Για εμφάνιση, χρησιμοποιήστε το DateFormatter με το πρότυπο “LLLL yyyy” για το τοπικοποιημένο όνομα μήνα.
| Εργασία | Μέθοδος Calendar | Ρόλος DateComponents |
|---|---|---|
| Πρώτη ημέρα μήνα | nextDate(after:matching:) | day: 1 |
| Υπολογισμός ηλικίας | dateComponents(from:to:) | [.year] από τη διαφορά |
| Ομαδοποίηση ημερομηνιών | dateComponents(_:from:) | year + month κλειδί |
| Αναζήτηση ημέρας εβδομάδας | nextDate(after:matching:) | weekday: N |
Συχνές ερωτήσεις
Αιτίες: ανύπαρκτη ημερομηνία (31 Απριλίου), αντιφατικά πεδία (weekday=1 με day=5), μη έγκυρος συνδυασμός πεδίων για το επιλεγμένο ημερολόγιο. Το Calendar προσπαθεί να ερμηνεύσει τα στοιχεία στο σύστημά του – εάν ο συνδυασμός είναι αδύνατος, το αποτέλεσμα είναι nil. Χρησιμοποιείτε πάντα guard let ή if let κατά τη μετατροπή.
Ναι, μέσω του τελεστή ==. Το DateComponents υλοποιεί το Equatable, συγκρίνοντας όλα τα πεδία. Δύο δομές είναι ίσες εάν όλα τα πεδία τους είναι ίσα (το nil == nil θεωρείται αληθές). Για σύγκριση μόνο μέρους των πεδίων – εξάγετε το ίδιο σύνολο μέσω Calendar.dateComponents.
Date – μια απόλυτη χρονική στιγμή χωρίς σύνδεση με ημερολόγιο. DateComponents – ένα σύνολο αριθμών αναγνώσιμων από τον άνθρωπο (έτος, μήνας, ημέρα) που έχουν νόημα μόνο στο πλαίσιο του Calendar. Το Date μπορεί να συγκριθεί, να αφαιρεθεί, να σειριοποιηθεί σε ISO 8601. Το DateComponents – μια ενδιάμεση αναπαράσταση για αλληλεπίδραση με το ημερολόγιο.
Ορίστε μόνο τα πεδία year και month, αφήνοντας τα υπόλοιπα ως nil. Κατά τη μετατροπή σε Date μέσω Calendar.date(from:), το Calendar θα ορίσει αυτόματα ημέρα = 1, ώρα = 0, λεπτό = 0. Το αποτέλεσμα – μια Date που αντιστοιχεί στην πρώτη ημέρα του καθορισμένου μήνα τα μεσάνυχτα.
Το DateComponents δεν αποθηκεύει πληροφορίες σχετικά με τη ζώνη ώρας στα πεδία – οι τιμές των πεδίων (έτος, μήνας, ημέρα) εξαρτώνται από τη timeZone στην οποία εξήχθησαν. Τα στοιχεία “21 Ιουλίου 2026 14:00 MSK” και “21 Ιουλίου 2026 10:00 UTC” αντιπροσωπεύουν την ίδια Date, αλλά τα πεδία DateComponents είναι διαφορετικά.
Περίληψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης