2009-12-05 86 views
15

我正在使用NSDateFormatter来解析iPhone上的RFC 822日期。但是,无法在日期格式中指定可选元素。 RFC 822规范中有几个可选部分正在打破日期解析器。如果什么都没有解决,我可能不得不编写一个自定义解析器来遵守规范。使用NSDateFormatter解析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]; 

一种方法是尝试两种形式ats,并取任何非空值的返回值。但是,规范中有两个可选部分(日期名称和秒数),并且会有4种可能的组合。还不错,但有点不好意思。

回答

4

在决定使用哪个格式化程序之前,计算显着字符的数量。例如,你给的两个有不同数量的逗号和空格。如果没有已知的格式与计数相匹配,那么您甚至不会将其解析为日期。

+0

这对我来说似乎是最实际的解决方案,因为月份和星期的名称是固定长度,所有其他值都是固定长度的数字。比尝试格式要便宜得多,直到一个作品! – 2009-12-05 23:53:10

+0

实施基本解决方案。不是很满意,但它是迄今为止最好的一个:)逗号表示星期几的存在,两个冒号有助于识别秒数。如果日期中包含对它所遵循的规范的引用,那就太好了,因为日期分析在许多格式的许多语言中都非常麻烦。 – Anurag 2009-12-06 12:29:25

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格式。但它可能会让你有两种格式,而不是四种。

+0

感谢您的提示。我认为RFC 822没有提到本地化,只使用英文格式。追加逗号而不是硬编码值仍然是个好主意。但是由于我仍然需要检查两种组合,因此事先检查字符而不是尝试两次可能是个好主意。 – Anurag 2009-12-06 12:23:16

5

我已使用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; 

} 
+0

更改日期格式字符串非常昂贵,您可能需要为每个日期格式化程序创建一个日期格式程序,并在应用程序的整个生命周期内保留它。 – SomeGuy 2014-12-03 23:57:05

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 
    } 
} 
相关问题