Calendar — είναι μια κλάση Foundation που ορίζει το ημερολογιακό σύστημα και παρέχει μεθόδους για ημερολογιακούς υπολογισμούς: εξαγωγή στοιχείων ημερομηνίας, υπολογισμός διαφοράς μεταξύ ημερομηνιών, εύρεση ορίων περιόδων και μετατόπιση ημερομηνιών. Το ημερολόγιο συνδέει τον απόλυτο χρόνο (Date) με αναγνώσιμα από τον άνθρωπο στοιχεία και λαμβάνει υπόψη περιφερειακά χαρακτηριστικά: αρχή της εβδομάδας, ζώνη ώρας και θερινή ώρα. Σύμφωνα με το Apple Developer Documentation (2025), το Foundation υποστηρίζει 17 ημερολογιακά συστήματα — από το Γρηγοριανό έως το Βουδιστικό και το Ιαπωνικό, καθιστώντας το Calendar ένα καθολικό εργαλείο για διεθνοποιημένες εφαρμογές.
Κύρια Σημεία
Calendar — είναι μια κλάση Foundation που υλοποιεί ημερολογιακούς υπολογισμούς βάσει του ICU (International Components for Unicode). Το ημερολόγιο καθορίζει πώς ο απόλυτος χρόνος (Date) αντιστοιχίζεται σε ημερολογιακά στοιχεία: έτος, μήνας, ημέρα, ώρα, λεπτό, δευτερόλεπτο. Χωρίς το Calendar, είναι αδύνατο να γνωρίζουμε ποιο έτος, μήνα και ημέρα είναι σήμερα — το Date από μόνο του δεν περιέχει αυτές τις πληροφορίες.
Το ημερολόγιο λαμβάνει υπόψη τρεις ομάδες παραμέτρων: ημερολογιακό σύστημα (Γρηγοριανό, Βουδιστικό, Ιαπωνικό), ζώνη ώρας και τοπικές ρυθμίσεις. Το Calendar.current συνδυάζει και τις τρεις από τις ρυθμίσεις συστήματος του χρήστη. Το Calendar.autoupdatingCurrent — μια ειδική έκδοση που ενημερώνεται αυτόματα όταν αλλάζουν οι ρυθμίσεις χωρίς επανεκκίνηση της εφαρμογής μέσω του NotificationCenter.
Το ημερολόγιο είναι ένας τύπος τιμής (value type) στο Foundation. Το Calendar(identifier:) δημιουργεί ένα νέο στιγμιότυπο με σταθερές παραμέτρους. Το ημερολόγιο μπορεί να αντιγραφεί, να συγκριθεί με == και να χρησιμοποιηθεί ως κλειδί σε λεξικό. Αυτό επιτρέπει τη δημιουργία ημερολογίων με συγκεκριμένες ρυθμίσεις timeZone και locale για δοκιμές.
Calendar — η έκδοση Swift του Objective-C NSCalendar, με τη γέφυρα as Calendar / as NSCalendar. Στη σύγχρονη Swift, το Calendar χρησιμοποιείται παντού. Το NSCalendar παραμένει για συμβατότητα προς τα πίσω με το Objective-C API. Το Calendar έχει ένα πλήρες σύνολο μεθόδων χωρίς το πρόθεμα NS, με type-safe ορίσματα και Swift προαιρετικότητα.
Thread Safety — το Calendar είναι thread-safe για ανάγνωση. Το δημιουργημένο στιγμιότυπο μπορεί να διαβαστεί με ασφάλεια από πολλά νήματα. Η τροποποίηση ιδιοτήτων (timeZone, locale) δεν είναι thread-safe — για διαφορετικές διαμορφώσεις, δημιουργήστε ξεχωριστά στιγμιότυπα Calendar.
Το Foundation υποστηρίζει 17 ημερολογιακά συστήματα μέσω της απαρίθμησης Calendar.Identifier. Κάθε σύστημα έχει τους δικούς του κανόνες για δίσεκτα έτη, αριθμό μηνών και αρχή εποχής. Η επιλογή ημερολογίου επηρεάζει όλους τους υπολογισμούς: dateComponents, dateInterval, nextDate.
Κύρια ημερολογιακά συστήματα:
Calendar(identifier: .gregorian) — το πιο συχνά χρησιμοποιούμενο. Αντιστοιχεί στο διεθνές πρότυπο ISO 8601 και είναι το προεπιλεγμένο ημερολόγιο στις περισσότερες χώρες. Για εφαρμογές με διεθνές κοινό, χρησιμοποιήστε το Calendar.current — αντιστοιχεί αυτόματα στο ημερολόγιο συστήματος του χρήστη.
| Αναγνωριστικό | Τύπος | Περιοχή χρήσης |
|---|---|---|
| .gregorian | Ηλιακό | Διεθνές |
| .buddhist | Ηλιακό | Ταϊλάνδη, Καμπότζη |
| .japanese | Ηλιακό | Ιαπωνία |
| .hebrew | Σεληνιακό-Ηλιακό | Ισραήλ |
| .islamic | Σεληνιακό | Ισλαμικές χώρες |
| .chinese | Σεληνιακό-Ηλιακό | Κίνα |
DateComponents και Calendar — αχώριστο ζευγάρι. Το Calendar.dateComponents(_:from:) εξάγει στοιχεία από το Date λαμβάνοντας υπόψη τη ζώνη ώρας του ημερολογίου. Το Calendar.date(from:) δημιουργεί Date από DateComponents, συμπληρώνοντας τα πεδία που λείπουν με προεπιλεγμένες τιμές: ημέρα = 1, ώρα = 0, λεπτό = 0, δευτερόλεπτο = 0.
Η μέθοδος Calendar.component εξάγει ένα στοιχείο, το οποίο είναι βολικό για γρήγορο έλεγχο. Η Calendar.dateComponents εξάγει ένα σύνολο στοιχείων σε μία κλήση — αυτό είναι πιο αποδοτικό επειδή το Calendar εκτελεί τους ημερολογιακούς υπολογισμούς μία φορά, όχι για κάθε στοιχείο ξεχωριστά. Για λίστα 3+ στοιχείων, χρησιμοποιείτε πάντα το dateComponents.
Calendar.compare συγκρίνει δύο Date με καθορισμένη ακρίβεια. Η παράμετρος toGranularity καθορίζει μέχρι ποιο στοιχείο θα γίνει η σύγκριση: .year συγκρίνει μόνο το έτος, .month — έτος και μήνα, .day — έτος, μήνα, ημέρα. Αυτό είναι βολικό για τον έλεγχο εάν δύο ημερομηνίες ανήκουν στην ίδια ημέρα, χωρίς να λαμβάνεται υπόψη η ώρα.
let calendar = Calendar.current
let now = Date()
// Εξαγωγή ενός στοιχείου
let year = calendar.component(.year, from: now)
// Εξαγωγή συνόλου στοιχείων
let comps = calendar.dateComponents(
[.year, .month, .day], from: now
)
// Σύγκριση με ακρίβεια ημέρας
let isSameDay = calendar.compare(date1, to: date2,
toGranularity: .day) == .orderedSame
// Ελέγξτε εάν η ημερομηνία είναι σήμερα
let isToday = calendar.isDateInToday(someDate)
Calendar.isDateInToday, isDateInTomorrow, isDateInYesterday — μέθοδοι για σχετικούς ελέγχους. Η Calendar.isDate(_:inSameDayAs:) ελέγχει εάν δύο ημερομηνίες πέφτουν στην ίδια ημερολογιακή ημέρα λαμβάνοντας υπόψη τη ζώνη ώρας του ημερολογίου. Αυτές οι μέθοδοι χρησιμοποιούν το Calendar.compare εσωτερικά και είναι βελτιστοποιημένες για συχνή κλήση.
Calendar.dateInterval — μία από τις πιο χρήσιμες μεθόδους για αναλυτικά στοιχεία και UI. Επιστρέφει το DateInterval για το καθορισμένο στοιχείο: έναρξη και λήξη ημέρας, εβδομάδας, μήνα, έτους. Το DateInterval περιέχει start (Date) και end (Date) — τα όρια της περιόδου. Για παράδειγμα, το dateInterval(of: .weekOfYear, for: Date()) επιστρέφει την έναρξη της Δευτέρας και τη λήξη της Κυριακής της τρέχουσας εβδομάδας.
Calendar.date με byAdding — μέθοδος για μετατόπιση ημερομηνίας. Το Calendar.date(byAdding: .day, value: 7, to: Date()) επιστρέφει την ημερομηνία σε μία εβδομάδα. Το Calendar.date(byAdding: DateComponents) — μια πιο ευέλικτη έκδοση, που επιτρέπει τη μετατόπιση πολλών στοιχείων ταυτόχρονα: +1 μήνας +3 ημέρες. Το Calendar λαμβάνει αυτόματα υπόψη το διαφορετικό μήκος των μηνών και τα δίσεκτα έτη.
Calendar.nextDate αναζητά την επόμενη ημερομηνία που ταιριάζει με τα καθορισμένα DateComponents. Η παράμετρος matchingPolicy καθορίζει τη συμπεριφορά σε περίπτωση μη αντιστοιχίας: .nextTime — επόμενη αντιστοιχία σε χρόνο, .nextTimePreservingSmallerComponents — διατηρεί τα λεπτά και δευτερόλεπτα από την αρχική ημερομηνία, .strict — απαιτεί ακριβή αντιστοιχία.
let calendar = Calendar.current
let today = Date()
// Αρχή και τέλος εβδομάδας
let weekInterval = calendar.dateInterval(
of: .weekOfYear, for: today
)!
// Μετατόπιση κατά 1 μήνα
let nextMonth = calendar.date(
byAdding: .month, value: 1, to: today
)!
// Μετατόπιση μέσω DateComponents
var delta = DateComponents()
delta.month = 1
delta.day = 3
let shifted = calendar.date(byAdding: delta, to: today)!
// Επόμενη Παρασκευή 13
let friday13Components = DateComponents(
weekday: 6, day: 13
)
let nextFriday13 = calendar.nextDate(
after: today, matching: friday13Components,
matchingPolicy: .nextTime
)
EnumerateDates — μια ισχυρή μέθοδος για επανάληψη ημερομηνιών βάσει προτύπου. Το Calendar.enumerateDates(startingAfter:matching:matchingPolicy:using:) καλεί ένα μπλοκ για κάθε αντιστοιχία μέχρι το μπλοκ να επιστρέψει stop = true. Χρησιμοποιείται για τη δημιουργία επαναλαμβανόμενων γεγονότων σε ημερολόγια και προγράμματα. Η μέθοδος είναι πιο αποδοτική από τον χειροκίνητο βρόχο με nextDate, επειδή είναι βελτιστοποιημένη από το ICU.
TimeZone — αναπόσπαστο μέρος του Calendar. Η ζώνη ώρας καθορίζει σε ποια ημερολογιακή ώρα αντιστοιχεί το απόλυτο Date. Το ίδιο Date σε UTC και στη Μόσχα δίνει διαφορετικά στοιχεία: το Date() σε UTC μπορεί να δείχνει 10:00, και σε MSK — 13:00. Το Calendar.timeZone είναι από προεπιλογή ίσο με το TimeZone.current.
Locale επηρεάζει την πρώτη ημέρα της εβδομάδας, τον ελάχιστο αριθμό ημερών στην πρώτη εβδομάδα του έτους (minDaysInFirstWeek) και τα ονόματα μηνών/ημερών της εβδομάδας (κατά τη μετατροπή μέσω DateFormatter). Το Calendar.locale είναι από προεπιλογή ίσο με το Locale.current. Στις ελληνικές τοπικές ρυθμίσεις, η εβδομάδα ξεκινά τη Δευτέρα, στις αμερικανικές — την Κυριακή.
Calendar.availableIdentifiers επιστρέφει μια λίστα όλων των υποστηριζόμενων αναγνωριστικών ημερολογίου. static property Calendar.availableCalendarIdentifiers — ένας πίνακας συμβολοσειρών με τα ίδια αναγνωριστικά. Χρησιμοποιείται για τη δημιουργία UI επιλογής ημερολογίου και για τον έλεγχο διαθεσιμότητας ενός συγκεκριμένου ημερολογιακού συστήματος στη συσκευή.
// Ημερολόγιο με συγκεκριμένη ζώνη ώρας
var utcCalendar = Calendar(identifier: .gregorian)
utcCalendar.timeZone = TimeZone(identifier: "UTC")!
// Ημερολόγιο με ελληνικές τοπικές ρυθμίσεις
var russianCalendar = Calendar(identifier: .gregorian)
russianCalendar.locale = Locale(identifier: "ru_RU")
// Πρώτη ημέρα εβδομάδας εξαρτάται από το locale
let firstWeekday = russianCalendar.firstWeekday
// 2 = Δευτέρα (στο el_GR)
// Λίστα διαθέσιμων ημερολογίων
for identifier in Calendar.availableIdentifiers {
print(identifier)
}
firstWeekday — η ιδιότητα του Calendar που καθορίζει ποια ημέρα της εβδομάδας θεωρείται πρώτη. Στις ελληνικές τοπικές ρυθμίσεις, Sunday = 2 (Δευτέρα πρώτη). Στις αμερικανικές, Sunday = 1. Αυτό επηρεάζει τη λειτουργία των weekOfMonth και weekOfYear: η ίδια ημερομηνία μπορεί να αποδοθεί σε διαφορετικούς αριθμούς εβδομάδας σε διαφορετικές τοπικές ρυθμίσεις. Για εφαρμογές με ημερομηνίες, χρησιμοποιήστε το Calendar.current ή ορίστε ρητά το firstWeekday.
Ας εξετάσουμε πρακτικά σενάρια που επιδεικνύουν τις δυνατότητες του Calendar. Κάθε παράδειγμα λύνει μια συγκεκριμένη εργασία ανάπτυξης iOS και δείχνει τον σωστό τρόπο χρήσης ημερολογιακών υπολογισμών.
Calendar.dateInterval(of: .month, for:) επιστρέφει τα όρια του τρέχοντος μήνα. Ο έλεγχος εάν το Date εμπίπτει σε αυτό το διάστημα — ο ταχύτερος τρόπος για να προσδιοριστεί εάν η ημερομηνία ανήκει στον τρέχοντα μήνα. Εναλλακτικός τρόπος — Calendar.compare με granularity .month: εάν το αποτέλεσμα είναι .orderedSame, τότε ο μήνας ταιριάζει.
func isInCurrentMonth(_ date: Date) -> Bool {
let calendar = Calendar.current
let monthInterval = calendar.dateInterval(
of: .month, for: Date()
)!
return monthInterval.contains(date)
}
// Αριθμός ημερών σε ένα μήνα
func daysInMonth(for date: Date) -> Int {
let calendar = Calendar.current
return calendar.range(
of: .day, in: .month, for: date
)?.count ?? 0
}
// Προσθήκη μηνών με σωστή ολοκλήρωση
func addMonths(_ months: Int, to date: Date) -> Date {
let calendar = Calendar.current
return calendar.date(
byAdding: .month, value: months, to: date
)!
}
Calendar.range(of:in:for:) επιστρέφει το εύρος των επιτρεπόμενων τιμών για το καθορισμένο στοιχείο στο πλαίσιο ενός άλλου στοιχείου. Για παράδειγμα, το range(of: .day, in: .month, for: date) επιστρέφει 1..<32 για μήνες με 31 ημέρες ή 1..<29 για τον Φεβρουάριο μη δίσεκτου έτους. Αυτός είναι ο σωστός τρόπος για να μάθετε τον αριθμό των ημερών σε έναν μήνα, όχι η χρήση hardcode τιμών.
Προσθήκη μηνών μέσω του Calendar.date(byAdding:value:to:) χειρίζεται σωστά τις ημερομηνίες ορίων. Εάν στις 31 Ιανουαρίου προστεθεί 1 μήνας, το Calendar επιστρέφει 28 Φεβρουαρίου (ή 29 σε δίσεκτο έτος), όχι 3 Μαρτίου, όπως θα συνέβαινε με απλή προσθήκη 30 ημερών μέσω TimeInterval. Αυτός είναι ένας ακόμη λόγος να μην χρησιμοποιείτε το TimeInterval για ημερολογιακούς υπολογισμούς.
| Μέθοδος Calendar | Σκοπός | Παράδειγμα |
|---|---|---|
| dateInterval | Όρια περιόδου | Έναρξη και λήξη μήνα |
| range(of:in:for:) | Εύρος στοιχείου | Ημέρες στον τρέχοντα μήνα |
| date(byAdding:) | Μετατόπιση ημερομηνίας | +1 μήνας από σήμερα |
| isDateInToday | Έλεγχος εάν είναι σήμερα | Είναι η ημερομηνία σήμερα |
| compare(toGranularity:) | Σύγκριση με ακρίβεια | Ίδια ημέρα χωρίς ώρα |
Συχνές Ερωτήσεις
Calendar.current επιστρέφει το ημερολόγιο από τις ρυθμίσεις συστήματος του χρήστη — μπορεί να μην είναι Γρηγοριανό (για παράδειγμα, Βουδιστικό στην Ταϊλάνδη). Calendar(identifier: .gregorian) δημιουργεί πάντα ένα Γρηγοριανό ημερολόγιο ανεξάρτητα από τις ρυθμίσεις. Για εμφάνιση ημερομηνιών, χρησιμοποιήστε το Calendar.current, για επιχειρηματική λογική — το ρητά επιλεγμένο αναγνωριστικό.
Αυτό σχετίζεται με το διαφορετικό μήκος των μηνών. Εάν η τρέχουσα ημερομηνία είναι 31 Ιανουαρίου, η προσθήκη 1 μήνα δίνει 28 Φεβρουαρίου, επειδή ο Φεβρουάριος δεν έχει 31 ημέρες. Το Calendar συμπληρώνει αυτόματα την ημερομηνία μέχρι την τελευταία επιτρεπόμενη ημέρα του μήνα. Για ακριβή έλεγχο, χρησιμοποιήστε το DateComponents με day: 1 για μετάβαση στην πρώτη ημέρα του μήνα.
DateFormatter χρησιμοποιεί το Calendar.current — το ημερολόγιο συστήματος του χρήστη. Εάν η εφαρμογή πρέπει πάντα να εμφανίζει ημερομηνίες στο Γρηγοριανό ημερολόγιο ανεξάρτητα από τις ρυθμίσεις, ορίστε το formatter.calendar = Calendar(identifier: .gregorian). Αυτό εγγυάται ομοιόμορφη εμφάνιση για όλους τους χρήστες.
Calendar.range(of: .day, in: .year, for: date) επιστρέφει 365 ή 366 ημέρες. Απλούστερα: Calendar.date(from: DateComponents(year: έτος, month: 2, day: 29)) != nil — εάν υπάρχει 29 Φεβρουαρίου, το έτος είναι δίσεκτο. Το Calendar λαμβάνει υπόψη του τους κανόνες για το συγκεκριμένο ημερολογιακό σύστημα.
Ναι, η ιδιότητα firstWeekday είναι εγγράψιμη. Η αλλαγή επηρεάζει το weekOfMonth, το weekOfYear και όλους τους υπολογισμούς που σχετίζονται με αριθμούς εβδομάδων. Κατά τον ορισμό locale = Locale(identifier: "el_GR"), το firstWeekday γίνεται αυτόματα 2 (Δευτέρα). Η χειροκίνητη ρύθμιση παρακάμπτει την τιμή από το locale.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης