Foundation Date identifies a moment, even though its name can sound like a calendar-only value. The same Date can display as different local dates and times in different zones. Calendar interprets that moment using calendar rules, while formatting creates text for a person or a protocol.
Start with the functions lesson. This reference teaches the distinction before adding convenience syntax. A birthday, a receipt timestamp and a shop's opening schedule need different models. Converting everything to an arbitrary midnight timestamp can change a date-only fact when another zone later displays it.
Date is independent of a displayed zone
A Date value is an absolute point in time, not a bundle containing one permanent year, month and hour. Calendar and TimeZone provide the context for extracting those fields. DateComponents represents selected calendar fields, which can be incomplete and need a calendar and zone to become a particular Date.
Use an event timestamp when a real global moment is known. For a date-only rule, preserve the intended calendar fields and their domain meaning rather than invent a universal midnight moment. For a scheduled local appointment, retain the relevant location's zone policy because future offsets can change.
TimeInterval is measured in seconds. It is useful for a fixed elapsed interval, but a month or local calendar day is not universally a fixed number of seconds. Make that unit explicit in parameters and stored values. A variable called duration should not ambiguously alternate between milliseconds and seconds across different APIs.
Calendar arithmetic states a business rule
Use Calendar.date(byAdding:value:to:) for a calendar-based change such as seven days later. Adding eighty-six thousand four hundred seconds is a different rule: exactly one elapsed twenty-four-hour interval. Across daylight-saving transitions those operations can produce different local results.
End-of-month rules also require attention. Adding one month to a late-January date needs a calendar resolution policy, not an assumption that every month has thirty days. Test the calendar's result against the business requirement and decide how recurring billing or reminders handle shorter months.
Local times can be nonexistent or repeated during zone transitions. Calendar APIs provide matching and repeated-time policies for such tasks. A booking system should choose and communicate its policy rather than silently assume every local clock reading describes one unique moment. Updating the runtime's time-zone data matters because governments can change the rules.
Formatting and parsing serve different audiences
Human-readable text should use localized formatting appropriate to the user. Machine formats should specify a stable contract, such as an ISO representation with an explicit offset. DateFormatter can be configured with a locale, calendar, time zone and pattern, but a formatting pattern alone does not settle all those choices.
For fixed-format parsing, use the appropriate stable locale and strict expectations. Do not assume a slash-separated date uses the same month/day order worldwide. Uppercase week-based year symbols and calendar-year symbols can differ near a year boundary, so use the pattern intended by the protocol rather than copying a visually similar one.
Avoid placing Date() throughout every function. Pass the current Date and needed Calendar into business logic, or inject a provider when that better fits the design. Tests can then supply a moment near midnight or a transition without waiting. A performance timer should use an appropriate monotonic clock rather than assume wall-clock adjustments cannot occur.
Separate the user's display zone from a business zone when they differ. A traveler may want receipts shown in their current location while a shop's payment cutoff follows its own local calendar. Store enough information to apply both policies and label the cutoff clearly. Changing a device preference should not silently change an already agreed deadline or reinterpret a historical event as a different moment.
Official references
Read Date and Calendar. Their official Date implementation documents the absolute-moment model. A temporal review should name the unit, calendar, zone, current-time source and invalid-input behavior; leaving one implicit often explains the eventual boundary bug.
Swift Dates, Calendars and Time Zones Examples
Each example shows the code, the output it produces and what each part does.
Interpret one fixed moment in two zones
The fixed offsets are selected for a deterministic demonstration. A real location schedule should use its named zone, not assume its current offset describes all historical and future dates. The force unwraps concern known valid constants and explicitly requested Gregorian components here; validate uncertain external values instead of copying those assumptions into an input parser.
import Foundation
let instant = Date(timeIntervalSince1970: 0)
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(secondsFromGMT: 0)!
let utc = calendar.dateComponents([.year, .month, .day, .hour], from: instant)
print("\(utc.year!)-\(utc.month!)-\(utc.day!):\(utc.hour!)")
calendar.timeZone = TimeZone(secondsFromGMT: 5 * 60 * 60)!
let local = calendar.dateComponents([.year, .month, .day, .hour], from: instant)
print("\(local.year!)-\(local.month!)-\(local.day!):\(local.hour!)")
print(Int(instant.timeIntervalSince1970))1970-1-1:0
1970-1-1:5
0Swift Dates, Calendars and Time Zones in Real Projects
Worked exercise: Calculate a shop deadline
Give a customer seven calendar days from an explicit reference moment. Use a Gregorian UTC calendar for this example and format the deadline through a fixed ISO formatter. Return an optional because calendar construction APIs can fail.
import Foundation
func paymentDeadline(from now: Date, calendar: Calendar) -> Date? {
calendar.date(byAdding: .day, value: 7, to: now)
}
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(secondsFromGMT: 0)!
let parser = ISO8601DateFormatter()
let now = parser.date(from: "2025-01-15T10:00:00Z")!
if let deadline = paymentDeadline(from: now, calendar: calendar) {
print(parser.string(from: deadline))
print(deadline > now)
}2025-01-22T10:00:00Z
trueThe known fixture is force-unwrapped, while the function preserves its optional result. Production input should handle a failed parse descriptively. If the shop means payment by the end of the seventh local day, this function needs a different explicit boundary policy; seven days at the same time is not automatically equivalent to a date-only deadline.
Swift Dates, Calendars and Time Zones FAQ
Why does Date not contain a time zone?
It represents one absolute moment independently of how that moment is displayed. A zone and calendar interpret the moment into local fields. Storing them separately avoids changing the event when a user changes presentation preferences. If a schedule's local meaning matters, retain the schedule's zone information as part of its domain model. Do not expect Date alone to remember that a meeting was originally entered for a particular city's wall clock.
Is adding one day the same as adding 86400 seconds?
They express different policies. Calendar-based day arithmetic advances through local calendar rules, while adding seconds advances a fixed elapsed interval. A daylight-saving transition can make their results differ. Choose the rule from the domain: tomorrow at the same local time or expire after exactly twenty-four hours. Test transition dates for supported zones and avoid relying exclusively on ordinary dates that happen to make both operations look equivalent.
Can I compare formatted date strings to determine order?
Usually compare Date values for global moments instead. Localized strings can use different field order, language and omitted information, so lexical order need not match chronology. A carefully specified machine format can have useful ordering properties, but that is a protocol guarantee requiring consistent offsets and representation. Formatting is primarily presentation; keeping typed temporal values preserves clearer comparison and arithmetic semantics than reparsing display text throughout the application.
How do I test code that depends on today?
Pass a reference Date and the business Calendar or an explicit time provider into the operation. The production caller supplies the current time, while a test supplies a fixed fixture near a relevant boundary. This avoids failures caused by midnight or a developer's default zone. Include the actual deadline day, the preceding day and any transition rule the business supports. Time dependency should be visible in the function contract rather than hidden in repeated now calls.
Swift Dates, Calendars and Time Zones Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
What makes the payment-deadline function reproducible in tests?
Swift Dates, Calendars and Time Zones Quiz
2 questions to check what you learned.
What does Foundation Date represent?
- Only a formatted string.
- One permanent local calendar date with a stored display zone.
- An absolute moment independent of calendar and time-zone presentation.
Which API expresses calendar-based addition of seven days?
- Calendar.date(byAdding: .day, value: 7, to: ...).
- A guessed fixed month length in seconds.
- Lexical sorting of localized display text.