在一般情况下,使用NSDateFormatter解析rfc3339日期似乎是不可能的。我错了吗? [编辑2年后:现在有办法!见下文和脚注。]
一个不特别具有可塑性的网络服务正在为我提供日期:
2009-12-31T00:00:00-06:00
符合Rfc3339,他们正在使用的jaxb库的默认输出。注意冒号,当偏移量不是文字“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偏移量;我的数据不清楚。)
此时我的选择很遗憾:
strptime_l
:work。 :)我是否准确理解了这种情况,当前的NSDateFormatter严格遵循unicode而没有扩展;并且unicode格式不足以完全描述rfc3339的日期?
[脚注] 三年后我回到这个小小的附录:Unicode和Apple已经将这个功能添加到格式字符串中,从iOS6 / OSX10.8开始。将The latest revision as of this writing与its immediate predecessor进行比较,并注意添加5“Z”,这会产生类似“-08:00”的区域格式。因此,如果您能够放弃对5.x / 10.7的弃用支持,那么有一种新的正确方法可以做到这一点。我将离开之前的答案,因为当需要向后兼容时,它仍然是最好的方法。
答案 0 :(得分: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];
答案 1 :(得分:8)
Cocoa中的日期字符串解析可能很麻烦,特别是如果您必须处理基于.NET的Web服务生成的日期。
我建议查看Michael Waterfall在NSDate上的NSDate + InternetDateTime类别,作为他在github上的MWFeedParser项目的一部分。它很适合我解析你描述的日期格式。
答案 2 :(得分: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;
}