对于观察巴西利亚夏令时的城市,iOS 11.2.6 DateFormatter.date返回nil

Ada*_*hns 14 nsdateformatter ios

我从头开始创建了一个新的Single View App项目,并且只向ViewController的viewDidLoad方法添加了以下代码:

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/yy"
if let date = dateFormatter.date(from: "11/20") {
    print("got the date: \(date)")
} else {
    print("failed getting the date")
}
Run Code Online (Sandbox Code Playgroud)

除了观察巴西夏令时(BRST)的城市,上述代码在世界各地都有效.

我通过在设置>常规>日期和时间中更改设备上的时区来测试此处列出的所有38个时区中的城市.我还确认BRST城市在iOS 11.0设备上运行良好,但不是 iOS 11.2.6.

另请注意,即使在iOS 11.2.6上,我尝试过的几乎所有其他月/年组合也能正常工作.只有 "11/20"和"11/26"似乎失败了.

为什么在iOS 11.2.6上观察BRST的城市,此代码返回nil?

Ada*_*hns 33

垫片的答案很明显,但我想提供一些澄清细节.

2017年12月15日,巴西总统米歇尔·特梅尔签署了一项法令,将夏令时(DST)的开始时间改为11月的第一个星期日,从2018年开始.看起来iOS 11.2.6是iOS的第一个版本.这个变化就是为什么在以前的iOS版本中没有看到这个问题的原因.

随着时间的改变而移动到这个问题第一个星期日十一月是,11月的第一个周日可以最终被(和在2020年和2026的情况下)11月1日.为什么这会出现问题?好吧,恰恰相反,当DST开始时,巴西也在午夜时分(从晚上11:59到凌晨1点)将时钟"弹回" .

为什么11月1日午夜的日期出现问题?好吧,当我们要求iOS根据用户输入的月份/年份给我们一个Date对象时(例如11/20),Date对象默认为午夜的第一天.这是有问题的,因为在DST于11月1日午夜在巴西开始的年份,那个时间在技术上从未存在过.因此,当我们要求iOS为11/20提供Date对象时,iOS会尝试返回11/01/2020 @ 00:00,但由于该时间从未存在,因此返回nil.

所以这个问题在技术上可以发生在观察夏令时的任何时区,这个时区可以在午夜的一个月的第一天开始.经过一些国家并检查他们的DST规则后,我发现巴西只允许DST在午夜1点1开始.

为了解决这个问题,我有效地做了以下事情:

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MM/yy"
let dateFormatterWithTime = DateFormatter()
dateFormatterWithTime.dateFormat = "MM/yy HH:mm"
if let date = dateFormatter.date(from: "11/20") ??
    dateFormatterWithTime.date(from: "11/20 03:00") {
    print("got the date: \(date)")
} else {
    print("failed getting the date")
}
Run Code Online (Sandbox Code Playgroud)

03:00 是一个未来的任意时间,应该安全地考虑午夜的DST变化.


shi*_*him 13

它不适用于那个时区(圣保罗)的原因是因为该时区特有的考虑因素,即夏令时.巴西的夏令时从11月第一个星期日开始,恰好是2020年的11月1日.

它默认的时间不存在,因此返回nil.

您可以通过更改格式化程序来包含时间并查看日期格式化程序何时开始返回nil.

之前遇到过类似的困惑; 日期和时区很棘手.

如果您使用日期格式化程序向用户显示日期,则通常不应覆盖其设备设置,并且您可能希望避免使用固定日期格式,并且应该知道日期格式化程序返回nil的可能性价值(救援的Swift选项).但是,如果您将其用于内部日期(例如API),则应考虑在日期格式化程序上设置显式语言环境,以便不会发生这类事情,例如:

dateFormatter.locale = Locale(identifier: "en_US_POSIX")
Run Code Online (Sandbox Code Playgroud)