¿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.
Como complemento a la respuesta de Maddy, el formato de zona horaria debe ser "ZZZZZ" (5 veces Z) para ISO 8601 en lugar de una sola "Z" (que es para el formato RFC 822). Al menos en iOS 6.
(ver http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns )
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
- Parse paso a paso, como soffes ISO8601
- Convierte a formato básico, como onmyway133 ISO8601
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()
Solo use NSISO8601DateFormatter desde el framework de Foundation.
let isoDateFormatter = ISO8601DateFormatter()
print("ISO8601 string: /(isoDateFormatter.string(from: Date()))")
// ISO8601 string: 2018-03-21T19:11:46Z
https://developer.apple.com/documentation/foundation/nsiso8601dateformatter?language=objc
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())