为什么时间在不同的时区有不同的解释?

Why are times being interpreted differently in different time zones?

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 下午

CHI时间:2017-08-1300:10:00+00008:10下午

GMT时间:2017-08-1305:10:00+00001:10AM


当我的系统设置为

时输出 CDT:

纽约时间:2017-08-13 01:10:00 +0000 8:10 下午

CHI时间:2017-08-1300:10:00+00007:10下午

GMT时间:2017-08-1305:10:00+000012:10AM


无论我在哪个时区,这些时间不应该保持不变吗?我没有使用与 TimeZone.current 相关的任何内容。

注意:我知道使用 TimeZone.secondsFromGMT: 是更好的做法,但是使用缩写参数可以更容易地阅读这个问题中发生的事情。

考虑这段代码:

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")

运行 在美国东部时间:输出是:

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

这是我在 playground 上的代码版本。

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 与应用的时区一起使用。我的游乐场设置为默认的美国区域设置,但我可以更改任何日期格式化程序的区域设置以不同方式显示日期和时间。

您不需要将时间间隔添加到您拥有的日期,您只需要格式化它的输出,这就是 DateFormatter 的用途。