为什么Calendar.date(from:DateComponents)会增加时间?

时间:2017-01-25 19:27:31

标签: swift date swift3 nsdate nsdatecomponents

我使用以下代码创建DateComponents的实例:

let dateComponents = DateComponents(
            calendar: .current,
            timeZone: Calendar.current.timeZone,
            era: nil,
            year: nil,
            month: nil,
            day: nil,
            hour: 9,
            minute: 0,
            second: 0,
            nanosecond: 0,
            weekday: 2,
            weekdayOrdinal: nil,
            quarter: nil,
            weekOfMonth: nil,
            weekOfYear: nil,
            yearForWeekOfYear: nil)

然后我打印dateComponents对象并获得以下(预期)输出:

  

calendar:gregorian(current)timeZone:Europe / London(当前)小时:9分钟:0秒:0纳秒:0个工作日:2个是LeMonth:false

紧接着,我打印使用以下代码创建的日期:

print(Calendar.current.date(from: dateComponents)!)

令我非常沮丧和彻底的不快乐,输出如下:

  

0001-01-01 09:0 1:15 +0000

date(from: dateComponents)函数似乎在从dateComponents创建日期之前已经添加了超过一分钟。

感谢您提前提供任何帮助。

1 个答案:

答案 0 :(得分:4)

NSDate对古代约会有一些奇怪的和无证的行为。这种变化似乎发生在1895年左右:

for year in 1890..<1900 {
    // January 1 of each year @ 9AM
    let dateComponents = DateComponents(
        calendar: .current,
        timeZone: Calendar.current.timeZone,
        year: year,
        month: 1,
        day: 1,
        hour: 9)

    if dateComponents.isValidDate {
        print(dateComponents.date!)
    }
}

我的日历是格里高利,时区是EDT(UTC -0500)。这是输出:

1890-01-01 14:17:32 +0000
1891-01-01 14:17:32 +0000
1892-01-01 14:17:32 +0000
1893-01-01 14:17:32 +0000
1894-01-01 14:17:32 +0000 // not correct
1895-01-01 14:00:00 +0000 // correct
1896-01-01 14:00:00 +0000
1897-01-01 14:00:00 +0000
1898-01-01 14:00:00 +0000
1899-01-01 14:00:00 +0000

因此,在1895年之前的几年里,Apple以某种方式增加了17分32秒。您有不同的偏移量,这可能是由于您的区域设置。

我在1895年找不到关于格里高利历的任何历史事件。This question提到英国开始转向格林威治标准时间,格林威治天文台在19世纪90年代开始调整不列颠群岛的日期/时间标准。可能已经解释了这种抵消。也许有人可以深入研究Date / NSDate的源代码并找出答案?

如果您想使用DateComponent存储重复的时间表,请使用nextDate(after:matching:matchingPolicy:)查找下一次出现的时间表:

let dateComponents = DateComponents(calendar: .current, timeZone: .current, hour: 9, weekday: 2)

// 9AM of the next Monday
let nextOccurance = Calendar.current.nextDate(after: Date(), matching: dateComponents, matchingPolicy: .nextTime)!