在iOS 10.0中,80年代的第一个日期未能解析

问题描述:

我发现DateFormatter date(from:)方法无法解析几个特定日期。方法在1981 - 1984年的第一个月返回 nil 。这是基金会的错误吗?我们可以做些什么来解析这些日期?

I found that DateFormatter date(from:) method can't parse a couple of specific dates. Method returns nil for the 1st april of 1981-1984 years. Is it a bug of Foundation? What can we do to perform parsing of such dates?

Xcode 8.0,iOS SDK 10.0。以下是一个简短操场示例的屏幕截图:

Xcode 8.0, iOS SDK 10.0. Here is a screenshot of a short playground example:

如果夏令时正好在
午夜开始,就会出现此问题,就像1981 - 1984年莫斯科的情况一样(例如,请参阅俄罗斯莫斯科时钟变化(莫斯科)

This problem occurs if daylight saving time starts exactly on midnight, as it was the case in Moscow in the years 1981–1984 (see for example Clock Changes in Moscow, Russia (Moskva)).

  • Why does NSDateFormatter return nil date for these 4 time zones? and
  • Why NSDateFormatter is returning null for a 19/10/2014 in a Brazilian time zone?

例如,在午夜时分1984年4月1日,时钟向前调整了一小时,这意味着在该时区内不存在1984-04-01 00:00
的日期:

For example, at midnight of April 1st 1984, the clocks were adjusted one hour forward, which means that the date "1984-04-01 00:00" does not exist in that timezone:

let dFmt = DateFormatter()
dFmt.dateFormat = "yyyy-MM-dd"
dFmt.timeZone = TimeZone(identifier: "Europe/Moscow")
print(dFmt.date(from: "1984-04-01")) // nil

作为解决方案,您可以告诉日期格式化程序宽松:

As a solution, you can tell the date formatter to be "lenient":

dFmt.isLenient = true

然后它将返回当天的第一个有效日期:

and then it will return the first valid date on that day:

dFmt.isLenient = true
if let date = dFmt.date(from: "1984-04-01") {
    dFmt.dateFormat = "yyyy-MM-dd HH:mm:ss"
    print(dFmt.string(from: date)) 
}
// 1984-04-01 01:00:00

一个不同的解决方案
由rob mayoff提供,这是为了使日期格式化程序使用 noon 而不是午夜作为
默认日期。以下是从Objective-C到Swift的rob代码的翻译:

A different solution was given by rob mayoff, which is to make the date formatter use noon instead of midnight as the default date. Here is a translation of rob's code from Objective-C to Swift:

let noon = DateComponents(calendar: dFmt.calendar, timeZone: dFmt.timeZone,
               year: 2001, month: 1, day: 1, hour: 12, minute: 0, second: 0)
dFmt.defaultDate = noon.date
if let date = dFmt.date(from: "1984-04-01") {
    dFmt.dateFormat = "yyyy-MM-dd HH:mm:ss"
    print(dFmt.string(from: date)) 
}
// 1984-04-01 12:00:00