Абсолютное смещение UTC в Swift - PullRequest
0 голосов
/ 06 ноября 2019

Моя задача - создать строку, содержащую смещение UTC во время летнего времени и в летнее время (например: UTC+1UTC+2 или UTC+1UTC+1, если для региона нет летнего времени). Моя функция выглядит следующим образом:

extension TimeZone {
    public func utcOffset(for date: Date = Date()) -> String {
        var currentTimeOffest = self.secondsFromGMT(for: date)
        if isDaylightSavingTime() {
            currentTimeOffest -= Int(daylightSavingTimeOffset(for: date))
        }
        let currentInHours = Int(currentTimeOffest / 3_600)
        let hoursSymbol: String = currentInHours > 0 ? "+" : ""

        let daylightOffset = TimeInterval(currentTimeOffest) + self.daylightSavingTimeOffset(for: date)
        let daylightInHours = Int(daylightOffset / 3_600)
        let daylightSymbol: String = daylightInHours > 0 ? "+" : ""

        return "UTC\(hoursSymbol)\(currentInHours)UTC\(daylightSymbol)\(daylightInHours)"
    }
}

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

    func testUtcOffset() {
        let date: Date = Date(timeIntervalSince1970: 1_557_482_400) //May 10, 2019 10:00:00 AM

        let warsaw = TimeZone.init(identifier: "Europe/Warsaw")! //eastern hemisphere, with DST
        XCTAssertEqual(warsaw.utcOffset(for: date), "UTC+2UTC+3")

        let shanghai = TimeZone.init(identifier: "Asia/Shanghai")! //eastern hemisphere, without DST
        XCTAssertEqual(shanghai.utcOffset(for: date), "UTC+8UTC+8")

        let barbados = TimeZone.init(identifier: "America/Barbados")! //western hemisphere, without DST
        XCTAssertEqual(barbados.utcOffset(for: date), "UTC-4UTC-4")

        let bermuda = TimeZone.init(identifier: "Atlantic/Bermuda")! //western hemisphere, with DST
        XCTAssertEqual(bermuda.utcOffset(for: date), "UTC-4UTC-3")

        let gmt = TimeZone.init(identifier: "GMT")! //GMT, without DST
        XCTAssertEqual(gmt.utcOffset(for: date), "UTC0UTC0")

        let lisbon = TimeZone.init(identifier: "Europe/Lisbon")! //GMT, with DST
        XCTAssertEqual(lisbon.utcOffset(for: date), "UTC+1UTC+2")
    }

2 недели назад, warsaw и lisbonчасовые пояса начали выходить из строя, сегодня bermuda. Есть идеи, что может быть не так?

1 Ответ

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

Несколько вещей:

  • В ваших тестах у вас есть смещения для Варшавы и Лиссабона на час от отпуска. Варшава - это UTC + 1 в стандартное время и UTC + 2 в летнее время. В Лиссабоне UTC + 0 в стандартное время и UTC + 1 в летнее время.

  • Из вашего комментария кажется, что вы ищете стандартное смещение и смещение дневного света. Однако стандартное смещение не обязательно совпадает со смещением current . Текущее смещение может включать летнее время или нет.

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

  • Кажется, не имеет смысла запрашивать функцию daylightSavingTimeOffset для смещения даты, когда переход на летнее время не выполняется. т применить. Вы можете получить лучшие результаты, просто используя secondsFromGMT для двух разных дат в текущем году. Общий подход заключается в том, чтобы получить смещения на 1 января и 1 июля. Чем меньше стандартное время, тем меньше дневное время. Имейте в виду, что они могут быть одинаковыми, если летнее время не используется, и они будут инвертированы между часовыми поясами северного и южного полушария.

    • Даже при описанном выше подходе этот алгоритм игнорирует многосложности часовых поясов. Учтите, что некоторые часовые пояса изменили свое стандартное время в разные моменты своей истории. Такой алгоритм может ошибочно принять за изменение летнего времени.
  • Проблема: как только вы сгенерируете свою строку, такую ​​как "UTC+1UTC+2", как изменится внешнийAPI вы знаете из одного этого, какой набор правил летнего времени применять? Поскольку летнее время начинается и заканчивается в разные даты и время в разных частях света , вполне вероятно, что при интерпретации смещений могут использоваться неправильные даты.

...