为啥不同时区对时间的解释不同?

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_YorkAmerica/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

【讨论】:

以上是关于为啥不同时区对时间的解释不同?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Spark 以不同的方式解释这两个查询?

MySQL 专家:为啥 2 个查询给出不同的“解释”索引使用结果?

有人可以解释为啥以下查询的功能不同吗?从字面上看,两者之间的唯一区别是

为啥相同的查询在从 MySQL 服务器上的解释和执行如此不同?

不同时区转换时间戳

为啥 datetime 为同一时区提供不同的时区格式?