在 iOS 4.x 和 MacOS X 10.6 中使用 NSDateFormatter 解析 rfc3339 日期:不可能?

发布于 2024-10-05 07:33:35 字数 1689 浏览 3 评论 0原文

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

一个不是特别可延展的 Web 服务正在向我提供日期,例如:

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

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

time-numoffset = ("+" / "-") 时间-小时 ":" 时间-分钟
时间偏移量=“Z”/时间偏移量

我想将它们解析为 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 进入,它将接受杂散的冒号:长镜头,可能不存在。 [脚注]
  • 说服我的服务发布者将所有日期转换为祖鲁时间并指定“Z”:具有政治挑战性。
  • 编写我自己的 NSFormatter 子类或研究好的旧 strptime_l:工作。 :)
  • 字符串操作我的输入并去掉最后一个冒号:脆弱且丑陋,但可能是阻力最小的路径。

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

[脚注]三年后,我再次回顾这一点,补充一个小补充:自 iOS6/OSX10.8 起,Unicode 和 Apple 已将此功能添加到格式字符串中。将截至撰写本文时的最新版本其直接前身,并注意添加了 5 个“Z”,这会产生区域格式如“-08:00”。因此,如果您可以放弃对 5.x/10.7 的支持,那么有一种新的正确方法可以做到这一点。我将保留之前的答案,因为当需要向后兼容性时,它仍然是最佳方法。

Parsing a rfc3339 date with NSDateFormatter appears to be impossible, in the general case. Am I wrong? [Edit 2 years later: there is now a way! See below and footnote.]

A not-especially-malleable web service is feeding me dates like:

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

Rfc3339 compliant, default output of the jaxb library they're using. Note the colon, which rfc3339 requires when the offset isn't a literal "z":

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

I want to parse these into NSDates.

NSDateFormatter wants patterns in the syntax specified by Unicode, which offers date field symbols for timezones like "PDT", "-0800", "GMT-08:00" but not "-08:00".

Googling, and other similar SO questions, produces only date formats like

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

The latter of which requires a literal "Z", and the former insists either the absence of a colon or presence of a "GMT". However, they appeared to work before ios 4.x (possibly by discarding the tz offset completely; my data aren't clear.)

My options at this point are a sorry lot:

  • discover some undocumented format specifier, or some strange mode to put NSDateFormatter into, that will accept the stray colon: longshot, likely nonexistent. [footnote]
  • persuade my service publisher to turn all dates into zulu time and specify 'Z': politically challenging.
  • write my own NSFormatter subclass or research good old strptime_l: work. :)
  • string-manipulate my input and strip the last colon: brittle and ugly, but the likely path of least resistance.

Have I understood the situation accurately, that current NSDateFormatter follows unicode strictly without extensions; and the unicode formats are insufficient to fully describe an rfc3339 date?

[FOOTNOTE] I come back to this three years later to tack on a small addendum: Unicode and Apple have added this feature to the format strings, as of iOS6/OSX10.8. Compare The latest revision as of this writing with its immediate predecessor, and note the addition of 5 "Z"s, which yields a zone format like "-08:00". So if you can get away with ditching support for 5.x/10.7, there's a new right way to do it. I'll leave the previous answer stand, as it's still the best approach when backward compatibility is required.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

美胚控场 2024-10-12 07:33:35

– 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];

– getObjectValue:forString:range:error: can actually parse RFC3339 dates correctly. I have no idea why - dateWithString: cannot:

// 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];
命硬 2024-10-12 07:33:35

Cocoa 中的日期字符串解析可能很痛苦,尤其是当您必须处理基于 .NET 的 Web 服务生成的日期时。

我建议查看 Michael Waterfall 在 NSDate 上的 NSDate+InternetDateTime 类别,作为他在 github 上的 MWFeedParser 项目的一部分。它对我来说非常有效,可以准确解析您描述的日期格式。

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

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/

空城仅有旧梦在 2024-10-12 07:33:35

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;
}

The string format characters are documented nowhere in the Apple documentation. Instead there is a link hidden deep in some document pointing to the Unicode standard at

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

Using the information at that link it's quite simple:

- (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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文