为啥不同时区对时间的解释不同?
Posted
技术标签:
【中文标题】为啥不同时区对时间的解释不同?【英文标题】:Why are times being interpreted differently in different time zones?为什么不同时区对时间的解释不同? 【发布时间】:2017-08-12 16:44:39 【问题描述】:import UIKit
import Foundation
let dateString = "2017-08-13T05:10:00Z"
let dateFormatter = ISO8601DateFormatter()
if var date = dateFormatter.date(from: dateString)
if let newYorkTimeZone = TimeZone(abbreviation: "EDT")
date.addTimeInterval(TimeInterval(newYorkTimeZone.secondsFromGMT(for: date)))
print("NY time:", date, date.hour())
if var date = dateFormatter.date(from: dateString)
if let chiTimeZone = TimeZone(abbreviation: "CDT")
date.addTimeInterval(TimeInterval(chiTimeZone.secondsFromGMT(for: date)))
print("CHI time:", date, date.hour())
if let gmt = TimeZone(abbreviation: "GMT")
if var date = dateFormatter.date(from: dateString)
print("GMT time:", date, date.hour())
extension Date
func hour() -> String
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "h:mm a"
return dateFormatter.string(from: self)
我的系统设置为 EDT 时的输出:
纽约时间:2017-08-13 01:10:00 +0000 9:10 PM
CHI时间:2017-08-13 00:10:00 +0000 8:10 PM
格林威治标准时间:2017-08-13 05:10:00 +0000 1:10 AM
我的系统设置为 CDT 时的输出:
纽约时间:2017-08-13 01:10:00 +0000 8:10 PM
CHI时间:2017-08-13 00:10:00 +0000 7:10 PM
格林威治标准时间:2017-08-13 05:10:00 +0000 12:10 AM
无论我在哪个时区,这些时间不应该保持不变吗?我没有使用与TimeZone.current
相关的任何内容。
注意:我知道使用TimeZone.secondsFromGMT:
是更好的做法,但使用缩写参数更容易阅读此问题中发生的情况。
【问题讨论】:
你的代码没有意义。可可日期对象是整个星球上的一个瞬间。在我写这篇文章的时候,大约是美国东部时间下午 1:00,中部时间下午 12:00。为什么同一个Date
对象会在不同时区显示相同的时间?
您应该使用设置为所需时区的日期格式化程序以当地时间表示该日期。
您的两组输出之间唯一不同的是调用hour
的结果,而您的hour
函数基于您当前的语言环境和当前时区。因此,当您更改系统的时区时,这些值当然会发生变化。
不要使用时区缩写。它们可能是模棱两可的。一直使用长格式tzdb identifier,如America/New_York
、America/Chicago
等
【参考方案1】:
这是我在操场上的代码版本。
import UIKit
let dateString = "2017-08-13T05:10:00Z"
let isoDateFormatter = ISO8601DateFormatter()
guard let date = isoDateFormatter.date(from: dateString) else assert(false)
let gmtDateFormatter = DateFormatter()
gmtDateFormatter.timeZone = TimeZone(secondsFromGMT: 0)!
gmtDateFormatter.dateStyle = .medium
gmtDateFormatter.timeStyle = .medium
let nyDateFormatter = DateFormatter()
nyDateFormatter.timeZone = TimeZone(abbreviation: "EDT")!
nyDateFormatter.dateStyle = .medium
nyDateFormatter.timeStyle = .medium
let chiDateFormatter = DateFormatter()
chiDateFormatter.timeZone = TimeZone(abbreviation: "CDT")!
chiDateFormatter.dateStyle = .medium
chiDateFormatter.timeStyle = .medium
let gmtDate = gmtDateFormatter.string(from: date) // -> Aug 13, 2017, 5:10:00 AM
let nyDate = nyDateFormatter.string(from: date) // -> Aug 13, 2017, 1:10:00 AM
let chiDate = chiDateFormatter.string(from: date) // -> Aug 13, 2017, 12:10:00 AM
日期是一个固定的时间点,它没有时区或夏令时。要获得时间的字符串表示,请将DateFormatter
与应用的时区一起使用。我的 Playground 设置为默认的美国语言环境,但我可以更改任何日期格式化程序的语言环境以不同方式显示日期和时间。
您不需要为您拥有的日期添加间隔,您只需要格式化它的输出,这就是 DateFormatter 的用途。
【讨论】:
好的,我现在明白了。我应该用DateFormatter
改变日期的显示方式,而不是试图改变Date
本身。【参考方案2】:
考虑这段代码:
let now = Date()
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .medium
func printDate(_ aDate: Date, inTimeZone timeZoneString: String? = nil)
let timeZone: TimeZone!
if let timeZoneString = timeZoneString
timeZone = TimeZone(abbreviation: timeZoneString)
guard timeZone != nil else
print("invalid time zone string \(timeZoneString)")
return
else
timeZone = TimeZone.current
formatter.timeZone = timeZone
print("Date = \(formatter.string(from: now)) in time zone \(timeZone.abbreviation()!)")
printDate(now)
printDate(now, inTimeZone: "CDT")
printDate(now, inTimeZone: "GMT")
printDate(now, inTimeZone: "NZST")
在 EDT 中运行:输出为:
Date = Aug 12, 2017, 1:17:13 PM in time zone EDT
Date = Aug 12, 2017, 12:17:13 PM in time zone CDT
Date = Aug 12, 2017, 5:17:13 PM in time zone GMT
Date = Aug 13, 2017, 5:17:13 AM in time zone GMT+12
【讨论】:
以上是关于为啥不同时区对时间的解释不同?的主要内容,如果未能解决你的问题,请参考以下文章
MySQL 专家:为啥 2 个查询给出不同的“解释”索引使用结果?
有人可以解释为啥以下查询的功能不同吗?从字面上看,两者之间的唯一区别是