Swift 中的绝对 UTC 偏移量
Absolute UTC offset in Swift
我的任务是创建一个字符串,其中包含 DST 期间和夏令时期间的 UTC 偏移量(例如:UTC+1UTC+2
或 UTC+1UTC+1
如果某个地区没有 DST)。我的函数如下所示:
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)"
}
}
它运行良好,我已经为它编写了测试。一切都很好,但在最近多个国家/地区的 DST 更改之后,测试开始失败,即使我通过了特定日期来计算偏移量:
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
。有什么想法可能是错误的吗?
一些事情:
在您的测试中,华沙和里斯本的偏移量减少了一个小时。华沙在标准时间为 UTC+1,在夏令时为 UTC+2。里斯本标准时间为 UTC+0,白天为 UTC+1。
从您的评论来看,您似乎正在寻找标准偏移量和日光偏移量。但是,标准偏移量不一定与 current 偏移量相同。当前偏移量可能包括夏令时,也可能不包括。
根据these docs,secondsFromGMT
函数returns差异包括日光调整,如果一个在影响。因此你不应该自己调整。
在夏令时不适用的日期向 daylightSavingTimeOffset
函数询问偏移量似乎没有意义。如果对当年的两个不同日期使用 secondsFromGMT
,您可能会获得更好的结果。一种常见的方法是获取 1 月 1 日和 7 月 1 日的偏移量。小者为标准时间,小者为夏令时。请记住,如果不使用 DST,它们可能相同,并且它们将在南北半球时区之间倒转。
- 即使采用上述方法,这种算法也忽略了很多时区的复杂性。考虑到某些时区在其历史的不同时间点更改了 标准时间 。这样的算法可能会将其误认为是夏令时的变化。
关注点:一旦你生成了你的字符串,比如"UTC+1UTC+2"
,你如何从外部API知道哪一组夏令时规则适用?由于 daylight saving time starts and stops at different dates and times in different parts of the world,在解释偏移量时可能会使用错误的日期。
我的任务是创建一个字符串,其中包含 DST 期间和夏令时期间的 UTC 偏移量(例如:UTC+1UTC+2
或 UTC+1UTC+1
如果某个地区没有 DST)。我的函数如下所示:
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)"
}
}
它运行良好,我已经为它编写了测试。一切都很好,但在最近多个国家/地区的 DST 更改之后,测试开始失败,即使我通过了特定日期来计算偏移量:
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
。有什么想法可能是错误的吗?
一些事情:
在您的测试中,华沙和里斯本的偏移量减少了一个小时。华沙在标准时间为 UTC+1,在夏令时为 UTC+2。里斯本标准时间为 UTC+0,白天为 UTC+1。
从您的评论来看,您似乎正在寻找标准偏移量和日光偏移量。但是,标准偏移量不一定与 current 偏移量相同。当前偏移量可能包括夏令时,也可能不包括。
根据these docs,
secondsFromGMT
函数returns差异包括日光调整,如果一个在影响。因此你不应该自己调整。在夏令时不适用的日期向
daylightSavingTimeOffset
函数询问偏移量似乎没有意义。如果对当年的两个不同日期使用secondsFromGMT
,您可能会获得更好的结果。一种常见的方法是获取 1 月 1 日和 7 月 1 日的偏移量。小者为标准时间,小者为夏令时。请记住,如果不使用 DST,它们可能相同,并且它们将在南北半球时区之间倒转。- 即使采用上述方法,这种算法也忽略了很多时区的复杂性。考虑到某些时区在其历史的不同时间点更改了 标准时间 。这样的算法可能会将其误认为是夏令时的变化。
关注点:一旦你生成了你的字符串,比如
"UTC+1UTC+2"
,你如何从外部API知道哪一组夏令时规则适用?由于 daylight saving time starts and stops at different dates and times in different parts of the world,在解释偏移量时可能会使用错误的日期。