1
votes

In England, we use GMT for our timezone in winter and BST in summer. It's currently GMT but when I use this code to get the correct abbreviation it gives me BST:

let abbreviation = TimeZone.abbreviationDictionary.filter { $0.value == TimeZone.current.identifier }.keys.first

If I print out the TimeZone.current.identifier it gives me Europe/London. When I print out the TimeZone.abbreviationDictionary it gives me this:

["MST": "America/Phoenix", "ICT": "Asia/Bangkok", "NZST": "Pacific/Auckland", "CDT": "America/Chicago", "UTC": "UTC", "WEST": "Europe/Lisbon", "HKT": "Asia/Hong_Kong", "CST": "America/Chicago", "PKT": "Asia/Karachi", "BST": "Europe/London", "KST": "Asia/Seoul", "PET": "America/Lima", "SGT": "Asia/Singapore", "GST": "Asia/Dubai", "MDT": "America/Denver", "BRST": "America/Sao_Paulo", "ART": "America/Argentina/Buenos_Aires", "CET": "Europe/Paris", "AST": "America/Halifax", "NZDT": "Pacific/Auckland", "JST": "Asia/Tokyo", "CEST": "Europe/Paris", "BRT": "America/Sao_Paulo", "HST": "Pacific/Honolulu", "WIT": "Asia/Jakarta", "WET": "Europe/Lisbon", "AKST": "America/Juneau", "NST": "America/St_Johns", "EEST": "Europe/Athens", "CLT": "America/Santiago", "EST": "America/New_York", "PHT": "Asia/Manila", "GMT": "GMT", "CLST": "America/Santiago", "MSD": "Europe/Moscow", "TRT": "Europe/Istanbul", "PDT": "America/Los_Angeles", "COT": "America/Bogota", "PST": "America/Los_Angeles", "IRST": "Asia/Tehran", "MSK": "Europe/Moscow", "IST": "Asia/Kolkata", "NDT": "America/St_Johns", "WAT": "Africa/Lagos", "ADT": "America/Halifax", "BDT": "Asia/Dhaka", "AKDT": "America/Juneau", "CAT": "Africa/Harare", "EAT": "Africa/Addis_Ababa", "EET": "Europe/Athens", "EDT": "America/New_York"]

As you can see, there is a GMT in there but in order to get that, the TimeZone.current.identifier must return GMT and not Europe/London. Is this a bug? How can I fix this?

1
Don't use GMT as a time zone to get the local time in England. - El Tomato
@ElTomato What? - Tometoyou
You can't get the currently used abbreviation from that dictionary, it doesn't contain that information. As you can see for most regions it's the same identifier for both DST and non-DST abbreviations. - Guy Incognito
@GuyIncognito should TimeZone.current.abbreviation(for: someDate) give me the correct abbreviation that adjusts to DST no matter where I am? - Tometoyou
Update: that didn't work properly. It works for england but when I change my timezone to other places it just says GMT+2 etc - Tometoyou

1 Answers

2
votes

There are two values "Europe/London" since as you said there is abbreviation for winter GMT as well as for day light saving summer with abbreviation BST. So returning some first key from dictionary won't work since you have no possibility to determine which is suitable for you (at least if you don't want hard-coded solution).

What you are looking for is method abbreviation() which returns correct abbreviation for your TimeZone if it knows its identifier and you have correct Locale.

And this is what you are maybe confused about. It simply doesn't work for for example TimeZone(secondsFromGMT: 3600). This is because GMT+1 simply doesn't identify if it is BST for England in summer or e.g. CET used for Czech Republic in winter, you just said that it is one hour from GMT. You have to create TimeZone using TimeZone(identifier:) in order to specify identifier.

But, user uses his device already has TimeZone.current which returns time zone which knows its identifier and he also has Locale which knows his abbreviation, so you don't have to worry that user would see something like GMT+1 for Europe/London instead of BST or GMT-8 for America/Los_Angeles instead of PST


To show you how it works for different identifiers and for different seasons I used method abbreviation(for:) for given Date where 1577836800 representing date in winter and 1595289600 date in summer:

TimeZone(identifier: "Europe/London")?
    .abbreviation(for: Date(timeIntervalSince1970: 1577836800)) // GMT
TimeZone(identifier: "Europe/London")?
    .abbreviation(for: Date(timeIntervalSince1970: 1595289600)) // BST
TimeZone(identifier: "Europe/Prague")?
    .abbreviation(for: Date(timeIntervalSince1970: 1577836800)) // CET
TimeZone(identifier: "Europe/Prague")?
    .abbreviation(for: Date(timeIntervalSince1970: 1595289600)) // CEST

You may also want to use DateFormatter in order to format date with abbreviation. In order to do that you want to use characters aaa:

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "d.M.yyyy zzz"

dateFormatter.timeZone = TimeZone(identifier: "Europe/London")
dateFormatter.string(from: Date(timeIntervalSince1970: 1577836800)) // 1.1.2020 GMT
dateFormatter.string(from: Date(timeIntervalSince1970: 1595289600)) // 21.7.2020 BST

dateFormatter.timeZone = TimeZone(identifier: "Europe/Prague")
dateFormatter.string(from: Date(timeIntervalSince1970: 1577836800)) // 1.1.2020 CET
dateFormatter.string(from: Date(timeIntervalSince1970: 1595289600)) // 21.7.2020 CEST

Note that it may not work for other regions. For example if you are in UK, it will format abbreviation for time zone America/Los_Angeles as GMT-8 instead of PST.

This you can manually fix by changing formatter's locale:

dateFormatter.locale = Locale(identifier: "en_US")

But as I said. User in most cases has its Locale and TimeZone by default corresponding to what you may need. So for basic working with Date() or Date() + timeInterval it should work.