tutorial objective ios objective-c

ios - objective - Cómo analizar ISO 8601 utilizando NSDateFormatter con la parte de milisegundos opcional



objective c tutorial (3)

Estoy tratando de usar un NSDateFormatter para analizar las fechas que están en cualquiera de estos formatos

@"2013-02-01T14:21:00"

o

@"2013-02-01T14:21:56.345"

Actualmente estoy usando el siguiente método para analizar la cadena y devolver una fecha:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]]; [dateFormatter setDateFormat:@"yyyy-MM-dd''T''HH:mm:ss"]; [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]]; NSDate *date = [dateFormatter dateFromString:dateToFormat];

Esto funciona bien para el primer estilo de fecha pero devuelve nil para una cadena que incluye la parte de milisegundos.

Supongo que podría probar la existencia de los milisegundos y eliminarlos, pero me preguntaba si podría cambiar el formato de fecha para tratar el .SSS como opcional.

Gracias por tu ayuda


El enfoque correcto desde iOS 10 es usar ISO8601DateFormatter creado específicamente para manejar todas las variaciones de las cadenas de fecha ISO 8601. Por favor, vea el ejemplo a continuación:

let date = Date() var string: String let formatter = ISO8601DateFormatter() string = formatter.string(from: date) let GMT = TimeZone(abbreviation: "GMT") let options: ISO8601DateFormatOptions = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withTimeZone] string = ISO8601DateFormatter.string(from: date, timeZone: GMT, formatOptions: options)

Y la versión Objective-C:

NSDate *date = [NSDate date]; NSString *string; NSISO8601DateFormatter *formatter = [[NSISO8601DateFormatter alloc] init]; string = [formatter stringFromDate:date]; NSTimeZone *GMT = [NSTimeZone timeZoneWithAbbreviation: @"GMT"]; NSISO8601DateFormatOptions options = NSISO8601DateFormatWithInternetDateTime | NSISO8601DateFormatWithDashSeparatorInDate | NSISO8601DateFormatWithColonSeparatorInTime | NSISO8601DateFormatWithTimeZone; string = [NSISO8601DateFormatter stringFromDate:date timeZone:GMT formatOptions:options];


Escribí un analizador universal que soltó milisegundos.

@implementation JSONModel(NSPAdditions) - (NSDate *)NSDateFromNSString:(NSString*)string { NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]]; NSArray* parts = [string componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@" T"]]; if ([parts count] <= 1) { return [formatter dateFromString:string]; } NSString *part0 = parts[0]; NSAssert([part0 length] == [@"yyyy-MM-dd" length], @"Date format error"); NSString *part1 = parts[1]; if ([part1 length] > [@"HH:mm:ss" length]) { part1 = [part1 substringToIndex:[@"HH:mm:ss" length]]; } NSString *fmted = [NSString stringWithFormat:@"%@ %@", part0, part1]; [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; return [formatter dateFromString:fmted]; } @end


Por lo que sé, no hay manera de hacer parámetros opcionales.

La solución habitual es utilizar dos formateadores, uno para cada formato. Para decidir qué formateador utilizar, puede:

  1. Cuente el número de caracteres en la cadena de fecha (como se sugiere en el análisis de una fecha RFC 822 con NSDateFormatter )

  2. Solo intente con ambos formateadores y obtenga el primer resultado no nil .

Dado que los formatos de fecha son similares, puede ir con un solo formateador y si la cadena de fecha es demasiado corta, agregue .000 antes de usar el formateador.