私はこれを解析しようとしています
2017-01-23T10:12:31.484Z
ネイティブISO8601DateFormatter
が提供するクラスiOS 10
しかし、常に失敗します。文字列にミリ秒が含まれていない場合、Date
オブジェクトが問題なく作成されます。
私はこれと多くのoptions
の組み合わせを試しましたが、常に失敗します...
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.formatOptions = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withColonSeparatorInTimeZone, .withFullTime]
何か案が?ありがとう!
MacOS 10.13/iOS 11より前ISO8601DateFormatter
は、ミリ秒を含む日付文字列をサポートしません。
回避策は、正規表現でミリ秒部分を削除することです。
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)
MacOS 10.13以降/ iOS 11以降では、秒の小数部をサポートするための新しいオプションが追加されました。
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)
まだiOS 11に移行する準備が整っていない人のために、ミリ秒を処理する独自のフォーマッターをいつでも作成できます。例:
extension DateFormatter {
static var iSO8601DateWithMillisec: DateFormatter {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
return dateFormatter
}
}
使用法:
let formater = DateFormatter.iSO8601DateWithMillisec
let date = formater.date(from: "2017-01-23T10:12:31.484Z")!
print(date) // output: 2017-01-23 10:12:31 +0000
入力文字列からミリ秒を取り除くために正規表現を書くよりもわずかにエレガントです。
たぶん、これはわずかに異なる形式をデコードするのに役立ちます:
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
}
}
から: https://Gist.github.com/th3m477/442a0d1da6354dd3b84e3b71df5dca6a
私は数ヶ月前に同じ問題に遭遇しました。参照用の私のソリューションは次のとおりです。
// *****************************************
// 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)