Date Range Styles
Interval Date Style (Date Range) Xcode 13+
Shows the earliest and last dates in aRange, similar options to the Date and Time single date format style.
For a given Range<Date>, this format will output the earliest and last days.
| Symbol | Description | 
|---|---|
.day() | 
The numerical day relative to the month | 
.hour() | 
The hour | 
.minute() | 
The minute | 
.month() | 
The month of the year | 
.second() | 
The second | 
.timeZone | 
The time zone | 
.weekday() | 
The named day of the week | 
.year() | 
The year | 
let range = Date(timeIntervalSince1970: 0)..<Date(timeIntervalSinceReferenceDate: 2837)
range.formatted(.interval) // "12/31/69, 5:00 PM – 12/31/00, 5:47 PM"
range.formatted(.interval.day()) // "12/31/1969 – 12/31/2000"
range.formatted(.interval.hour()) // "12/31/1969, 5 PM – 12/31/2000, 5 PM"
range.formatted(.interval.hour(.conversationalDefaultDigits(amPM: .abbreviated))) // "12/31/1969, 5 PM – 12/31/2000, 5 PM"
range.formatted(.interval.hour(.conversationalDefaultDigits(amPM: .narrow))) // "12/31/1969, 5 p – 12/31/2000, 5 p"
range.formatted(.interval.hour(.conversationalDefaultDigits(amPM: .omitted))) // "12/31/1969, 5 PM – 12/31/2000, 5 PM"
range.formatted(.interval.hour(.conversationalDefaultDigits(amPM: .wide))) // "12/31/1969, 5 PM – 12/31/2000, 5 PM"
range.formatted(.interval.minute()) // "12/31/1969, 0 – 12/31/2000, 47"
range.formatted(.interval.month(.defaultDigits)) // "12/1969 – 12/2000"
range.formatted(.interval.month(.twoDigits)) // "12/1969 – 12/2000"
range.formatted(.interval.month(.wide)) // "December 1969 – December 2000"
range.formatted(.interval.month(.narrow)) // "D 1969 – D 2000"
range.formatted(.interval.month(.abbreviated)) // "Dec 1969 – Dec 2000"
range.formatted(.interval.second()) // "12/31/1969, 0 – 12/31/2000, 17"
range.formatted(.interval.timeZone()) // "12/31/1969, MST – 12/31/2000, MT"
range.formatted(.interval.timeZone(.exemplarLocation)) // "12/31/1969, Edmonton – 12/31/2000, Edmonton"
range.formatted(.interval.timeZone(.genericLocation)) // "12/31/1969, Edmonton Time – 12/31/2000, Edmonton Time"
range.formatted(.interval.timeZone(.genericName(.long))) // "12/31/1969, Mountain Standard Time – 12/31/2000, Mountain Time"
range.formatted(.interval.timeZone(.genericName(.short))) // "12/31/1969, MST – 12/31/2000, MT"
range.formatted(.interval.timeZone(.identifier(.short))) // "12/31/1969, caedm – 12/31/2000, caedm"
range.formatted(.interval.timeZone(.identifier(.long))) // "12/31/1969, America/Edmonton – 12/31/2000, America/Edmonton"
range.formatted(.interval.timeZone(.iso8601(.short))) // "12/31/1969, -0700 – 12/31/2000, -0700"
range.formatted(.interval.timeZone(.iso8601(.long))) // "12/31/1969, -07:00 – 12/31/2000, -07:00"
range.formatted(.interval.timeZone(.localizedGMT(.short))) // "GMT-7"
range.formatted(.interval.timeZone(.localizedGMT(.long))) // "12/31/1969, GMT-07:00 – 12/31/2000, GMT-07:00"
range.formatted(.interval.timeZone(.specificName(.long))) // "12/31/1969, Mountain Standard Time – 12/31/2000, Mountain Standard Time"
range.formatted(.interval.timeZone(.specificName(.short))) // "12/31/1969, MST – 12/31/2000, MST"
range.formatted(.interval.year()) //"1969 – 2000"
Date.IntervalFormatStyle().day().format(range) // "12/31/1969 – 12/31/2000"
Date.IntervalFormatStyle().hour().format(range) // "12/31/1969, 5 PM – 12/31/2000, 5 PM"
Date.IntervalFormatStyle().hour(.conversationalDefaultDigits(amPM: .abbreviated)).format(range) // "12/31/1969, 5 PM – 12/31/2000, 5 PM"
Date.IntervalFormatStyle().hour(.conversationalDefaultDigits(amPM: .narrow)).format(range) // "12/31/1969, 5 p – 12/31/2000, 5 p"
Date.IntervalFormatStyle().hour(.conversationalDefaultDigits(amPM: .omitted)).format(range) // "12/31/1969, 5 PM – 12/31/2000, 5 PM"
Date.IntervalFormatStyle().hour(.conversationalDefaultDigits(amPM: .wide)).format(range) // "12/31/1969, 5 PM – 12/31/2000, 5 PM"
Date.IntervalFormatStyle().minute().format(range) // "12/31/1969, 0 – 12/31/2000, 47"
Date.IntervalFormatStyle().month(.defaultDigits).format(range) // "12/1969 – 12/2000"
Date.IntervalFormatStyle().month(.twoDigits).format(range) // "12/1969 – 12/2000"
Date.IntervalFormatStyle().month(.wide).format(range) // "December 1969 – December 2000"
Date.IntervalFormatStyle().month(.narrow).format(range) // "D 1969 – D 2000"
Date.IntervalFormatStyle().month(.abbreviated).format(range) // "Dec 1969 – Dec 2000"
Date.IntervalFormatStyle().second().format(range) // "12/31/1969, 0 – 12/31/2000, 17"
Date.IntervalFormatStyle().timeZone().format(range) // "12/31/1969, MST – 12/31/2000, MT"
Date.IntervalFormatStyle().timeZone(.exemplarLocation).format(range) // "12/31/1969, Edmonton – 12/31/2000, Edmonton"
Date.IntervalFormatStyle().timeZone(.genericLocation).format(range) // "12/31/1969, Edmonton Time – 12/31/2000, Edmonton Time"
Date.IntervalFormatStyle().timeZone(.genericName(.long)).format(range) // "12/31/1969, Mountain Standard Time – 12/31/2000, Mountain Time"
Date.IntervalFormatStyle().timeZone(.genericName(.short)).format(range) // "12/31/1969, MST – 12/31/2000, MT"
Date.IntervalFormatStyle().timeZone(.identifier(.short)).format(range) // "12/31/1969, caedm – 12/31/2000, caedm"
Date.IntervalFormatStyle().timeZone(.identifier(.long)).format(range) // "12/31/1969, America/Edmonton – 12/31/2000, America/Edmonton"
Date.IntervalFormatStyle().timeZone(.iso8601(.short)).format(range) // "12/31/1969, -0700 – 12/31/2000, -0700"
Date.IntervalFormatStyle().timeZone(.iso8601(.long)).format(range) // "12/31/1969, -07:00 – 12/31/2000, -07:00"
Date.IntervalFormatStyle().timeZone(.localizedGMT(.short)).format(range) // "GMT-7"
Date.IntervalFormatStyle().timeZone(.localizedGMT(.long)).format(range) // "12/31/1969, GMT-07:00 – 12/31/2000, GMT-07:00"
Date.IntervalFormatStyle().timeZone(.specificName(.long)).format(range) // "12/31/1969, Mountain Standard Time – 12/31/2000, Mountain Standard Time"
Date.IntervalFormatStyle().timeZone(.specificName(.short)).format(range) // "12/31/1969, MST – 12/31/2000, MST"
Date.IntervalFormatStyle().year().format(range) //"1969 – 2000"
You can customize the locale of the output by appending the localized() method onto the style.
let franceLocale = Locale(identifier: "fr_FR")
range.formatted(.interval.locale(franceLocale)) // "31/12/1969 à 17:00 – 31/12/2000 à 17:47"
| DateStyle | Description | 
|---|---|
.omitted | 
Excludes the date part. | 
.numeric | 
Shows date components in their numeric form. For example, “10/21/2015”. | 
.abbreviated | 
Shows date components in their abbreviated form if possible. For example, “Oct 21, 2015”. | 
.long | 
Shows date components in their long form if possible. For example, “October 21, 2015”. | 
.complete | 
Shows the complete day. For example, “Wednesday, October 21, 2015”. | 
| TimeStyle | Description | 
|---|---|
.omitted | 
Excludes the time part. | 
.shortened | 
For example, 04:29 PM, 16:29. | 
.standard | 
For example, 4:29:24 PM, 16:29:24. | 
.complete | 
For example, 4:29:24 PM PDT, 16:29:24 GMT. | 
struct NarrowIntervalStyle: FormatStyle {
    static let interval = Date.IntervalFormatStyle(
        date: .abbreviated,
        time: .shortened,
        locale: Locale(identifier: "en_US"),
        calendar: Calendar(identifier: .gregorian),
        timeZone: TimeZone(secondsFromGMT: 0)!
    )
    func format(_ value: Range<Date>) -> String {
        NarrowIntervalStyle.interval.format(value)
    }
}
extension FormatStyle where Self == NarrowIntervalStyle {
    static var narrowInterval: NarrowIntervalStyle { .init() }
}
range.formatted(.narrowInterval)
Components Date Style (Date Range) Xcode 13+
Shows the distance between the earliest and latest dates in a range, similar to the Relative Date style for single dates.
For a given Range<Date>, you can display the distance between the earliest and latest dates using specific units.
For all given fields, the system will only display the unit if it’s not a 0 value. Including the field will only specify that the unit might be used.
dayhourminutemonthsecondweekyear
| Style Option | Description | 
|---|---|
| wide | Shows the fields in their full spelling. For example, “2 hour, 10 minutes”, “2小時10分鐘”  | 
| abbreviated | Shows the fields in the abbreviation.  For example, “2 hr, 10 min”, “2小時10分鐘”  | 
| condensedAbbreviated | Uses the abbreviated form but condensed if possible.  For example, “2hr 10min”, “2小時10分鐘”  | 
| narrow | Shows the fields in the shortest form possible.  For example, “2h 10m”, “2時10分”  | 
| spellOut | Values are spelled out and fields are displayed in their full name. For example, “two hours, ten minutes”, “2小時10分鐘”  | 
let testRange = Date(timeIntervalSince1970: 0) ..< Date(timeIntervalSinceReferenceDate: 0)
testRange.formatted(.components(style: .abbreviated, fields: [.day]))           // "11,323 days"
testRange.formatted(.components(style: .narrow, fields: [.day]))                // "11,323days"
testRange.formatted(.components(style: .wide, fields: [.day]))                  // "11,323 days"
testRange.formatted(.components(style: .spellOut, fields: [.day]))              // "eleven thousand three hundred twenty-three days"
testRange.formatted(.components(style: .condensedAbbreviated, fields: [.day]))  // "11,323d"
testRange.formatted(.components(style: .abbreviated, fields: [.year])
    .calendar(Calendar(identifier: .coptic))) // "31 yrs"
testRange.formatted(.components(style: .condensedAbbreviated, fields: [.day, .month, .year, .hour, .second, .week])) // "31y"
let appleReferenceDay = Date(timeIntervalSinceReferenceDate: 0)
let twosday = Calendar(identifier: .gregorian).date(from: twosdayDateComponents)!
let secondRange = appleReferenceDay .. <twosday
// 21 yrs, 1 mth, 3 wks, 9 hr, 1,342 sec
secondRange.formatted(.components(style: .abbreviated, fields: [.day, .month, .year, .hour, .second, .week]))
// 21yrs 1mth 3wks 9hr 1,342sec
secondRange.formatted(.components(style: .narrow, fields: [.day, .month, .year, .hour, .second, .week]))
// 21 years, 1 month, 3 weeks, 9 hours, 1,342 seconds
secondRange.formatted(.components(style: .wide, fields: [.day, .month, .year, .hour, .second, .week]))
// twenty-one years, one month, three weeks, nine hours, one thousand three hundred forty-two seconds
secondRange.formatted(.components(style: .spellOut, fields: [.day, .month, .year, .hour, .second, .week]))
// 21y 1mo 3w 9h 1,342s
secondRange.formatted(.components(style: .condensedAbbreviated, fields: [.day, .month, .year, .hour, .second, .week]))
You can set the locale by appending the locale() method onto the end of the format style.
let franceLocale = Locale(identifier: "fr_FR")
// vingt-et-un ans, un mois, trois semaines, neuf heures et mille trois cent quarante-deux secondes
secondRange.formatted(.components(style: .spellOut, fields: [.day, .month, .year, .hour, .second, .week]).locale(franceLocale))
You can set the calendar by using the Date.ComponentFormatStyle initializer and using the resulting format style.
let componentsFormat = Date.ComponentsFormatStyle(
    style: .wide,
    locale: Locale(identifier: "fr_FR"),
    calendar: Calendar(identifier: .gregorian),
    fields: [
        .day,
        .month,
        .year,
        .hour,
        .second,
        .week,
    ]
)
componentsFormat.format(secondRange)    // "21 ans, 1 mois, 3 semaines, 9 heures et 1 342 secondes"
secondRange.formatted(componentsFormat) // "21 ans, 1 mois, 3 semaines, 9 heures et 1 342 secondes"
struct InFrench: FormatStyle {
    typealias FormatInput = Range<Date>
    typealias FormatOutput = String
    static let componentsFormat = Date.ComponentsFormatStyle(
        style: .wide,
        locale: Locale(identifier: "fr_FR"),
        calendar: Calendar(identifier: .gregorian),
        fields: [
            .day,
            .month,
            .year,
            .hour,
            .second,
            .week,
        ]
    )
    func format(_ value: Range<Date>) -> String {
        InFrench.componentsFormat.format(value)
    }
}
extension FormatStyle where Self == InFrench {
    static var inFrench: InFrench { .init() }
}
secondRange.formatted(.inFrench) // "21 ans, 1 mois, 3 semaines, 9 heures et 1 342 secondes"