DateComponents – τι είναι, στοιχεία ημερολογίου και NSCalendar

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-07-12 Χρόνος ανάγνωσης: 7 λεπ

DateComponents είναι μια δομή Foundation που αποθηκεύει τα στοιχεία μιας ημερολογιακής ημερομηνίας ως ξεχωριστά πεδία: έτος, μήνας, ημέρα, ώρα, λεπτό, δευτερόλεπτο και άλλα. Σε αντίθεση με το Date, που αντιπροσωπεύει μια απόλυτη χρονική στιγμή, το DateComponents περιέχει τιμές αναγνώσιμες από τον άνθρωπο, εξαρτώμενες από το ημερολόγιο και τη ζώνη ώρας. Σύμφωνα με το Apple Developer Documentation (2025), το DateComponents χρησιμοποιείται ως ενδιάμεσος κρίκος μεταξύ Date και Calendar – μέσω αυτού εξάγονται και κατασκευάζονται ημερολογιακές ημερομηνίες, εκτελούνται υπολογισμοί και μετατοπίσεις ημερομηνιών χωρίς χειροκίνητη αριθμητική.

Κύρια σημεία

  • DateComponents – δομή για αποθήκευση στοιχείων ημερομηνίας (έτος, μήνας, ημέρα) ως προαιρετικά ακέραια πεδία.
  • Calendar.dateComponents – μέθοδος που εξάγει τα καθορισμένα στοιχεία από το Date λαμβάνοντας υπόψη τη ζώνη ώρας.
  • Calendar.date(from:) – αντίστροφη μετατροπή DateComponents σε Date με αυτόματη συμπλήρωση των πεδίων που λείπουν.
  • Προαιρετικά πεδία – κάθε πεδίο DateComponents μπορεί να είναι nil, επιτρέποντας τον καθορισμό ελλιπών ημερομηνιών.
  • Range και στοιχεία – το DateComponents χρησιμοποιείται στο Calendar για υπολογισμό της διαφοράς μεταξύ ημερομηνιών και εύρεσης ημερομηνιών σε ένα εύρος.

Τι είναι το DateComponents;

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, day1..∞, 1..12, 1..31
Χρονικάhour, minute, second, nanosecond0..23, 0..59, 0..59, 0..999999999
Εβδομαδιαίαweekday, weekOfMonth, weekOfYear1..7, 1..5, 1..53
Ειδικάquarter, yearForWeekOfYear1..4, εξαρτώμενο

Κατά την εξαγωγή στοιχείων μέσω Calendar.dateComponents, είναι σημαντικό να ζητάτε μόνο τα απαραίτητα πεδία για απόδοση. Το Calendar εξάγει όλα τα ζητούμενα πεδία σε ένα πέρασμα – αυτό είναι σημαντικά ταχύτερο από την κλήση του Calendar.component για κάθε πεδίο ξεχωριστά.

Δημιουργία DateComponents

Αρχικοποίηση 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.

swift
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.

Μετατροπή DateComponents σε Date

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 έχει οριστεί ρητά σε ένα από τα αντικείμενα.

swift
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 – η κεντρική κλάση που εργάζεται με 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.

swift
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

Θα εξετάσουμε πρακτικά σενάρια χρήσης DateComponents σε μια εφαρμογή. Κάθε παράδειγμα δείχνει μια τυπική εργασία που αντιμετωπίζει ένας προγραμματιστής iOS κατά την εργασία με ημερολογιακές ημερομηνίες.

Υπενθύμιση για την πρώτη ημέρα κάθε μήνα

Η Calendar.nextDate με DateComponents(day: 1) βρίσκει την πρώτη ημέρα του επόμενου μήνα. Το Calendar καθορίζει αυτόματα τον αριθμό ημερών στον τρέχοντα μήνα και μεταβαίνει στον επόμενο μήνα. Για επαναλαμβανόμενες ειδοποιήσεις, χρησιμοποιήστε το enumerateDates ή το Combine.Timer με κλειδί Calendar.

swift
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

Συχνές ερωτήσεις

Γιατί το Calendar.date(from:) επιστρέφει nil για DateComponents;

Αιτίες: ανύπαρκτη ημερομηνία (31 Απριλίου), αντιφατικά πεδία (weekday=1 με day=5), μη έγκυρος συνδυασμός πεδίων για το επιλεγμένο ημερολόγιο. Το Calendar προσπαθεί να ερμηνεύσει τα στοιχεία στο σύστημά του – εάν ο συνδυασμός είναι αδύνατος, το αποτέλεσμα είναι nil. Χρησιμοποιείτε πάντα guard let ή if let κατά τη μετατροπή.

Μπορούν να συγκριθούν τα DateComponents μεταξύ τους;

Ναι, μέσω του τελεστή ==. Το DateComponents υλοποιεί το Equatable, συγκρίνοντας όλα τα πεδία. Δύο δομές είναι ίσες εάν όλα τα πεδία τους είναι ίσα (το nil == nil θεωρείται αληθές). Για σύγκριση μόνο μέρους των πεδίων – εξάγετε το ίδιο σύνολο μέσω Calendar.dateComponents.

Σε τι διαφέρει το DateComponents από το Date;

Date – μια απόλυτη χρονική στιγμή χωρίς σύνδεση με ημερολόγιο. DateComponents – ένα σύνολο αριθμών αναγνώσιμων από τον άνθρωπο (έτος, μήνας, ημέρα) που έχουν νόημα μόνο στο πλαίσιο του Calendar. Το Date μπορεί να συγκριθεί, να αφαιρεθεί, να σειριοποιηθεί σε ISO 8601. Το DateComponents – μια ενδιάμεση αναπαράσταση για αλληλεπίδραση με το ημερολόγιο.

Πώς να καθορίσω μόνο έτος και μήνα στο DateComponents;

Ορίστε μόνο τα πεδία year και month, αφήνοντας τα υπόλοιπα ως nil. Κατά τη μετατροπή σε Date μέσω Calendar.date(from:), το Calendar θα ορίσει αυτόματα ημέρα = 1, ώρα = 0, λεπτό = 0. Το αποτέλεσμα – μια Date που αντιστοιχεί στην πρώτη ημέρα του καθορισμένου μήνα τα μεσάνυχτα.

Πώς χειρίζεται το DateComponents τις ζώνες ώρας;

Το DateComponents δεν αποθηκεύει πληροφορίες σχετικά με τη ζώνη ώρας στα πεδία – οι τιμές των πεδίων (έτος, μήνας, ημέρα) εξαρτώνται από τη timeZone στην οποία εξήχθησαν. Τα στοιχεία “21 Ιουλίου 2026 14:00 MSK” και “21 Ιουλίου 2026 10:00 UTC” αντιπροσωπεύουν την ίδια Date, αλλά τα πεδία DateComponents είναι διαφορετικά.

Περίληψη

  • DateComponents – δομή Foundation για αποθήκευση ημερολογιακών στοιχείων (έτος, μήνας, ημέρα, ώρα) ως προαιρετικά πεδία Int?.
  • Calendar.dateComponents εξάγει στοιχεία από το Date λαμβάνοντας υπόψη τη ζώνη ώρας και το ημερολογιακό σύστημα.
  • Calendar.date(from:) συναρμολογεί Date από DateComponents χρησιμοποιώντας προεπιλεγμένες τιμές για πεδία που λείπουν.
  • Προαιρετικότητα πεδίων επιτρέπει τον καθορισμό ελλιπών ημερομηνιών – το Calendar συμπληρώνει τις τιμές που λείπουν.
  • Calendar.nextDate αναζητά την επόμενη ημερομηνία που αντιστοιχεί σε DateComponents – για υπενθυμίσεις και επαναλαμβανόμενα συμβάντα.
  • Υπολογισμός ηλικίας μέσω Calendar.dateComponents([.year], from:to:) – ο μόνος σωστός τρόπος που λαμβάνει υπόψη τα δίσεκτα έτη.
  • MatchingPolicy ελέγχει τη συμπεριφορά του Calendar όταν δεν ταιριάζουν όλα τα στοιχεία – σημαντική παράμετρος για αναζήτηση ημερομηνιών.

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης