Вопрос

Я использую NSDateFormatter для анализа даты RFC 822 на iPhone.Однако нет способа указать необязательные элементы в формате даты.В спецификации 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 возможных комбинации.Все еще не так уж плохо, но это немного халтурно.

Это было полезно?

Решение

Подсчитайте количество характерных символов, прежде чем принимать решение о том, какой форматировщик использовать.Например, те два, которые вы приводите, содержат разное количество запятых и пробелов.Если ни один известный формат не соответствует подсчетам, то вам, как известно, даже не стоит пытаться разобрать его как дату.

Другие советы

Я использовал следующий метод для анализа дат 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;

}

Я полагаю, что 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 в формате.Но это может позволить вам иметь два формата, а не четыре.

На случай, если это будет полезно кому-то еще..вот расширение 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
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top