ios nsdate nsdateformatter iso8601

¿Cómo obtengo una fecha ISO 8601 en iOS?



nsdate nsdateformatter (10)

Basado en esta esencia: https://github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.swift , se puede usar el siguiente método para convertir NSDate en cadena de fecha ISO 8601 en el formato de aaaa-MM -dd''T''HH: mm: ss.SSSZ

-(NSString *)getISO8601String { static NSDateFormatter *formatter = nil; if (!formatter) { formatter = [[NSDateFormatter alloc] init]; [formatter setLocale: [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]]; formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation: @"UTC"]; [formatter setDateFormat:@"yyyy-MM-dd''T''HH:mm:ss.SSS"]; } NSString *iso8601String = [formatter stringFromDate: self]; return [iso8601String stringByAppendingString: @"Z"]; }

Es bastante fácil obtener la cadena de fecha ISO 8601 (por ejemplo, 2004-02-12T15:19:21+00:00 ) en PHP a través de la date(''c'') , pero ¿cómo se obtiene en Objective-C (iPhone? )? ¿Hay alguna manera similar de hacerlo?

Aquí está el largo camino que encontré para hacerlo:

NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; dateFormatter.dateFormat = @"yyyy-MM-dd''T''HH:mm:ssZ"; NSDate *now = [NSDate date]; NSString *formattedDateString = [dateFormatter stringFromDate:now]; NSLog(@"ISO-8601 date: %@", formattedDateString); // Output: ISO-8601 date: 2013-04-27T13:27:50-0700

Parece una gran cantidad de tonterías para algo tan central.



Desde IS8601 , los problemas son la representación y la zona horaria

  • ISO 8601 = year-month-day time timezone
  • Para la fecha y la hora, hay formato básico (AAAAMMDD, hhmmss, ...) y extendido (AAAA-MM-DD, hh: mm: ss, ...)
  • La zona horaria puede ser Zulu, offset o GMT
  • El separador de fecha y hora puede ser espacio, o T
  • Hay formato de semana para la fecha, pero rara vez se usa
  • La zona horaria puede ser un montón de espacios después
  • El segundo es opcional

Aquí hay algunas cadenas válidas

2016-04-08T10:25:30Z 2016-04-08 11:25:30+0100 2016-04-08 202530GMT+1000 20160408 08:25:30-02:00 2016-04-08 11:25:30 +0100

Soluciones

NSDateFormatter

Así que aquí está el formato que estoy usando en myway133 ISO8601

let formatter = NSDateFormatter() formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") formatter.dateFormat = "yyyyMMdd HHmmssZ"

Acerca del identificador Z Fecha Tabla de símbolos de campo

Z: The ISO8601 basic format with hours, minutes and optional seconds fields. The format is equivalent to RFC 822 zone format (when optional seconds field is absent)

Acerca de la locale Formateo de datos utilizando la configuración regional

Las configuraciones regionales representan las opciones de formato para un usuario en particular, no el idioma preferido del usuario. Estos son a menudo lo mismo, pero pueden ser diferentes. Por ejemplo, un hablante nativo de inglés que vive en Alemania puede seleccionar inglés como idioma y Alemania como región

Acerca de en_US_POSIX Preguntas y respuestas técnicas QA1480 NSDateFormatter y fechas de Internet

Por otro lado, si está trabajando con fechas de formato fijo, primero debe establecer la configuración regional del formateador de fechas en algo apropiado para su formato fijo. En la mayoría de los casos, la mejor ubicación para elegir es "en_US_POSIX", una configuración regional específicamente diseñada para generar resultados en inglés de EE. UU. Independientemente de las preferencias del usuario y del sistema. "en_US_POSIX" también es invariante en el tiempo (si EE. UU., en algún momento en el futuro, cambia la forma en que da formato a las fechas, "en_US" cambiará para reflejar el nuevo comportamiento, pero "en_US_POSIX" no), y entre máquinas ( "en_US_POSIX" funciona igual en iOS que en OS X, y como lo hace en otras plataformas).

Interesantes consultas relacionadas


Entonces usa la categoría de Sam Soffee en NSDate que se encuentra here . Con ese código agregado a su proyecto, a partir de ese momento puede usar un único método en NSDate:

- (NSString *)sam_ISO8601String

No solo es una línea, es mucho más rápido que el enfoque NSDateFormatter, ya que está escrito en C. puro


Esto es un poco más simple y pone la fecha en UTC.

extension NSDate { func iso8601() -> String { let dateFormatter = NSDateFormatter() dateFormatter.timeZone = NSTimeZone(name: "UTC") let iso8601String = dateFormatter.stringFromDate(NSDate()) return iso8601String } } let date = NSDate().iso8601()



Un problema que a menudo se pasa por alto es que las cadenas en formato ISO 8601 pueden tener milisegundos y pueden no serlo.

En otras palabras, tanto "2016-12-31T23: 59: 59.9999999" como "2016-12-01T00: 00: 00" son legítimos, pero si está utilizando el formateador de fecha de tipo estático, uno de ellos no será analizado .

A partir de iOS 10 , debe usar ISO8601DateFormatter que maneja todas las variaciones de cadenas de fecha ISO 8601. Vea el siguiente ejemplo:

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)

Para iOS 9 y siguientes, utilice el siguiente enfoque con formateadores de datos múltiples.

No he encontrado una respuesta que cubra ambos casos y abstraiga esta sutil diferencia. Aquí está la solución que lo aborda:

extension DateFormatter { static let iso8601DateFormatter: DateFormatter = { let enUSPOSIXLocale = Locale(identifier: "en_US_POSIX") let iso8601DateFormatter = DateFormatter() iso8601DateFormatter.locale = enUSPOSIXLocale iso8601DateFormatter.dateFormat = "yyyy-MM-dd''T''HH:mm:ss.SSS''Z''" iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0) return iso8601DateFormatter }() static let iso8601WithoutMillisecondsDateFormatter: DateFormatter = { let enUSPOSIXLocale = Locale(identifier: "en_US_POSIX") let iso8601DateFormatter = DateFormatter() iso8601DateFormatter.locale = enUSPOSIXLocale iso8601DateFormatter.dateFormat = "yyyy-MM-dd''T''HH:mm:ss''Z''" iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0) return iso8601DateFormatter }() static func date(fromISO8601String string: String) -> Date? { if let dateWithMilliseconds = iso8601DateFormatter.date(from: string) { return dateWithMilliseconds } if let dateWithoutMilliseconds = iso8601WithoutMillisecondsDateFormatter.date(from: string) { return dateWithoutMilliseconds } return nil } }

Uso:

let dateToString = "2016-12-31T23:59:59.9999999" let dateTo = DateFormatter.date(fromISO8601String: dateToString) // dateTo: 2016-12-31 23:59:59 +0000 let dateFromString = "2016-12-01T00:00:00" let dateFrom = DateFormatter.date(fromISO8601String: dateFromString) // dateFrom: 2016-12-01 00:00:00 +0000

También recomiendo consultar el artículo de Apple sobre formateadores de fecha.


Usando Swift 3.0 y iOS 9.0

extension Date { private static let jsonDateFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateFormat = "yyyy-MM-dd''T''HH:mm:ss.SSSZZZZZ" formatter.locale = Locale(identifier: "en_US_POSIX") formatter.timeZone = TimeZone(identifier: "UTC")! return formatter }() var IOS8601String: String { get { return Date.jsonDateFormatter.string(from: self) } } init?(fromIOS8601 dateString: String) { if let d = Date.jsonDateFormatter.date(from: dateString) { self.init(timeInterval: 0, since:d) } else { return nil } } }


Use NSDateFormatter :

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; NSLocale *enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; [dateFormatter setLocale:enUSPOSIXLocale]; [dateFormatter setDateFormat:@"yyyy-MM-dd''T''HH:mm:ssZZZZZ"]; NSDate *now = [NSDate date]; NSString *iso8601String = [dateFormatter stringFromDate:now];

Y en Swift:

let dateFormatter = DateFormatter() let enUSPosixLocale = Locale(identifier: "en_US_POSIX") dateFormatter.locale = enUSPosixLocale dateFormatter.dateFormat = "yyyy-MM-dd''T''HH:mm:ssZZZZZ" let iso8601String = dateFormatter.string(from: Date())


iOS 10 presenta una nueva clase NSISO8601DateFormatter para manejar esto. Si está usando Swift 3, su código sería algo como esto:

let formatter = ISO8601DateFormatter() let date = formatter.date(from: "2016-08-26T12:39:00Z") let string = formatter.string(from: Date())