我正在使用NSDateFormatter来解析iPhone上的RFC 822日期。但是,无法在日期格式中指定可选元素。 RFC 822规范中有几个可选部分,它们打破了日期解析器。如果没有任何效果,我可能必须编写一个自定义解析器来遵守规范。
例如,日期名称在规范中是可选的。所以这两个日期都是有效的:
Tue, 01 Dec 2009 08:48:25 +0000
使用格式EEE, dd MMM yyyy HH:mm:ss z
进行解析
01 Dec 2009 08:48:25 +0000
的解析格式为dd MMM yyyy HH:mm:ss z
这就是我目前使用的:
+ (NSDateFormatter *)rfc822Formatter {
static NSDateFormatter *formatter = nil;
if (formatter == nil) {
formatter = [[NSDateFormatter alloc] init];
NSLocale *enUS = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[formatter setLocale:enUS];
[enUS release];
[formatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss z"];
}
return formatter;
}
+ (NSDate *)dateFromRFC822:(NSString *)date {
NSDateFormatter *formatter = [NSDate rfc822Formatter];
return [formatter dateFromString:date];
}
解析日期如下:
self.entry.published = [NSDate dateFromRFC822:self.currentString];
一种方法是尝试两种格式,并采取任何返回非空值。但是,规范中有两个可选部分(日期名称和秒),可能有4种可能的组合。仍然不是太糟糕,但它有点hacky。
答案 0 :(得分:6)
我使用following method来解析RFC822日期。我相信它最初来自MWFeedParser:
+ (NSDate *)dateFromRFC822String:(NSString *)dateString {
// Create date formatter
static NSDateFormatter *dateFormatter = nil;
if (!dateFormatter) {
NSLocale *en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setLocale:en_US_POSIX];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
[en_US_POSIX release];
}
// Process
NSDate *date = nil;
NSString *RFC822String = [[NSString stringWithString:dateString] uppercaseString];
if ([RFC822String rangeOfString:@","].location != NSNotFound) {
if (!date) { // Sun, 19 May 2002 15:21:36 GMT
[dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm:ss zzz"];
date = [dateFormatter dateFromString:RFC822String];
}
if (!date) { // Sun, 19 May 2002 15:21 GMT
[dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm zzz"];
date = [dateFormatter dateFromString:RFC822String];
}
if (!date) { // Sun, 19 May 2002 15:21:36
[dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm:ss"];
date = [dateFormatter dateFromString:RFC822String];
}
if (!date) { // Sun, 19 May 2002 15:21
[dateFormatter setDateFormat:@"EEE, d MMM yyyy HH:mm"];
date = [dateFormatter dateFromString:RFC822String];
}
} else {
if (!date) { // 19 May 2002 15:21:36 GMT
[dateFormatter setDateFormat:@"d MMM yyyy HH:mm:ss zzz"];
date = [dateFormatter dateFromString:RFC822String];
}
if (!date) { // 19 May 2002 15:21 GMT
[dateFormatter setDateFormat:@"d MMM yyyy HH:mm zzz"];
date = [dateFormatter dateFromString:RFC822String];
}
if (!date) { // 19 May 2002 15:21:36
[dateFormatter setDateFormat:@"d MMM yyyy HH:mm:ss"];
date = [dateFormatter dateFromString:RFC822String];
}
if (!date) { // 19 May 2002 15:21
[dateFormatter setDateFormat:@"d MMM yyyy HH:mm"];
date = [dateFormatter dateFromString:RFC822String];
}
}
if (!date) NSLog(@"Could not parse RFC822 date: \"%@\" Possibly invalid format.", dateString);
return date;
}
答案 1 :(得分:4)
在决定使用哪个格式化程序之前,计算显着字符的数量。例如,你给出的两个有不同数量的逗号和空格。如果没有已知的格式与计数匹配,那么您甚至不知道尝试将其解析为日期。
答案 2 :(得分:1)
我相信RFC 822在日期时间中指定了两个可选组件:星期几和小时后的秒数。
作为一个黑客,有可能是一周中短日的符号:
NSArray *shortWeekSymbols = [NSArray arrayWithObjects:@"Sun,", @"Mon,", @"Tue,", @"Wed,", @"Thu,", @"Fri,", @"Sat,", nil];
[formatter setShortWeekdaySymbols:shortWeekSymbols];
如果您随后将日期格式更改为:EEEdd MMM yyyy HH:mm:ss z
。你可以在没有星期几的情况下解析约会。这似乎也允许在逗号之后留出空格。
为了安全起见,你不应该盲目地设置这样的符号。您应该使用setShortWeekdaySymbols
并迭代它们,最后添加逗号。原因是每个区域设置可能不同,第一天可能不是星期日。
有趣的是,格式EEE, dd MMM yyyy HH:mm:ss z
将解析没有星期几的时间,但逗号必须在那里,例如, 01 Dec 2009 08:48:25 +0000
。因此,你可以做一些史蒂夫所说的事情,然后剥离一天然后传递给格式化程序。格式中没有逗号似乎不允许本周是可选的。奇怪。
不幸的是,这仍然无助于格式化的可选:ss。但它可能允许你有两种格式而不是四种格式。
答案 3 :(得分:0)
如果这对其他人有帮助..这里是基于Simucal's answer的NSDate + RFC822String.swift扩展。
它还缓存了上次使用的日期格式,因为设置dateFormatter.dateFormat非常昂贵。
import Foundation
private let dateFormatter: NSDateFormatter = {
let dateFormatter = NSDateFormatter()
dateFormatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
dateFormatter.timeZone = NSTimeZone(forSecondsFromGMT: 0)
return dateFormatter
}()
private let dateFormatsWithComma = ["EEE, d MMM yyyy HH:mm:ss zzz", "EEE, d MMM yyyy HH:mm zzz", "EEE, d MMM yyyy HH:mm:ss", "EEE, d MMM yyyy HH:mm"]
private let dateFormatsWithoutComma = ["d MMM yyyy HH:mm:ss zzz", "d MMM yyyy HH:mm zzz", "d MMM yyyy HH:mm:ss", "d MMM yyyy HH:mm"]
private var lastUsedDateFormatString: String?
extension NSDate {
class func dateFromRFC822String(RFC822String: String) -> NSDate? {
let RFC822String = RFC822String.uppercaseString
if lastUsedDateFormatString != nil {
if let date = dateFormatter.dateFromString(RFC822String) {
return date
}
}
if RFC822String.containsString(",") {
for dateFormat in dateFormatsWithComma {
dateFormatter.dateFormat = dateFormat
if let date = dateFormatter.dateFromString(RFC822String) {
lastUsedDateFormatString = dateFormat
return date
}
}
} else {
for dateFormat in dateFormatsWithoutComma {
dateFormatter.dateFormat = dateFormat
if let date = dateFormatter.dateFromString(RFC822String) {
lastUsedDateFormatString = dateFormat
return date
}
}
}
return nil
}
}