Pergunta

Eu estou usando um NSDateFormatter para analisar a 822 data RFC no iPhone. No entanto, não há nenhuma maneira de especificar elementos opcionais no formato de data. Há um par de peças opcionais na especificação RFC 822, que está quebrando o analisador data. Se nada der certo, eu provavelmente tenho que escrever um analisador personalizado obedecer às especificações.

Por exemplo, o nome do dia é opcional na especificação. Assim, tanto essas datas são válidos:

Tue, 01 Dec 2009 08:48:25 +0000 é analisado com o EEE, dd MMM yyyy HH:mm:ss z formato 01 Dec 2009 08:48:25 +0000 é analisado com o dd MMM yyyy HH:mm:ss z formato

Este é o que eu estou usando atualmente:

+ (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];
}

E analisar a data da seguinte forma:

self.entry.published = [NSDate dateFromRFC822:self.currentString];

Uma maneira é tentar ambos os formatos, e tomar qualquer retorna valor não nulo. No entanto, existem duas partes opcionais na especificação (nome dia e segundos) e não haveria 4 combinações possíveis. Ainda não muito ruim, mas é um pouco hacky.

Foi útil?

Solução

Contar o número de caracteres salientes antes de decidir qual formatador para uso. Por exemplo, os dois você dá ter números diferentes de vírgulas e espaços. Se nenhum formato conhecido corresponde a contagem, então você não sabe até tentar analisá-lo como uma data.

Outras dicas

Eu usei o seguinte método para datas RFC822 analisar. Eu acredito que originalmente era de 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;

}

Eu acredito RFC 822 especifica dois componentes opcionais no tempo de data:. Dia da semana e os segundos após a hora

Como um hack, é possível os símbolos para os curtos dias da semana:

NSArray *shortWeekSymbols = [NSArray arrayWithObjects:@"Sun,", @"Mon,", @"Tue,", @"Wed,", @"Thu,", @"Fri,", @"Sat,", nil];
        [formatter setShortWeekdaySymbols:shortWeekSymbols];

Se você alterar o formato de data para isso: EEEdd MMM yyyy HH:mm:ss z. Você vai ser capaz de analisar vezes com aproximadamente sem o dia da semana. Este parece permitir um espaço após a vírgula também.

Para ser seguro, você não deve apenas cega definir os símbolos como este. Você deve obter usando setShortWeekdaySymbols e iterate sobre eles adicionando a vírgula no final. A razão é que eles são potencialmente diferente para cada localidade e no primeiro dia pode não ser domingo.

Curiosamente o formato EEE, dd MMM yyyy HH:mm:ss z irá analisar vezes sem o dia da semana, mas a vírgula deve estar lá, por exemplo , 01 Dec 2009 08:48:25 +0000. Portanto, você poderia fazer algo parecido com Steve disse, mas, em seguida, retirar o dia e passar embora para o formatador. Não tendo a vírgula no formato não parece permitir a semana para ser opcional. Strange.

Infelizmente, isso ainda não ajuda com o opcional: ss no formato. Mas pode permitir que você tenha dois formatos em vez de quatro.

No caso este seja útil para qualquer outra pessoa .. aqui é uma extensão NSDate + RFC822String.swift baseado em de Simucal resposta .

Ele também armazena o último formato de data usado que foi bem sucedida, uma vez definindo o dateFormatter.dateFormat é caro.

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
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top