代码之家  ›  专栏  ›  技术社区  ›  AaronBaker

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

  •  3
  • AaronBaker  · 技术社区  · 8 年前

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

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

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

    Strange date results

    怎么可能 newDate 上午7:00和11:56同时出现吗?

    1 回复  |  直到 8 年前
        1
  •  5
  •   rob mayoff    8 年前

    您没有指定时区(通过设置 timeZone 任何一方的属性 components calendar ). 所以系统使用你的本地时区来转换 组件 去约会。

    游乐场系统使用您的本地时区转换 newDate 1月1日上午7:00发送至字符串。(游乐场系统有特殊案例代码用于显示 Date 物体。特例代码使用您的本地时区。)

    这个 print 函数使用UTC时区转换 新建日期 到字符串0001-01-01 11:56:02+0000。(The 打印 函数使用 CustomStringConvertible 协议 日期 CustomStringConvertible 实施使用UTC时区。)

    我推断您的本地时区是美国/东部时间,也称为 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
    

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

    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
    

    中午之前,与UTC时间的差值为4:56:02。

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

    如果我们看看美国/纽约的定义 the tz Time Zone Database ,我们发现:

    # From Paul Eggert (2014-09-06):
    # Monthly Notices of the Royal Astronomical Society 44, 4 (1884-02-08), 208
    # says that New York City Hall time was 3 minutes 58.4 seconds fast of
    # Eastern time (i.e., -4:56:01.6) just before the 1883 switch.  Round to the
    # nearest second.
    

    再往下一点:

    Zone America/New_York   -4:56:02 -  LMT 1883 Nov 18 12:03:58
    

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