DateFormatter — είναι μια κλάση του Foundation που προορίζεται για τον αμφίδρομο μετασχηματισμό μεταξύ αντικειμένων Date και της αναπαράστασής τους ως συμβολοσειράς. Η κλάση λαμβάνει υπόψη τη γλώσσα (locale), τη ζώνη ώρας και το ημερολόγιο του χρήστη, εξασφαλίζοντας τη σωστή εμφάνιση των ημερομηνιών σε οποιαδήποτε περιοχή του κόσμου. Σύμφωνα με το Apple Developer Documentation (2025), το DateFormatter υποστηρίζει τέσσερα προκαθορισμένα στυλ ημερομηνίας και ώρας, καθώς και πλήρως προσαρμοσμένα formats μέσω μιας συμβολοσειράς προτύπου. Χωρίς το DateFormatter είναι αδύνατη η σωστή εμφάνιση της ημερομηνίας στον χρήστη σε μια διεθνοποιημένη εφαρμογή.
Βασικά σημεία
DateFormatter — είναι μια κλάση από το πλαίσιο Foundation που υλοποιεί τον αμφίδρομο μετασχηματισμό μεταξύ Date και συμβολοσειράς. Εμφανίστηκε στο OpenStep ως NSDateFormatter και από τότε παραμένει το κύριο εργαλείο μορφοποίησης ημερομηνιών σε όλες τις πλατφόρμες της Apple. Η κλάση κληρονομεί από τη Formatter και παρέχει ένα βολικό API για την τοπικοποιημένη εμφάνιση ημερομηνιών.
Η αρχή λειτουργίας του DateFormatter βασίζεται σε πρότυπα Unicode LDML — τα ίδια που χρησιμοποιούνται στο ICU (International Components for Unicode). Το πρότυπο ορίζεται μέσω της ιδιότητας dateFormat, όπου οι χαρακτήρες y, M, d, H, m, s αντιστοιχούν σε έτος, μήνα, ημέρα, ώρες, λεπτά, δευτερόλεπτα. Η επανάληψη ενός χαρακτήρα καθορίζει το format: “y” — έτος δύο ψηφίων, “yyyy” — τεσσάρων ψηφίων.
Η δημιουργία ενός DateFormatter είναι ακριβή διαδικασία, καθώς κατά την αρχικοποίηση φορτώνονται τα δεδομένα της γλώσσας και του ημερολογίου. Η Apple συνιστά να δημιουργείτε τον formatter μία φορά για κάθε τύπο μορφοποίησης και να τον επαναχρησιμοποιείτε. Στα SwiftUI και UIKit οι formatters συχνά αποθηκεύονται σε στατικές ιδιότητες ή δημιουργούνται τεμπέλικα κατά την πρώτη προσέγγιση.
DateFormatter χρησιμοποιείται σε πολλά στοιχεία συστήματος του iOS. Το UIDatePicker χρησιμοποιεί εσωτερικά το DateFormatter για την εμφάνιση ημερομηνιών στη λειτουργία countDownTimer. Ένα TextField με formatter στην είσοδο μπορεί να επικυρώνει αυτόματα την ημερομηνία που εισάγει ο χρήστης. Το Core Data υποστηρίζει χαρακτηριστικά τύπου Date, αλλά η εμφάνισή τους ως συμβολοσειρά πραγματοποιείται πάντα μέσω του DateFormatter.
Thread Safety — το DateFormatter δεν είναι ασφαλές για πολλαπλά νήματα. Η τροποποίηση των ιδιοτήτων του formatter από διαφορετικά νήματα οδηγεί σε απροσδιόριστη συμπεριφορά. Για πολυνηματική χρήση, δημιουργήστε ξεχωριστά στιγμιότυπα formatter για κάθε νήμα ή χρησιμοποιήστε συγχρονισμό μέσω NSLock ή serial queue.
dateStyle και timeStyle — οι πιο απλοί τρόποι ρύθμισης της εμφάνισης της ημερομηνίας. Κάθε στυλ έχει τέσσερις παραλλαγές: .short, .medium, .long, .full. Ο συνδυασμός των dateStyle και timeStyle επιτρέπει να ρυθμίσετε ανεξάρτητα το format ημερομηνίας και ώρας, ενώ η ιδιότητα .none απενεργοποιεί το αντίστοιχο μέρος.
Για την αμερικανική locale το .short μορφοποιεί την ημερομηνία ως “7/21/26”, ενώ για τη ρωσική — ως “21.07.2026”. Το στυλ .long για τη ρωσική locale εμφανίζει “21 Ιουλίου 2026”, ενώ το .full — “Τρίτη, 21 Ιουλίου 2026” με αναφορά στην ημέρα της εβδομάδας. Και τα τέσσερα στυλ προσαρμόζονται αυτόματα στα περιφερειακά πρότυπα, συμπεριλαμβανομένης της σειράς των στοιχείων και των διαχωριστικών.
SFDateFormatter στο iOS 15+ παρέχει μια εναλλακτική προσέγγιση μέσω των RelativeDateFormatter και DateIntervalFormatter. Το RelativeDateFormatter εμφανίζει “σήμερα”, “χθες”, “σε 3 ημέρες” για άμεσο πλαίσιο. Το DateIntervalFormatter εμφανίζει εύρη ημερομηνιών: “21–25 Ιουλίου 2026” — για κρατήσεις και προγραμματισμό.
| Στυλ | Παράδειγμα (ru_RU) | Παράδειγμα (en_US) |
|---|---|---|
| .short | 21.07.2026 | 7/21/26 |
| .medium | 21 Ιουλ. 2026 | Jul 21, 2026 |
| .long | 21 Ιουλίου 2026 | July 21, 2026 |
| .full | Τρίτη, 21 Ιουλίου 2026 | Tuesday, July 21, 2026 |
Κατά τον συνδυασμό στυλ, το DateFormatter επιλέγει αυτόματα τον διαχωριστή: για .short.date + .short.time το αποτέλεσμα μπορεί να είναι “21.07.2026, 14:30”. Για .full.date + .full.time — “Τρίτη, 21 Ιουλίου 2026, 14:30:00 MSK”. Τον διαχωριστή τον ελέγχει η γλώσσα, όχι ο προγραμματιστής — αυτό εξασφαλίζει ότι ταιριάζει με τις περιφερειακές προσδοκίες του χρήστη.
dateFormat επιτρέπει να ορίσετε ένα αυθαίρετο πρότυπο μορφοποίησης χρησιμοποιώντας τους χαρακτήρες της προδιαγραφής Unicode LDML. Αυτό παρέχει πλήρη έλεγχο της εμφάνισης: μπορείτε να εμφανίσετε μόνο έτος και μήνα, ή την ημέρα της εβδομάδας χωρίς τον αριθμό, ή την ώρα χωρίς δευτερόλεπτα. Το προσαρμοσμένο format είναι απαραίτητο για συγκεκριμένες απαιτήσεις σχεδιασμού.
Οι βασικοί χαρακτήρες είναι yyyy (έτος: 2026), MM (μήνας: 07), dd (ημέρα: 21), HH (ώρες: 14), mm (λεπτά: 30), ss (δευτερόλεπτα: 00). Για το πλήρες όνομα του μήνα χρησιμοποιήστε MMMM (Ιούλιος), για το συντομευμένο — MMM (Ιουλ.). Η ημέρα της εβδομάδας είναι EEEE (Τρίτη), συντομευμένα — E (Τρ).
Κατά τη χρήση του dateFormat είναι σημαντικό να ορίσετε το locale του formatter. Αν δεν οριστεί locale, ο formatter χρησιμοποιεί τη γλώσσα συστήματος, κάτι που μπορεί να είναι ανεπιθύμητο για ένα σταθερό format σε API. Η Apple συνιστά να ορίζετε locale = Locale(identifier: “en_US_POSIX”) για ένα σταθερό διαπεριφερειακό format, ειδικά κατά την ανάλυση ημερομηνιών από απαντήσεις διακομιστή.
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.dateFormat = "d MMMM yyyy"
let customString = formatter.string(from: Date())
// "21 Ιουλίου 2026"
// Ανάλυση προσαρμοσμένης συμβολοσειράς
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = formatter.date(from: "2026-07-21 14:30:00")!
Ένα σφάλμα στο dateFormat είναι μία από τις συχνές αιτίες κατάρρευσης της εφαρμογής. Αν το format δεν ταιριάζει με τη συμβολοσειρά, η μέθοδος date(from:) επιστρέφει nil. Χρησιμοποιήστε guard let ή ?? για ασφαλή εξαγωγή της προαιρετικής τιμής. Για την επικύρωση του format, δοκιμάστε σε όλες τις υποστηριζόμενες γλώσσες — ορισμένοι χαρακτήρες LDML λειτουργούν διαφορετικά σε διαφορετικές locale.
Locale καθορίζει πώς εμφανίζονται τα ονόματα των μηνών, των ημερών της εβδομάδας και ποιοι διαχωριστές χρησιμοποιούνται. Το DateFormatter χρησιμοποιεί από προεπιλογή το Locale.current, αλλά σε ορισμένα σενάρια απαιτείται συγκεκριμένη locale: για σταθερό format στα αρχεία καταγραφής χρησιμοποιήστε το en_US_POSIX, για ημερομηνίες διακομιστή — μια locale που αντιστοιχεί στον διακομιστή.
Η ιδιότητα TimeZone καθορίζει τη ζώνη ώρας για την εμφάνιση. Από προεπιλογή χρησιμοποιείται η ζώνη ώρας συστήματος, αλλά για εφαρμογές με διεθνές κοινό συχνά απαιτείται η εμφάνιση ημερομηνιών στη ζώνη ώρας του χρήστη ή σε UTC. Η αλλαγή του timeZone επηρεάζει μόνο την εμφάνιση — η τιμή του Date παραμένει αμετάβλητη.
Ένα σημαντικό χαρακτηριστικό: αν το DateFormatter χρησιμοποιείται για την ανάλυση μιας συμβολοσειράς και η συμβολοσειρά περιέχει ένδειξη ζώνης ώρας (για παράδειγμα, “2026-07-21T14:30:00Z” με Z για το UTC), η ιδιότητα timeZone αγνοείται — ο formatter χρησιμοποιεί τη ζώνη ώρας από τη συμβολοσειρά. Αν η ζώνη ώρας απουσιάζει από τη συμβολοσειρά, εφαρμόζεται το timeZone του formatter.
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "ru_RU")
formatter.timeZone = TimeZone(identifier: "Europe/Moscow")
formatter.dateStyle = .long
formatter.timeStyle = .short
let moscowTime = formatter.string(from: Date())
// "21 Ιουλίου 2026, 14:30"
// Ανάλυση χωρίς ζώνη ώρας στη συμβολοσειρά
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd HH:mm"
let utcDate = formatter.date(from: "2026-07-21 10:30")!
AutoupdatingCurrentLocale — ένας ειδικός τύπος γλώσσας που ενημερώνεται αυτόματα όταν αλλάζουν οι ρυθμίσεις συστήματος του χρήστη. Το DateFormatter το υποστηρίζει από προεπιλογή. Αν η εφαρμογή λειτουργεί στο παρασκήνιο και ο χρήστης αλλάξει τη γλώσσα συστήματος, ο formatter που δημιουργήθηκε πριν την αλλαγή θα συνεχίσει να χρησιμοποιεί την παλιά γλώσσα — για ενημέρωση πρέπει να δημιουργήσετε νέο στιγμιότυπο.
ISO8601DateFormatter — ένας εξειδικευμένος formatter για εργασία με ημερομηνίες σε format ISO 8601. Αυτό το format είναι το de facto πρότυπο για REST API, JSON και ανταλλαγή δεδομένων. Το ISO8601DateFormatter λειτουργεί σημαντικά ταχύτερα από το DateFormatter, καθώς δεν εξαρτάται από τη γλώσσα και χρησιμοποιεί σταθερή γραμματική ανάλυσης.
Οι βασικές επιλογές του formatter είναι .withInternetDateTime (2026-07-21T14:30:00Z), .withFractionalSeconds (προσθέτει χιλιοστά δευτερολέπτου), .withTimeZone (περιλαμβάνει την απόκλιση ζώνης ώρας). Συνδυάζοντας τις επιλογές, μπορείτε να λάβετε οποιαδήποτε παραλλαγή ISO 8601: με χιλιοστά δευτερολέπτου, με ζώνη ώρας, με ημερομηνία χωρίς ώρα.
JSONEncoder.DateEncodingStrategy επιτρέπει τη συνολική ρύθμιση της κωδικοποίησης ημερομηνιών για όλα τα μοντέλα Codable. Οι επιλογές είναι .iso8601 (χρησιμοποιεί το ISO8601DateFormatter), .formatted(DateFormatter), .millisecondsSince1970, .secondsSince1970. Η επιλογή της στρατηγικής επηρεάζει ολόκληρο τον κύκλο ζωής της σειριοποίησης και πρέπει να είναι ενιαία για όλα τα endpoints του API.
// ISO8601DateFormatter
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let isoString = isoFormatter.string(from: Date())
// "2026-07-21T14:30:00.000Z"
// JSONEncoder με ISO8601
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601
// Εναλλακτική: JSONEncoder με προσαρμοσμένο formatter
let customEncoder = JSONEncoder()
customEncoder.dateEncodingStrategy = .formatted(myFormatter)
DateFormatter vs ISO8601DateFormatter — επιλέξτε το ISO8601DateFormatter για τη σειριοποίηση και την ανάλυση ημερομηνιών σε API, καθώς λειτουργεί 5-10 φορές ταχύτερα από το DateFormatter και δεν επηρεάζεται από σφάλματα τοπικοποίησης. Χρησιμοποιήστε το DateFormatter για το περιβάλλον διεπαφής, όπου απαιτείται τοπικοποιημένη εμφάνιση με ονόματα μηνών και ημερών της εβδομάδας στη μητρική γλώσσα του χρήστη.
Ας εξετάσουμε πραγματικά σενάρια χρήσης του DateFormatter σε μια εφαρμογή iOS: εμφάνιση στη λίστα ειδήσεων, εισαγωγή ημερομηνίας γέννησης και εξαγωγή αναφοράς με ημερομηνίες σε διαφορετικές ζώνες ώρας.
RelativeDateFormatter είναι ο βέλτιστος για ροές ειδήσεων. Εμφανίζει “μόλις τώρα”, “πριν από 5 λεπτά”, “χθες” για νέες ειδήσεις και μεταβαίνει σε πλήρη ημερομηνία για παλιές. Το όριο μεταβολής ρυθμίζεται μέσω του calendar: για ειδήσεις χρησιμοποιήστε όριο 24 ωρών, για messengers — μία εβδομάδα.
func formatRelativeDate(_ date: Date) -> String {
let relative = RelativeDateFormatter()
relative.unitsStyle = .full
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let daysDiff = Calendar.current.dateComponents(
[.day], from: date, to: Date()
).day ?? 0
return daysDiff < 1
? relative.localizedString(for: date, relativeTo: Date())
: formatter.string(from: date)
}
Εισαγωγή ημερομηνίας γέννησης — ένα ακόμη συχνό σενάριο. Το DateFormatter ρυθμίζεται με συγκεκριμένο dateFormat “dd.MM.yyyy” και locale “ru_RU”. Κατά την ανάλυση της εισαγόμενης συμβολοσειράς είναι σημαντικό να διαχειρίζεστε πιθανά σφάλματα: ο formatter επιστρέφει nil για μη έγκυρη συμβολοσειρά. Μετά την επιτυχή ανάλυση, η ημερομηνία ελέγχεται για εγκυρότητα εντός επιτρεπόμενου εύρους — όχι πριν από το 1900, όχι αργότερα από σήμερα.
Εξαγωγή αναφοράς με ημερομηνίες απαιτεί σταθερό format, ανεξάρτητο από τη γλώσσα του χρήστη. Χρησιμοποιήστε dateFormat “yyyy-MM-dd HH:mm:ss” με locale en_US_POSIX και ζώνη ώρας UTC. Αυτή η προσέγγιση εξασφαλίζει ότι το αρχείο ανοίγει σωστά σε οποιαδήποτε χώρα, ανεξάρτητα από τις περιφερειακές ρυθμίσεις του συστήματος.
| Σενάριο | Formatter | Βασική ρύθμιση |
|---|---|---|
| Ροή ειδήσεων | RelativeDateFormatter | unitsStyle = .full |
| Εισαγωγή ημερομηνίας | DateFormatter | dateFormat + fallback |
| Σειριοποίηση API | ISO8601DateFormatter | withInternetDateTime |
| Εξαγωγή αναφοράς | DateFormatter | en_US_POSIX + UTC |
Συχνές ερωτήσεις
Η πιο συχνή αιτία είναι η αναντιστοιχία του dateFormat με το format της συμβολοσειράς. Για παράδειγμα, το format “dd.MM.yyyy” δεν θα αναλύσει τη συμβολοσειρά “2026-07-21”. Η δεύτερη αιτία είναι η αναντιστοιχία γλώσσας: η συμβολοσειρά “July 21, 2026” δεν θα αναλυθεί με τη γλώσσα ru_RU. Η τρίτη — τα τυπογραφικά λάθη στους χαρακτήρες LDML: χρησιμοποιήστε yyyy, όχι YYYY (διαφορετική σημασία).
Όχι. Το DateFormatter είναι ένα “βαρύ” αντικείμενο — η αρχικοποίησή του περιλαμβάνει τη φόρτωση δεδομένων γλώσσας. Δημιουργήστε ένα στιγμιότυπο ανά τύπο μορφοποίησης και επαναχρησιμοποιήστε το. Σε πολυνηματικό περιβάλλον χρησιμοποιήστε thread-local storage ή μια ομάδα formatters με serial queue για συγχρονισμό.
DateFormatter εμφανίζει απόλυτη ημερομηνία (21 Ιουλίου 2026), ενώ το RelativeDateFormatter — σχετική (σήμερα, χθες, σε 3 ημέρες). Το RelativeDateFormatter εμφανίστηκε στο iOS 15+ και χρησιμοποιεί το ίδιο πρότυπο LDML, αλλά επιλέγει αυτόματα τη σχετική εμφάνιση.
Ορίστε το timeZone του formatter σε UTC πριν την ανάλυση. Αν ο διακομιστής επιστρέφει ημερομηνία σε τοπική ώρα χωρίς ένδειξη ζώνης, διευκρινίστε την προδιαγραφή του API — πιθανότατα εννοείται το UTC. Για ISO 8601 με Z στο τέλος, το timeZone δεν χρειάζεται — ο formatter αναλύει την απόκλιση από τη συμβολοσειρά.
Μην χρησιμοποιείτε ένα στιγμιότυπο από διαφορετικά νήματα χωρίς συγχρονισμό. Δημιουργήστε νέο στιγμιότυπο σε κάθε νήμα ή χρησιμοποιήστε το Thread.current.threadDictionary για αποθήκευση. Εναλλακτικά — NSLock με κλείδωμα για τη διάρκεια των string(from:) και date(from:).
Συμπεράσματα
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης