Проблемы с инициализацией TimeZone из TimeZone.abbreviation () - PullRequest
0 голосов
/ 05 ноября 2019

Я храню даты рождения пользователей на своем бэкэнде через хранилище словаря компонентов даты. Это выглядит примерно так:

{
    "day": 1,
    "month": 1,
    "year": 1970,
    "timeZone": "GMT"
}

Чтобы сохранить этот объект, он берет день рождения, месяц и год пользователя из пользовательского ввода. Часовой пояс пользователя, однако, собирается через TimeZone.current.abbreviation().

Теперь некоторые из моих объектов рождения пользователя на моем бэкэнде имеют "timeZone" в формате "CST", "BST" или "PDT","timeZone" s, отформатированные таким образом, успешно инициализируют TimeZone на внешнем интерфейсе через let timeZone = TimeZone(abbreviation: "CST")!, let timeZone = TimeZone(abbreviation: "BST")! или let timeZone = TimeZone(abbreviation: "PDT")! соответственно.

Проблема в том, что другие объекты рождения пользователя намой бэкэнд имеет "timeZone" в формате "GMT+8". При попытке инициализировать "timeZone" s, отформатированный таким образом, через let timeZone = TimeZone(abbreviation: "GMT+8")!, инициализация возвращает nil. Я также попробовал let timeZone = TimeZone(identifier: "GMT+8")!, но это также возвращает nil.

Есть ли способ инициализировать TimeZone, когда он отформатирован с учетом его смещения по Гринвичу, а не его уникального сокращения? Я видел TimeZone инициализатор, который TimeZone(secondsFromGMT: Int). Могу ли я просто взять 8 из "GMT+8" и умножить его на 3600 (количество секунд в часе) и передать этот результат в TimeZone(secondsFromGMT: Int)?

1 Ответ

1 голос
/ 05 ноября 2019

В итоге я написал код, который адаптирует мое приложение для учета этих неожиданных незначительных случаев, когда аббревиатура TimeZone форматируется как "GMT+8", а не "SGT". Я создал расширение для TimeZone:

extension TimeZone {
    static func timeZone(from string: String) -> TimeZone {
        //The string format passed into this function should always be similar to "GMT+8" or "GMT-3:30"

        if string.contains("±") {
            //This case should always be "GMT±00:00", or simply GMT
            return TimeZone(secondsFromGMT: 0)!
        } else {

            //If the string doesn't contain "±", then there should be some offset. We will split the string into timeZone components. "GMT+8" would split into ["GMT", "8"]. "GMT-3:30" would split int ["GMT","3","30"]
            let timeZoneComponents = string.components(separatedBy: CharacterSet(charactersIn: "+-:"))
            var isAheadOfGMT: Bool!

            //Check if the string contains "+". This will dictate if we add or subtract seconds from GMT
            if string.contains("+") {
                isAheadOfGMT = true
            } else {
                isAheadOfGMT = false
            }

            //Grab the second element in timeZoneElements. This represents the offset in hours
            let offsetInHours = Int(timeZoneComponents[1])!

            //Convert these hours into seconds
            var offsetInSeconds: Int!
            if isAheadOfGMT {
                offsetInSeconds = offsetInHours * 3600
            } else {
                offsetInSeconds = offsetInHours * -3600
            }

            //Check if there is a colon in the passed string. If it does, then there are additional minutes we need to account for
            if string.contains(":") {
                let additionalMinutes = Int(timeZoneComponents[2])!
                let additionalSeconds = additionalMinutes * 60
                offsetInSeconds += additionalSeconds
            }

            //Create a TimeZone from this calculated offset in seconds
            let timeZoneFromOffset = TimeZone(secondsFromGMT: offsetInSeconds)!

            //Return this value
            return timeZoneFromOffset
        }
    }
}

Используется так:

let json: [String:String] = ["timeZone":"GMT+8"]
let timeZone = json["timeZone"]
let birthDate: BirthDate!
if let timeZoneFromAbbrev = TimeZone(abbreviation: timeZone) {
    birthDate = BirthDate(day: birthDay, month: birthMonth, year: birthYear, timeZone: timeZoneFromAbbrev)
} else {       
    let timeZoneFromOffset = TimeZone.timeZone(from: timeZone)
    print(timeZoneFromOffset.abbreviation())
    //Prints "GMT+8"

    birthDate = BirthDate(day: birthDay, month: birthMonth, year: birthYear, timeZone: timeZoneFromOffset)
}

Мой BirthDate класс для контекста:

class BirthDate {
    var day: Int
    var month: Int
    var year: Int
    var timeZone: TimeZone

    init(day: Int, month: Int, year: Int, timeZone: TimeZone) {
        self.day = day
        self.month = month
        self.year = year
        self.timeZone = timeZone
    }
}

Часовые пояса - забавные вещи для работы. Если кто-нибудь увидит проблему с расширением TimeZone выше, пожалуйста, дайте мне знать. Я думаю, что я учел все сценарии, но могу ошибаться.

...