ios - string to date swift 4
ISO8601DateFormatter no analiza la cadena de fecha ISO (3)
Antes de macOS 10.13 / iOS 11 ISO8601DateFormatter
no admite cadenas de fecha, incluidos los milisegundos.
Una solución es eliminar la parte de milisegundos con expresiones regulares.
let isoDateString = "2017-01-23T10:12:31.484Z"
let trimmedIsoString = isoDateString.replacingOccurrences(of: "//.//d+", with: "", options: .regularExpression)
let formatter = ISO8601DateFormatter()
let date = formatter.date(from: trimmedIsoString)
En macOS 10.13+ / iOS 11+ se agrega una nueva opción para soportar segundos fraccionarios:
static var withFractionalSeconds: ISO8601DateFormatter.Options { get }
let isoDateString = "2017-01-23T10:12:31.484Z"
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
let date = formatter.date(from: isoDateString)
Estoy tratando de analizar esto
2017-01-23T10: 12: 31.484Z
el uso de la clase nativa ISO8601DateFormatter
proporcionada por iOS 10
pero siempre falla. Si la cadena no contiene milisegundos, el objeto Date
se crea sin problemas.
He probado esta combinación y muchas options
pero siempre falla ...
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.formatOptions = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withColonSeparatorInTimeZone, .withFullTime]
¿Alguna idea? ¡Gracias!
Me encontré con el mismo problema hace unos meses. Y aquí está mi solución para referencia:
// *****************************************
// MARK: - Formatter extension
// *****************************************
extension Formatter {
static let iso8601: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone.current
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
return formatter
}()
static let iso8601NoSecond: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone.current
formatter.formatOptions = [.withInternetDateTime]
return formatter
}()
}
// *****************************************
// MARK: - ISO8601 helper
// *****************************************
func getDateFrom(DateString8601 dateString:String) -> Date?
{
if let date = Formatter.iso8601.date(from: dateString) {
return date
}
if let date = Formatter.iso8601NoSecond.date(from: dateString) {
return date
}
return nil
}
// *****************************************
// usage
// *****************************************
let d = getDateFrom(DateString8601: "2017-01-23T10:12:31.484Z")
print("2017-01-23T10:12:31.484Z millis= ", d?.timeIntervalSinceReferenceDate)
let d2 = getDateFrom(DateString8601: "2017-01-23T10:12:31Z")
print("2017-01-23T10:12:31Z millis= ", d2?.timeIntervalSinceReferenceDate)
// *****************************************
// result
// *****************************************
2017-01-23T10:12:31.484Z millis= Optional(506859151.48399997)
2017-01-23T10:12:31Z millis= Optional(506859151.0)
Quizás esto ayude a decodificar formatos ligeramente diferentes:
extension JSONDecoder {
enum DateDecodeError: String, Error {
case invalidDate
}
static var bestDateAttemptDecoder: JSONDecoder {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
let container = try decoder.singleValueContainer()
if let dateSecs = try? container.decode(Double.self) {
return Date(timeIntervalSince1970: dateSecs)
}
if let dateSecs = try? container.decode(UInt.self) {
return Date(timeIntervalSince1970: TimeInterval(dateSecs))
}
let dateStr = try container.decode(String.self)
let isoFormatter = ISO8601DateFormatter()
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
if let date = isoFormatter.date(from: dateStr) {
return date
}
isoFormatter.formatOptions = [.withInternetDateTime ]
if let date = isoFormatter.date(from: dateStr) {
return date
}
log.warning("Cannot decode date");
throw DateDecodeError.invalidDate
})
return decoder
}
}
Desde: https://gist.github.com/th3m477/442a0d1da6354dd3b84e3b71df5dca6a