Search code examples
swiftdatetimezonetimezone-offset

What is wrong with this Swift TimeZone for abbreviation for a date in another timezone assumption?


In an Xcode playground with the following Swift code, I get the commented output. Given a MST TimeZone object and a date that would be in the MDT TimeZone for this MST TimeZone, I do not receive the expected MDT TimeZone abbreviation output. What am I not understanding about this function, and how do I get the desired output of figuring out which of the two possible timezones a given date is in given the current example MST timezone?

// Daylight saving time (MDT) 2021 in Colorado began at 2:00 AM on Sunday, March 14
let mstDate = Date(timeIntervalSinceReferenceDate: 636327068) // "Mar 1, 2021 at 2:31 PM"
let mdtDate = Date(timeIntervalSinceReferenceDate: 637709468) // "Mar 17, 2021 at 3:31 PM"
let mstTimeZone = TimeZone(abbreviation: "MST")!
let mdtTimeZone = TimeZone(abbreviation: "MDT")!

mstTimeZone.abbreviation(for: mstDate) // expected MST, got MST
mstTimeZone.abbreviation(for: mdtDate) // expected MDT, got *****MST*****?

mdtTimeZone.abbreviation(for: mstDate) // expected MST, got MST
mdtTimeZone.abbreviation(for: mdtDate) // expected MDT, got MDT

Solution

  • Do not rely on timezone abbreviations. MST means "Mountain Standard Time" but it is being interpreted as Phoenix, Arizona ("America/Phoenix") instead of Denver, Colorado ("America/Denver"). You should always use timezone identifiers instead of abbreviations which are ambiguous. The timezone identifier doesn't change based on a date. What you need is to check if it is daylight saving or not for the desired date/timezone and get a timezone localized name based on it:

    extension TimeZone {
        static let denverCO = Self(identifier: "America/Denver")!
        func localizedName(for date: Date) -> String { localizedName(for: isDaylightSavingTime(for: date) ? .daylightSaving : .standard, locale: .current) ?? "" }
        func localizedNameShort(for date: Date) -> String { localizedName(for: isDaylightSavingTime(for: date) ? .shortDaylightSaving : .shortStandard, locale: .current) ?? "" }
    }
    

    let mst = Date(timeIntervalSinceReferenceDate: 636327068) // "Mar 1, 2021 at 2:31 PM"
    let mdt = Date(timeIntervalSinceReferenceDate: 637709468) // "Mar 17, 2021 at 3:31 PM"
    

    TimeZone.denverCO.localizedName(for: mst)  // "Mountain Standard Time"
    TimeZone.denverCO.localizedName(for: mdt)  // "Mountain Daylight Time"
    
    TimeZone.denverCO.localizedNameShort(for: mst)  // "MST"
    TimeZone.denverCO.localizedNameShort(for: mdt)  // "MDT"