【问题标题】:DateFormatter returns nil date for some users regardless of locale/isDaylightSavingTime/timezone无论语言环境/isDaylightSavingTime/时区如何,DateFormatter 都会为某些用户返回 nil 日期
【发布时间】:2019-09-20 16:08:24
【问题描述】:

我们将 Disqus 用于我们的 cmets 功能。它的 cmets 时间戳采用 ISO8601 日期格式,例如"2019-12-11T01:45:23"。我们尝试使用 DateFormatter 解析该字符串,设置如下:

let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
return dateFormatter

它适用于大多数用户。但是,我们会收到格式化程序返回 nil 的少量用户的报告。我们对原因的初步假设如下。

  • 日期格式“yyyy-MM-dd'T'HH:mm:ss”错误
  • 语言环境
  • 时区
  • 夏令时理论上不存在一些时间
  • 日历
  • 或者别的什么...

它们都是我们用来设置 DateFormatter 的参数。我们尝试了许多组合,包括我们从用户报告中获得的组合。我们尝试了与用户报告中相同的日期、区域设置、时区、日历和时间本身。

  • 语言环境:en_GB,时区:Europe/London,日历:gregorian,isDaylightSavingTime:1

  • 语言环境:en_TR,时区:Etc/GMT-3,日历:gregorian,isDaylightSavingTime:0

  • 语言环境:es_MX,时区:America/Mexico_City,日历:gregorian,isDaylightSavingTime:1

  • 语言环境:en_ID,时区:Asia/Jakarta,日历:gregorian,isDaylightSavingTime:0

但我们无法复制。

此外,我们还进行了另一项测试,其中包含全年分布的大量日期。并对每个用户进行隐藏解析测试。似乎在返回 nil 日期的设备上,它在每个日期都返回 nil。日期字符串列表如下所示...

    [
      "2019-01-11T01:45:23",
      "2019-02-11T01:45:23",
      "2019-03-11T01:45:23",
      "2019-04-10T01:45:23",
      "2019-04-11T01:45:23",
      "2019-04-12T01:45:23",
      "2019-05-11T01:45:23",
      "2019-06-11T01:45:23",
      "2019-07-11T01:45:23",
      "2019-08-11T01:45:23",
      "2019-09-11T01:45:23",
      "2019-10-11T01:45:23",
      "2019-11-11T01:45:23",
      "2019-12-11T01:45:23",
      ])

我们后来发现还有另一个日期格式化程序,叫做ISO8601DateFormatter。似乎更适合这种解析。以下是我们的设置方式。

let dateFormatter = ISO8601DateFormatter()
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
dateFormatter.formatOptions = [.withFullDate, .withTime, .withDashSeparatorInDate, .withColonSeparatorInTime]
return dateFormatter

有了这个ISO8601DateFormatter,问题就解决了。

但我仍然想知道什么会导致DateFormatter 在某些设备上失败?除了我不知道的语言环境/isDaylightSavingTime/时区之外,还有其他因素吗?

【问题讨论】:

  • 你有什么解决办法吗?不管怎样,我也得到了零。

标签: ios nsdateformatter


【解决方案1】:

是 12 小时制还是 24 小时制的用户设置?

iOS 可以更改日期格式化程序的格式字符串以匹配用户的设置。语言环境en_US_POSIXrecommended for fixed formats,以防止由于用户设置而导致格式更改。

【讨论】:

    【解决方案2】:

    请使用 ISO8601 日期格式和时区

      "2019-12-11T01:45:23.000Z"
    

    格式:

    "XXXX-XX-XX" = 年、月、日、 "T" = 分隔符 "XX:XX:XX.XXX" = 时、分、秒、毫秒 "Z" = 零偏移时区指示符,也称为 UTC、GMT、祖鲁时间

     let dateFormatter = DateFormatter()
     dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
     dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
     return dateFormatter
    

    【讨论】:

    • 它来自第三方服务 Disqus,所以我无法控制传入的日期字符串格式。
    【解决方案3】:

    对于仍然面临此问题的任何人,对我有用的是设置 dateFormatter.isLenient = true,如下所述:DateFormatter returning nil for a valid Date string

    【讨论】:

      猜你喜欢
      • 2010-11-25
      • 1970-01-01
      • 2018-09-16
      • 1970-01-01
      • 1970-01-01
      • 2021-05-05
      • 2019-10-09
      • 2018-02-17
      • 2011-02-11
      相关资源
      最近更新 更多