17

在一般情况下,使用 NSDateFormatter 解析 rfc3339 日期似乎是不可能的。我错了吗?[2年后编辑:现在有办法!见下文和脚注。]

一个不太可塑的网络服务正在给我提供日期,例如:

2009-12-31T00:00:00-06:00

他们使用的 jaxb 库的默认输出符合 Rfc3339。注意冒号,当偏移量不是文字“z”时,rfc3339需要它:

time-numoffset  = ("+" / "-") time-hour ":" time-minute
time-offset     = "Z" / time-numoffset

我想将这些解析为 NSDates。

NSDateFormatter 需要Unicode指定的语法模式,它为“PDT”、“-0800”、“GMT-08:00”等时区提供日期字段符号,但不提供“-08:00”。

谷歌搜索和其他类似的 SO 问题,只产生日期格式,如

[myDateParser setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"];
/* or: */ [myDateParser setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];

后者需要文字“Z”,而前者坚持不存在冒号或存在“GMT”。但是,它们似乎在 ios 4.x 之前工作(可能通过完全丢弃 tz 偏移量;我的数据不清楚。)

在这一点上,我的选择很抱歉:

  • 发现一些未记录的格式说明符,或者将 NSDateFormatter 放入的一些奇怪模式,它将接受流浪冒号:longshot,可能不存在。[脚注]
  • 说服我的服务发布者将所有日期转换为祖鲁时间并指定“Z”:政治上具有挑战性。
  • 编写我自己的 NSFormatter 子类或研究好旧的strptime_l:工作。:)
  • 对我的输入进行字符串操作并去掉最后一个冒号:易碎且丑陋,但可能是阻力最小的路径。

我是否准确地理解了情况,当前的 NSDateFormatter 严格遵循 unicode 没有扩展;并且 unicode 格式不足以完全描述 rfc3339 日期?

[FOOTNOTE]三年后我回来补充一个小附录:从 iOS6/OSX10.8 开始,Unicode 和 Apple 已将此功能添加到格式字符串中。将撰写本文时的最新版本与其直接前身进行比较,并注意添加了 5 个“Z”,这会产生类似于“-08:00”的区域格式。因此,如果您可以摆脱对 5.x/10.7 的支持,那么就有一种新的正确方法可以做到这一点。我将保留以前的答案,因为当需要向后兼容时,它仍然是最好的方法。

4

3 回答 3

11

– getObjectValue:forString:range:error: 实际上可以正确解析 RFC3339 日期。我不知道为什么 - dateWithString: 不能:

// RFC3339 date formatting
NSString *dateString = @"2012-04-11T18:34:19+00:00";
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";

NSDate *date;
NSError *error;
[formatter getObjectValue:&date forString:dateString range:nil error:&error];
于 2012-04-12T17:58:44.750 回答
8

Date string parsing in Cocoa can be a pain, especially if you have to deal with dates generated by .NET based web services.

I'd suggest looking at the NSDate+InternetDateTime category that Michael Waterfall has on NSDate as part of his MWFeedParser project on github. It's worked well for me parsing exactly the format of date you describe.

https://github.com/mwaterfall/MWFeedParser/

于 2010-12-02T02:52:56.347 回答
5

Apple 文档中没有记录字符串格式字符。取而代之的是,在某些文档的深处隐藏了一个指向 Unicode 标准的链接,网址为

http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns

使用该链接上的信息非常简单:

- (NSDate*)dateFromRFC3339String:(NSString*)aString
{
    static NSDateFormatter* sRFC3339DateFormatter = nil;
    static NSDateFormatter* sRFC3339DateFormatterSubSeconds = nil;
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];

        sRFC3339DateFormatter = [[NSDateFormatter alloc] init];
        [sRFC3339DateFormatter setLocale:enUSPOSIXLocale];
        [sRFC3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssXXXXX"];
        [sRFC3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];

        sRFC3339DateFormatterSubSeconds = [[NSDateFormatter alloc] init];
        [sRFC3339DateFormatterSubSeconds setLocale:enUSPOSIXLocale];
        [sRFC3339DateFormatterSubSeconds setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSSSSXXXXX"];
        [sRFC3339DateFormatterSubSeconds setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
    });

    NSDate* date = [sRFC3339DateFormatter dateFromString:aString];
    if (date == nil)
        date = [sRFC3339DateFormatterSubSeconds dateFromString:aString];

    return date;
}
于 2014-04-09T16:35:27.080 回答