2010-12-01 15 views
17

El análisis de una fecha rfc3339 con NSDateFormatter parece ser imposible, en el caso general. ¿Me equivoco? [Editar 2 años después: ¡ahora hay un camino! . Ver más abajo y la nota]Analizando rfc3339 fechas con NSDateFormatter en iOS 4.xy MacOS X 10.6: ¿imposible?

Un servicio web no-especialmente maleable me está alimentando fechas como:

2009-12-31T00:00:00-06:00 

Rfc3339 compatible, salida por defecto de la biblioteca jaxb que están usando. Observe los dos puntos, lo que requiere rfc3339 cuando el desplazamiento no es una "z" literal:

time-numoffset = ("+"/"-") time-hour ":" time-minute 
time-offset  = "Z"/time-numoffset 

Quiero analizar estos en NSDates.

NSDateFormatter desea patrones en la sintaxis especificada por Unicode, que ofrece símbolos de campo de fecha para zonas horarias como "PDT", "-0800", "GMT-08: 00" pero no "-08: 00".

Googling, y otros de los preguntas similares, produce sólo formatos de fecha como

[myDateParser setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"]; 
/* or: */ [myDateParser setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"]; 

El último de los cuales requiere un literal "Z", y la antigua insiste ya sea la ausencia de un colon o presencia de una " GMT". Sin embargo, aparecieron a trabajar antes de iOS 4.x (posiblemente descartando la tz compensar completamente; mis datos no son claras.)

Mis opciones en este momento hay una gran cantidad siento:

  • descubrir algunos especificador de formato no documentado, o algún modo extraño para poner NSDateFormatter en, que aceptará los dos puntos: tiro largo, probablemente inexistente. [nota al pie]
  • persuade a mi editor de servicios para convertir todas las fechas en hora zulu y especifique 'Z': políticamente desafiante.
  • escriba mi propia subclase NSFormatter o investigue bien anterior strptime_l: trabajo. :)
  • string-manipular mi entrada y eliminar el último colon: frágil y feo, pero el camino probable de menor resistencia.

¿He entendido correctamente la situación, que la corriente NSDateFormatter sigue estrictamente Unicode sin extensiones; y los formatos Unicode son insuficientes para describir completamente una fecha rfc3339?

[Nota] vuelvo a esto tres años más tarde para virar en una pequeña adición: Unicode y Apple han añadido esta característica para las cadenas de formato, a partir de iOS 6/OSX10.8. Compare The latest revision as of this writing con its immediate predecessor, y tenga en cuenta la adición de 5 "Z" s, que produce un formato de zona como "-08: 00". Entonces, si puede salirse con la ayuda de abandonar 5.x/10.7, hay una nueva forma correcta de hacerlo. Dejaré la respuesta anterior en pie, ya que sigue siendo el mejor enfoque cuando se requiere compatibilidad con versiones anteriores.

Respuesta

8

El análisis de cadenas de fechas en Cocoa puede ser un problema, especialmente si tiene que lidiar con las fechas generadas por los servicios web basados ​​en .NET.

Sugiero mirar la categoría NSDate + InternetDateTime que Michael Waterfall tiene en NSDate como parte de su proyecto MWFeedParser en github. Me funcionó bien al analizar exactamente el formato de la fecha que describes.

https://github.com/mwaterfall/MWFeedParser/

+0

Gracias por el puntero - Miré en su fuente, y lo que usted sabe, la opción 4 (eliminar los dos últimos puntos) es precisamente lo que hace. Como esto funciona para él, probablemente sigo su ejemplo. – rgeorge

11

- getObjectValue: forString: Gama: error: en realidad puede analizar data RFC3339 correctamente. No tengo ni idea de por qué - dateWithString: no se puede:

caracteres de formato
// RFC3339 date formatting 
NSString *dateString = @"2012-04-11T18:34:19+00:00"; 
NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ"; 

NSDate *date; 
NSError *error; 
[formatter getObjectValue:&date forString:dateString range:nil error:&error]; 
+0

En realidad, no tengo nada que mejorar aquí y quería agradecer al póster (sc0rp10n) por señalar que dateFromString: no funciona con este tipo de fechas, mientras que getObjectValue: does. Esto me ha estado volviendo loco y estaba a punto de probar getObjectValue: para poder especificar un rango que deje la parte de la zona horaria. Tu sugerencia me salvó. Gracias. –

5

la cadena están documentados en ninguna parte de la documentación de Apple. En cambio, hay un vínculo oculto en algún documento que apunta hacia el estándar Unicode en

http://www.unicode.org/reports/tr35/tr35-31/tr35-dates.html#Date_Format_Patterns

Usando la información en ese enlace es bastante simple:

- (NSDate*)dateFromRFC3339String:(NSString*)aString 
{ 
    static NSDateFormatter* sRFC3339DateFormatter = nil; 
    static NSDateFormatter* sRFC3339DateFormatterSubSeconds = nil; 
    static dispatch_once_t onceToken; 

    dispatch_once(&onceToken, ^{ 
     NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; 

     sRFC3339DateFormatter = [[NSDateFormatter alloc] init]; 
     [sRFC3339DateFormatter setLocale:enUSPOSIXLocale]; 
     [sRFC3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ssXXXXX"]; 
     [sRFC3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; 

     sRFC3339DateFormatterSubSeconds = [[NSDateFormatter alloc] init]; 
     [sRFC3339DateFormatterSubSeconds setLocale:enUSPOSIXLocale]; 
     [sRFC3339DateFormatterSubSeconds setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss.SSSSSSXXXXX"]; 
     [sRFC3339DateFormatterSubSeconds setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; 
    }); 

    NSDate* date = [sRFC3339DateFormatter dateFromString:aString]; 
    if (date == nil) 
     date = [sRFC3339DateFormatterSubSeconds dateFromString:aString]; 

    return date; 
} 
+0

sí, la familia de formatos 'X' ... se ha agregado a la versión de la especificación admitida por iOS 7 (tr35-31.) 'ZZZZZ' se define equivalente a 'XXXXX' y está disponible en ios6 (definido en tr35-25), entonces para esta aplicación en particular, recomiendo lo primero. – rgeorge

+1

XXXXX y ZZZZZ son más indulgentes que RFC 3339 ya que permiten segundos en la zona horaria. XXX está más cerca de la especificación (es decir, permite Z y compensaciones como -08: 00). –

Cuestiones relacionadas