#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 да, это то, о чем я забыл упомянуть. Сейчас это в моем ответе. 😌