Date — to struktura Foundation reprezentująca konkretny moment czasu niezależnie od kalendarza i strefy czasowej. Typ przechowuje liczbę sekund, które upłynęły od daty referencyjnej 1 stycznia 2001 roku (reference date) i zapewnia podstawowe operacje porównywania oraz obliczania interwałów czasowych. Według Apple Developer Documentation (2025), Date jest używany we wszystkich frameworkach Apple: od UIKit i SwiftUI po CloudKit i Core Data. Zrozumienie działania Date jest niezbędne dla każdego programisty iOS, ponieważ bez niego nie można zarządzać czasem w aplikacji.
Najważniejsze
Date — to typ wartościowy z frameworka Foundation, który rejestruje jeden absolutny moment czasu. W przeciwieństwie do reprezentacji kalendarzowych (rok, miesiąc, dzień), Date nie zależy od strefy czasowej ani systemu kalendarza — to czysto numeryczna wartość znacznika czasu.
Wewnętrzna reprezentacja Date to TimeInterval (alias dla Double), przechowujący liczbę sekund względem reference date — 1 stycznia 2001 roku 00:00:00 UTC. Apple wybrało tę datę, a nie Unix epoch (1970 rok), dla kompatybilności ze starymi systemami NeXTSTEP, na których oparte są iOS i macOS.
Date jest używany jako standardowy typ czasu we wszystkich API Apple: UIDatePicker, DatePicker, UserDefaults, Codable, Core Data, CloudKit. Bez Date nie można pracować z harmonogramami, timerami, wydarzeniami kalendarza, serializacją danych i wszelkimi operacjami związanymi z czasem.
Date różni się od typów kalendarzowych tym, że reprezentuje fizyczny znacznik czasu, a nie wartość czytelną dla człowieka. Ten sam Date może odpowiadać różnym datom kalendarzowym w różnych strefach czasowych. Aby uzyskać komponenty (rok, miesiąc, dzień), Date jest przekształcany przez Calendar i DateComponents.
Date różni się również od DispatchTime, który jest używany do dyspozytorii zadań w Grand Central Dispatch. DispatchTime jest względny względem momentu uruchomienia systemu, podczas gdy Date to absolutny znacznik, który można zapisywać, przesyłać i odtwarzać.
Date() — to najprostszy sposób na utworzenie obiektu z bieżącym momentem czasu. Inicjalizator bez argumentów zwraca dokładny czas wywołania. Aby utworzyć datę w przeszłości lub przyszłości, używa się TimeInterval i metody addingTimeInterval albo inicjalizacji z istniejącego Date.
Do utworzenia dowolnej daty z komponentów używa się pary Calendar i DateComponents. Calendar przekształca czytelne dla człowieka komponenty (rok, miesiąc, dzień, godzina, minuta) na Date. Można również zainicjalizować Date przez ISO8601DateFormatter z ciągu znaków w formacie ISO 8601 lub przez DateFormatter z dowolnej reprezentacji tekstowej.
Date.distantPast i Date.distantFuture — dwie statyczne właściwości reprezentujące nieskończenie odległe momenty przeszłości i przyszłości. Są używane jako wartości graniczne przy filtrowaniu i sortowaniu dat w algorytmach.
import Foundation
// Tworzenie Date z bieżącym czasem
let now = Date()
print("Current time: \(now)")
// Data za 1 godzinę (3600 sekund)
let inOneHour = now.addingTimeInterval(3600)
// Data z komponentów
var components = DateComponents()
components.year = 2025
components.month = 12
components.day = 25
let christmas = Calendar.current.date(from: components)!
W przykładzie pokazano trzy sposoby tworzenia Date: bieżący czas, dodanie interwału i tworzenie przez DateComponents. Wszystkie trzy podejścia zwracają wartość typu Date z dokładnością do milisekundy. Calendar.current używa systemowego kalendarza użytkownika — na urządzeniach Apple jest to zazwyczaj kalendarz gregoriański.
TimeInterval — to alias dla Double, reprezentujący liczbę sekund między dwoma momentami czasu. Dokładność TimeInterval sięga ułamków milisekundy, co jest wystarczające dla większości zadań aplikacyjnych. Ujemna wartość TimeInterval wskazuje na przeszłość względem punktu odniesienia.
Date obsługuje wszystkie standardowe operatory porównania: ==, <, >, <=, >=. Swift automatycznie porównuje wewnętrzne TimeInterval wartości. Metoda compare zwraca ComparisonResult z wariantami .orderedSame, .orderedAscending, .orderedDescending dla bardziej jawnego porównania.
Date.distance(to:) — metoda zwracająca TimeInterval do wskazanej daty. Jeśli docelowa data jest w przeszłości, wynik jest ujemny. advanced(by:) tworzy nową datę, dodając podany TimeInterval do bieżącej. Te metody implementują protokół Strideable, umożliwiając użycie Date w zakresach Range i ClosedRange.
let start = Date()
let end = start.addingTimeInterval(86400)
// Porównanie przez operatory
if start < end {
print("start is earlier")
}
// TimeInterval między dwiema datami
let interval: TimeInterval = end.timeIntervalSince(start)
print("Seconds: \(Int(interval / 60)) minutes")
// Using Date in range
let range = start...end
let mid = start.addingTimeInterval(43200)
if range.contains(mid) {
print("mid is between start and end")
}
TimeInterval równy 86400 odpowiada jednej dobie. W przypadku bardziej złożonych interwałów — tygodni, miesięcy, lat — używaj Calendar i DateComponents, ponieważ te jednostki mają zmienną długość (lata przestępne, zmiana czasu na letni). TimeInterval ma zastosowanie tylko dla stałych odstępów w sekundach.
Calendar — to pomost między Date a czytelnymi dla człowieka komponentami. Calendar przekształca Date w DateComponents (rok, miesiąc, dzień, godzina, minuta, sekunda) z uwzględnieniem strefy czasowej i lokalizacji. Bez Calendar nie można wydobyć z Date roku ani miesiąca — Date nie zawiera tych informacji ze względu na swoją absolutną naturę.
Metoda Calendar.component wydobywa jeden komponent z Date: rok, miesiąc, dzień, godzina, minuta, sekunda, weekday, quarter. Metoda Calendar.dateComponents wydobywa zestaw komponentów w jednym wywołaniu — to bardziej efektywne niż wywoływanie component dla każdego pola osobno.
Calendar.isDateInToday, isDateInTomorrow, isDateInYesterday — wygodne metody sprawdzania dat względnych. Calendar.dateInterval zwraca początek i koniec wskazanego okresu (dzień, tydzień, miesiąc, rok). Calendar.compare porównuje daty z dokładnością do wskazanego komponentu — na przykład rok bez uwzględnienia miesiąca i dnia.
let calendar = Calendar.current
// Wyodrębnianie komponentów
let year = calendar.component(.year, from: Date())
let month = calendar.component(.month, from: Date())
// Check relative date
if calendar.isDateInToday(someDate) {
print("Today!")
}
// Początek i koniec dnia
let dayInterval = calendar.dateInterval(of: .day, for: Date())!
print("Day start: \(dayInterval.start)")
print("Day end: \(dayInterval.end)")
Calendar.current używa systemowych ustawień użytkownika — kalendarza, strefy czasowej i lokalizacji. Do testowania lub specyficznych obliczeń można utworzyć Calendar z konkretnymi parametrami przez Calendar(identifier: .gregorian) i ustawić odpowiednią TimeZone przez właściwość timeZone.
DateFormatter — niezbędny komponent, jeśli Date ma być wyświetlony użytkownikowi. DateFormatter przekształca Date w ciąg znaków według podanego formatu i lokalizacji. Bezpośrednie przekształcenie Date na ciąg znaków przez String(describing:) zwraca techniczną reprezentację z reference date i TimeInterval — nie jest przeznaczona dla użytkownika.
Podstawowym podejściem jest użycie predefiniowanych stylów dateStyle i timeStyle. iOS obsługuje cztery style: .short, .medium, .long, .full. Kombinacja stylów daty i czasu pozwala elastycznie dostosować wyświetlanie. DateFormatter automatycznie stosuje lokalizację: dla polskiej lokalizacji data wyświetli się w formacie \"21 lipca 2026\".
ISO8601DateFormatter — wyspecjalizowany formatter dla ISO 8601, najczęściej spotykanego formatu dla API i wymiany danych. Ten formatter działa szybciej niż DateFormatter i nie zależy od lokalizacji, co czyni go preferowanym do serializacji dat w JSON.
// Gotowe style
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let userString = formatter.string(from: Date())
// ISO 8601 dla API
let isoFormatter = ISO8601DateFormatter()
let apiString = isoFormatter.string(from: Date())
// Parsowanie z ciągu znaków
let parsed = isoFormatter.date(from: "2026-07-21T10:30:00Z")!
Podczas pracy z DateFormatter należy pamiętać o wydajności: tworzenie nowego formattera to kosztowna operacja. Zaleca się cachowanie formattera lub utworzenie go raz i wielokrotne używanie. We właściwościach formattera można ustawić timeZone — domyślnie używana jest systemowa strefa czasowa, ale dla dat serwerowych często wymagany jest TimeZone(identifier: \"UTC\").
Rozważmy typowe scenariusze pracy z Date w aplikacji iOS. Pierwszy scenariusz — obliczanie wieku użytkownika z daty urodzenia. Drugi — licznik czasu wstecz do wydarzenia. Trzeci — grupowanie wpisów według daty do wyświetlania w postaci sekcji tabeli.
Calendar.dateComponents z flagą [.year] oblicza różnicę między dwiema datami. Ustawienie prawidłowej strefy czasowej jest krytyczne — jeśli nie określisz timeZone w Calendar, wynik może różnić się o dzień z powodu przejścia przez północ w innej strefie czasowej.
func calculateAge(from birthDate: Date) -> Int {
let calendar = Calendar.current
let now = Date()
let components = calendar.dateComponents(
[.year], from: birthDate, to: now
)
return components.year ?? 0
}
Licznik czasu wstecz realizuje się przez TimeInterval. Obliczamy różnicę między datą docelową a bieżącą, otrzymujemy resztę w sekundach i przekształcamy na dni, godziny, minuty. Do regularnej aktualizacji używa się Timer z interwałem 1 sekundy. ObservableObject z właściwością @Published pozwala SwiftUI automatycznie aktualizować interfejs.
Grupowanie według daty realizuje się przez słownik z kluczem Date. Calendar.dateInterval(of: .day, for:) normalizuje datę do początku dnia, co pozwala zgrupować wpisy dotyczące tego samego dnia. To samo podejście działa dla tygodni, miesięcy i lat — wystarczy zmienić komponent w dateInterval na .weekOfYear lub .month.
| Scenariusz | Kluczowe API | Cecha |
|---|---|---|
| Obliczanie wieku | Calendar.dateComponents | Uwzględnić timeZone |
| Licznik wstecz | Date.timeIntervalSince | Timer+Combine |
| Grupowanie dat | Calendar.dateInterval | Normalizacja do dnia |
| Serializacja JSON | ISO8601DateFormatter | Locale nie wpływa |
Często zadawane pytania
Date — to wewnętrzna reprezentacja czasu bez powiązania z kalendarzem i lokalizacją. Ciąg znaków to sformatowany widok zależny od ustawień użytkownika. Date można porównywać, serializować i matematycznie przetwarzać ze stuprocentową dokładnością, natomiast reprezentacja tekstowa zawsze wymaga parsowania przez formatter.
Date — to absolutny znacznik czasu (liczba sekund od reference date), który nie zależy od strefy czasowej. Strefa czasowa to kontekst wyświetlania. Ten sam Date w UTC i w Warszawie reprezentuje ten sam fizyczny moment, ale wyświetla się jako różny czas kalendarzowy.
Date jest bezpośrednio obsługiwany przez Core Data jako typ atrybutu. Core Data automatycznie serializuje Date w magazynie. Do zapytań z filtrowaniem według daty używaj NSPredicate z operatorami porównania — Core Data poprawnie obsługuje timezone na poziomie SQLite.
CFAbsoluteTime — to typ Core Foundation używający tej samej reference date (1 stycznia 2001). Date i CFAbsoluteTime są wzajemnie wymienne przez bezpośrednią konwersję. Date(timeIntervalSinceReferenceDate:) przyjmuje CFAbsoluteTime, a Date.timeIntervalSinceReferenceDate zwraca CFAbsoluteTime.
Date ma dokładność do milisekundy, ale nie gwarantuje dokładności nanosekundowej z powodu ograniczeń sprzętowych iOS/macOS. Do precyzyjnych pomiarów używaj mach_absolute_time lub ContinuousClock z Swift 5.7+, które działają na sprzętowych licznikach cykli procesora.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również