Неправильный идентификатор часового пояса в Англии

#ios #swift #timezone

#iOS #swift #Часовой пояс

Вопрос:

В Англии мы используем GMT для нашего часового пояса зимой и BST летом. По британскому летнему времени. В настоящее время по Гринвичу, но когда я использую этот код для получения правильной аббревиатуры, он выдает мне время по британскому летнему времени:

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

Если я распечатаю TimeZone.current.identifier , это даст мне Europe/London . Когда я распечатываю TimeZone.abbreviationDictionary , это дает мне это:

[«MST»: «Америка / Феникс», «ICT»: «Азия / Бангкок», «NZST»: «Тихий океан / Окленд», «CDT»: «Америка / Чикаго», «UTC»: «UTC», «ЗАПАД»: «Европа / Лиссабон», «HKT»: «Азия / Гонконг», «CST»: «Америка / Чикаго», «PKT»: «Азия / Карачи», «BST»: «Европа / Лондон», «KST»: «Азия / Сеул», «PET»: «Америка / Лима», «По британскому летнему времени».SGT»: «Азия / Сингапур», «GST»: «Азия / Дубай», «MDT»: «Америка / Денвер», «BRST»: «Америка / Sao_Paulo», «ART»: «Америка / Аргентина / Buenos_Aires», «CET»: «Европа / Париж», «AST»: «Америка / Галифакс», «NZDT»: «Тихий океан / Окленд», «JST»: «Азия / Токио», «CEST»: «Европа / Париж», «BRT»: «Америка / Сао_Пауло», «HST»: «Тихий океан / Гонолулу», «WIT»: «Азия / Джакарта», «WET»: «Европа / Лиссабон», «AKST»: «Америка / Джуно», «NST»: «Америка / St_Johns», «EEST»: «Европа / Афины», «CLT»: «Америка / Сантьяго», «EST»: «Америка / Нью-Йорк», «PHT»: «Азия / Манила», «GMT»: «GMT», «CLST»: «Америка / Сантьяго», «MSD»: «Европа / Москва», «TRT»: «Европа / Стамбул», «PDT»: «Америка / Лос-Анджелес», «КОТ»: «Америка / Богота», «PST»: «Америка / Лос-Анджелес», «Первый»: «Азия / Тегеран», «MSK»: «Европа / Москва», «IST»: «Азия / Калькутта», «NDT»: «Америка / St_Johns», «WAT»: «Африка / Лагос», «ADT»: «Америка / Галифакс», «BDT»: «Азия / Дакка», «AKDT»: «Америка / Джуно», «CAT»: «Африка / Хараре», «EAT»: «Африка / Addis_Ababa», «EET»: «Европа / Афины», «EDT»: «Америка / Нью-Йорк»]

Как вы можете видеть, там есть GMT, но для того, чтобы получить это, TimeZone.current.identifier необходимо вернуть GMT , а не Europe/London . Это ошибка? Как я могу это исправить?

Комментарии:

1. Не используйте GMT в качестве часового пояса для получения местного времени в Англии.

2. @ElTomato Что?

3. Вы не можете получить используемую в настоящее время аббревиатуру из этого словаря, она не содержит этой информации. Как вы можете видеть, для большинства регионов это один и тот же идентификатор как для DST, так и для сокращений, отличных от DST.

4. @GuyIncognito должен TimeZone.current.abbreviation(for: someDate) дать мне правильную аббревиатуру, которая адаптируется к DST независимо от того, где я нахожусь?

5. Обновление: это не сработало должным образом. Это работает для Англии, но когда я меняю свой часовой пояс на другие места, он просто говорит GMT 2 и т. Д

Ответ №1:

Существует два значения "Europe/London" , поскольку, как вы сказали, существует сокращение для зимы GMT , а также для сохранения дневного света летом с сокращением BST . Таким образом, возврат некоторого первого ключа из словаря не будет работать, поскольку у вас нет возможности определить, какой из них подходит вам (по крайней мере, если вы не хотите жестко запрограммированного решения).

То, что вы ищете, — это метод abbreviation() , который возвращает правильную аббревиатуру для вашего, TimeZone если он знает свой идентификатор, и у вас есть правильный Locale .

И это то, что вас, возможно, смущает. Это просто не работает, например TimeZone(secondsFromGMT: 3600) . Это потому GMT 1 , что просто не определяет, предназначен ли он BST для Англии летом или, например CET , используется для Чешской Республики зимой, вы только что сказали, что это в часе езды GMT . Вы должны создать TimeZone using TimeZone(identifier:) , чтобы указать идентификатор.

Но пользователь использует свое устройство TimeZone.current , которое уже возвращает часовой пояс, который знает его идентификатор, и у него также есть Locale , который знает его аббревиатуру, поэтому вам не нужно беспокоиться, что пользователь увидит что-то вроде GMT 1 Europe/London вместо BST или GMT-8 America/Los_Angeles вместо PST


Чтобы показать вам, как это работает для разных идентификаторов и для разных сезонов, я использовал метод abbreviation(for:) для given Date , где 1577836800 представляет дату зимой и 1595289600 дата летом:

 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
 

Вы также можете использовать DateFormatter для форматирования даты с сокращением. Для этого вы хотите использовать символы 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
 

Обратите внимание, что это может не сработать для других регионов. Например, если вы находитесь в Великобритании, он будет форматировать сокращение для часового пояса America/Los_Angeles как GMT-8 вместо PST .

Это можно исправить вручную, изменив язык форматирования:

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

Но, как я уже сказал. Пользователь в большинстве случаев имеет свой Locale и TimeZone по умолчанию соответствует тому, что вам может понадобиться. Итак, для базовой работы с Date() or Date() timeInterval он должен работать.

Комментарии:

1. Удалил мои предыдущие комментарии. Я только что понял, что мой язык был настроен на Locale(identifier: "en_US_POSIX") то, что путало часовые пояса. Установка его в Locale.current, похоже, исправляет это. Пожалуйста, не могли бы вы обновить свой ответ некоторой информацией о локали для будущих читателей, спасибо!

2. @Tometoyou да, это то, о чем я забыл упомянуть. Сейчас это в моем ответе. 😌