【问题标题】:iOS app occasionally sends an invalidly-formatted ISO8601 date to REST APIiOS 应用偶尔会向 REST API 发送格式无效的 ISO8601 日期
【发布时间】:2015-09-24 12:23:51
【问题描述】:

一天几次,我们的 PHP REST API 记录一个错误,该错误是由格式无效的 ISO8601 日期引起的,该日期来自我们的 iOS 应用程序发送的 GET 请求。有趣的是,大多数电话都很好(例如 2015-07-07T00:00:00+10:00),但我们经常会收到一个奇怪的电话(例如 2015-07-07T12:00:00上午+10:00)。

我认为导致此问题的代码如下:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];

NSString *iso8601StringStart = [dateFormatter stringFromDate:self.searchStartTime];

在任何情况下NSDateFormatter 可以以某种方式(错误地)从“yyyy-MM-dd'T'HH:mm:ssZZZZZ”中获取 am/pm,而这显然是意外行为?是否有某些类型的 NSDate 会导致不同的行为?我难住了。给定的日期始终是通过dateFromComponents 创建的。

【问题讨论】:

  • 试试这个“yyyy-MM-dd'T'HH:mm:ss a ZZZZZ”来显示上午/下午@Sadurnias
  • @DharmeshDhorajiya 我认为我不够清楚 - 我不是想显示 am/pm,我想弄清楚它如何在没有 ' 的情况下显示 am/pm a' 在格式字符串中。我已经编辑了这个问题以澄清一点。

标签: ios objective-c nsdateformatter


【解决方案1】:

我不相信该格式字符串可以使用您显示的 am/pm 注释生成日期。如果我是你,我的第一门课程是仔细检查这些日期是否真的是由这些代码行生成的。

但是,如果您确定这种情况正在发生,我能看到的唯一问题是您没有明确设置日期格式化程序对象的区域设置和日历,这可能是不正确的。日期格式语法由 unicode 联盟定义,governing spec 确实在第 4.5 节中说“如果未列出区域设置,则 dayPeriods 回退到 AM/PM”。我不理解整个文档,但它表明非常明确是最安全的路径。

如果您的唯一要求是 ISO8601,那么您可以在 UTC 时区使用 RFC3339,因为这是 ISO8601 的配置文件。这将为该格式创建一个正确的格式化程序:

let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z"
formatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
formatter.calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601)!
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")

【讨论】:

  • 谢谢!这正是我开始所需要的。经过更多研究,将语言环境设置为 en_US_POSIX 为我修复了它:)
【解决方案2】:

我的最终解决方案(藻类的回答促使我朝这个方向努力):

[dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]];

Unicode spec 很有帮助(感谢 algal),this Apple Technical QA 也很有帮助,它建议将 en_US_POSIX 作为一个特定的解决方案。

“在 iOS 上,用户可以覆盖默认的 AM/PM 与 24 小时时间设置(通过设置 > 常规 > 日期和时间 > 24 小时时间),这会导致 NSDateFormatter 重写您设置的格式字符串,这可能会导致您的时间解析失败。”

最有帮助的是,我找到了this explanation of the behaviour by huyz,虽然有点旧:

当 iPhone 用户在“美国”和“法国”之间更改他们的地区格式时,用户的“24 小时制”设置会自动切换到该地区最流行的模式。在法国,这会将 24 小时制设置为“开”,而在美国,这会将其设置为“关”。然后用户可以手动覆盖该设置,这就是麻烦开始的地方。

问题来自 NSDateFormatter 以某种方式“卡住”在用户手动选择的 12 或 24 小时时间模式。因此,如果法国用户手动选择 12 小时模式,并且应用程序请求 NSDateFormatter 以 24 小时格式“HHmm”输出时间,它实际上会以 12 小时格式接收时间,例如“01:00 PM”,好像应用程序改为请求“hhmm aa”。如果美国用户手动选择 24 小时模式,则会发生相反的情况:以 12 小时格式“hhmm aa”输出时间实际上会让您获得 24 小时格式的时间,例如“17:00”。

【讨论】:

  • 我认为该博客上的解释可能无关紧要,因为它涉及 iOS 3 beta SDK 中的错误,该错误可能已在五年内得到修复。真正的问题是,如果您不指定区域设置,那么它会使用用户的默认设置,并且生成的区域设置可以覆盖格式字符串。哎呀!不知道。
猜你喜欢
  • 2019-04-19
  • 2010-11-15
  • 1970-01-01
  • 1970-01-01
  • 2017-10-24
  • 2015-12-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多