Skip to content
AgileLogics
5 min read

Dates and Formatting

Prerequisites: Structs

Foundation represents a moment in time with Date, and uses Calendar for anything involving days, months, and time zones.

Date

A Date is a single point in time, independent of time zones:

import Foundation

let now = Date()
let inOneHour = now.addingTimeInterval(3600)
print(inOneHour > now)
print(inOneHour.timeIntervalSince(now))

let epoch = Date(timeIntervalSince1970: 0)
print(ISO8601DateFormatter().string(from: epoch))
true
3600.0
1970-01-01T00:00:00Z

timeIntervalSince1970 is the Unix timestamp. The Unix Epoch Converter translates these back and forth.

Calendar arithmetic

Use Calendar rather than adding seconds, because days and months aren't a fixed length (daylight saving, leap years):

import Foundation

var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(identifier: "UTC")!

let start = calendar.date(from: DateComponents(year: 2025, month: 1, day: 31))!
let nextMonth = calendar.date(byAdding: .month, value: 1, to: start)!
let parts = calendar.dateComponents([.year, .month, .day], from: nextMonth)
print(parts.year!, parts.month!, parts.day!)

let end = calendar.date(from: DateComponents(year: 2025, month: 12, day: 25))!
print(calendar.dateComponents([.day], from: start, to: end).day!)
2025 2 28
328

Adding one month to 31 January gives 28 February — Calendar knows February is shorter.

Formatting for people

Dates shown to users should follow their language and region:

let text = Date().formatted(date: .abbreviated, time: .shortened)
// e.g. "Jan 15, 2025 at 9:30 AM" in the US, "15 Jan 2025 at 09:30" in the UK

Numbers work the same way: 1234.5.formatted(.currency(code: "EUR")).

Common mistakes

  • Formatting dates by hand with a fixed pattern for display. Use formatted(...) so users see their own conventions. Fixed formats are for exchanging data — use ISO 8601 (ISO8601DateFormatter) there.
  • Adding 86400 seconds for "one day". Use calendar.date(byAdding:).