Swift - 打印时组件的日期不正确。日期有2个值?

时间:2017-12-07 03:00:10

标签: swift nscalendar nsdatecomponents

我正试图在日期中存储一天的时间:

let calendar = NSCalendar.init(identifier: .gregorian)
let components = NSDateComponents()
components.hour = 7
components.minute = 0

var newDate = calendar?.date(from: components as DateComponents)!

print(newDate!)

然而,当我尝试打印或以其他方式使用该值时,这会产生一些奇怪的结果。这是结果的Swift游乐场:

Strange date results

newDate如何同时在上午7:00到上午11:56?

1 个答案:

答案 0 :(得分:2)

您没有指定时区(通过设置timeZonecomponents的{​​{1}}属性。因此,系统会使用您当地的时区将calendar转换为日期。

游乐场系统使用您当地的时区将components转换为字符串“Jan 1,1中午7:00”。 (游乐场系统具有用于显示newDate个对象的特殊情况代码。特殊情况代码使用您的本地时区。)

Date函数使用UTC时区将print转换为字符串“0001-01-01 11:56:02 +0000”。 (newDate函数使用print协议。CustomStringConvertible的{​​{1}}实现使用UTC时区。)

我推断您的当地时区是美国/东部时间,也称为Date

CustomStringConvertible

那么为什么UTC中奇怪的分钟和秒? Because at noon on November 18, 1883, the US and Canada railway companies began using a new, standard time system,这是我们今天仍然使用的时间系统。观察:

America/New_York

在中午之前,与UTC时间的差异是4:56:02。

在标准铁路时间出现之前,我们通常根据当地明显的正午时间定义当地时间(太阳在天空中最高的时刻,阴影正好指向北方或南方,或者如果太阳直接在上方,则完全消失)。

如果我们在the tz Time Zone Database中查看America / New_York的定义,我们会发现:

import Foundation

var calendar = Calendar(identifier: .gregorian)
let components = NSDateComponents()
components.hour = 7
components.minute = 0

for timeZoneIdentifier in TimeZone.knownTimeZoneIdentifiers {
    calendar.timeZone = TimeZone(identifier: timeZoneIdentifier)!
    let date = calendar.date(from: components as DateComponents)!
    let dateString = "\(date)"
    if dateString == "0001-01-01 11:56:02 +0000" {
        print("\(timeZoneIdentifier) \(date)")
    }
}
// Only one line of output: America/New_York 0001-01-01 11:56:02 +0000

再向下一点:

import Foundation

let formatter = ISO8601DateFormatter()

var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(identifier: "America/New_York")!
let components = NSDateComponents()

components.year = 1883
components.month = 11
components.day = 18

components.hour = 11
print(formatter.string(from: calendar.date(from: components as DateComponents)!))
// prints 1883-11-18T15:56:02Z

components.hour = 12
print(formatter.string(from: calendar.date(from: components as DateComponents)!))
// prints 1883-11-18T17:00:00Z

这解释了我们在1883年11月18日中午之前看到的差异。