Pregunta

Estoy usando un NSDateFormatter para analizar una fecha RFC 822 en el iPhone. Sin embargo, no hay forma de especificar los elementos opcionales en el formato de fecha. Hay un par de piezas opcionales en el RFC 822 especificación que está rompiendo el analizador fecha. Si nada funciona, probablemente tendría que escribir un analizador personalizado a obedecer las especificaciones.

Por ejemplo, el nombre del día es opcional en la especificación. Así pues, estas dos fechas son válidas:

Tue, 01 Dec 2009 08:48:25 +0000 se analiza con el formato EEE, dd MMM yyyy HH:mm:ss z 01 Dec 2009 08:48:25 +0000 se analiza con el formato dd MMM yyyy HH:mm:ss z

Esto es lo que estoy utilizando actualmente:

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

y el análisis de la fecha de la siguiente manera:

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

Una forma es probar ambos formatos, y tomar cualquier valor que no vuelve nula. Sin embargo, hay dos partes opcionales en la especificación (nombre día y segundo) y no habría 4 combinaciones posibles. Todavía no es demasiado malo, pero es un poco hacky.

¿Fue útil?

Solución

Contar el número de caracteres sobresalientes antes de decidir qué formateador de usar. Por ejemplo, los dos das tienen diferente número de comas y espacios. Si hay un formato conocido coincide con el recuento, a continuación, usted conocido ni siquiera intentar analizarlo como una fecha.

Otros consejos

He utilizado el siguiente método para analizar fechas RFC822. Creo que fue originalmente 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;

}

Creo RFC 822 especifica dos componentes opcionales en el momento de la fecha:. Día de la semana y los segundos después de la hora

Como un truco, es posible que los símbolos de los cortos días de la semana:

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

Si cambia el formato de fecha a esto: EEEdd MMM yyyy HH:mm:ss z. Usted será capaz de analizar veces con aproximadamente sin el día de la semana. Esto parece permitir un espacio después de la coma también.

Para estar seguro que no sólo debe establecer ciegamente los símbolos de este tipo. Usted debe obtener utilizando setShortWeekdaySymbols e iterar sobre ellos la adición de la coma al final. La razón es que son potencialmente diferente para cada entorno local y el primer día podría no ser domingo.

Es interesante que el formato de EEE, dd MMM yyyy HH:mm:ss z analizará veces sin el día de la semana, pero la coma debe estar allí, por ejemplo , 01 Dec 2009 08:48:25 +0000. Por lo tanto, se podría hacer algo como Steve dijo, pero luego quitarse el día y pasar a través de al formateador. No tener la coma en el formato no parece permitir la semana para ser opcional. Extraña.

Por desgracia, esto todavía no ayuda con el programa opcional: ss en el formato. Pero puede ser que le permiten tener dos formatos en lugar de cuatro.

En el caso de que esto sea útil a alguien más .. aquí es una extensión NSDate + RFC822String.swift basado en de Simucal respuesta .

También almacena en caché el último formato de fecha usado que fue un éxito, ya que el establecimiento de la dateFormatter.dateFormat es 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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top