1895 年 1 月 1 日字符串错误的 DateFormatter

DateFormatter from String bug for January 1, 1895

提问人:Jim Sutcliffe 提问时间:2/26/2022 更新时间:3/6/2022 访问量:115

问:

我在 DateFormatter 的 .date(from: String) 函数中发现了最奇怪的错误,因为它似乎不喜欢 1895-01-01。上班前后的日期,但该特定日期为零。

我可以取 1894-12-31 并添加一天来表明底层 NSDate 很好——只是似乎是 DateFormatter 转换。

下面是要演示的 playground 代码。

import Foundation

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"

let fmt = DateFormatter()
fmt.dateFormat = "yyyy-MM-dd"
let date1 = fmt.date(from: "1894-12-31")
let date2 = fmt.date(from: "1895-01-01")
let date3 = fmt.date(from: "1895-01-02")
let calcDate2 = date1?.addingTimeInterval(86400)

print("Date 1: \(date1)")
print("Date 2: \(date2)")
print("Date 3: \(date3)")
print("\nCalculated Date 2: \(calcDate2)")

输出为:

Date 1: Optional(1894-12-31 05:17:32 +0000)
Date 2: nil
Date 3: Optional(1895-01-02 05:00:00 +0000)

Calculated Date 2: Optional(1895-01-01 05:17:32 +0000)

我还发现了一个关于奇怪行为的先前问题,时间是在 1895 年左右添加,所以也许这在某种程度上是相关的?

这是一个错误吗?知道在JSON解码时如何解决这个问题,因为我无法知道我的数据将包含哪些日期?到目前为止,我只是在代码中将其用作字符串,但这不会持续很长时间。

swift 字符串 null 日期格式化程序

评论

0赞 vikingosegundo 2/26/2022
几年前有一个 WWDC 视频,演示者显示在某些时区,DST 调整等事情在 00:00 进行。他的一般建议是,在其他时间进行这样的计算,比如中午
0赞 vikingosegundo 2/26/2022
现在 1895 年没有 DST,但还有其他一些改动?
0赞 vikingosegundo 2/26/2022
你位于哪个TZ?
0赞 vikingosegundo 2/26/2022
大约在那个时候,TZ由铁路公司引入美国。可能相关。
0赞 vikingosegundo 2/26/2022
投票决定重新开放:另一个问题是语言问题,这里不应该是这样。

答:

0赞 Jim Sutcliffe 3/6/2022 #1

好的,答案是,由于铁路的使用需要更好的时间,因此许多州和省在1895年采用了弗莱明几年前提出的时区。

这建立了太平洋、山区、中部和东部(我所在的地方)时区。因此,需要调整到东部 00:17:32。因此,时钟从新年的 23:59:59 变成了 00:17:32。

这可以通过以下代码显示:

import Foundation

let fmt = DateFormatter()
fmt.dateFormat = "yyyy-MM-dd HH:mm:ss"

let date1 = fmt.date(from: "1894-12-31 23:59:59")
let date2 = fmt.date(from: "1895-01-01 00:00:00")
let date3 = fmt.date(from: "1895-01-01 00:17:31")
let date4 = fmt.date(from: "1895-01-01 00:17:32")

print("Date 1 (1 sec to midnight): \(date1)")
print("Date 2 (midnight): \(date2)"). // invalid
print("Date 3 (17:31 past midnight): \(date3)"). // invalid
print("Date 4 (17:32 past midnight: \(date4)")

let calc1 = date1?.addingTimeInterval(1)
print("Date 1 + 1 second (midnight): \(calc1)")

输出为(对于 EST):

Date 1 (1 sec to midnight): Optional(1895-01-01 05:17:31 +0000)
Date 2 (midnight): nil
Date 3 (17:31 past midnight): nil
Date 4 (17:32 past midnight: Optional(1895-01-01 05:17:32 +0000)
Date 1 + 1 second (midnight): Optional(1895-01-01 05:17:32 +0000)

感谢所有帮助。

实际使用的解决方案是将“Z”时区添加到字符串格式的末尾,同样将“Z”附加到我正在调用的 API 的数据中。这迫使一切都到了格林威治标准时间,而格林威治标准时间不会受到这个问题的影响。

感谢大家的帮助

评论

0赞 Sulthan 3/6/2022
您也可以在格式化程序上设置特定的时区(例如)。另请注意,这将为您做到这一点。TimeZone(secondsFromGMT: 0)ISO8601DateFormatter
0赞 Jim Sutcliffe 3/6/2022
谢谢 Sulthan - 这似乎更干净,所以会尝试一下。