我正在用Swift的Codable替换旧的JSON解析代码,并且遇到了一些麻烦。我想这不是一个Codable问题,而是一个DateFormatter问题。
从结构开始
struct JustADate: Codable {
var date: Date
}
和一个json字符串
let json = """
{ "date": "2017-06-19T18:43:19Z" }
"""
现在让我们解码
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let data = json.data(using: .utf8)!
let justADate = try! decoder.decode(JustADate.self, from: data) //all good
但是,如果我们更改日期,使其具有小数秒,例如:
let json = """
{ "date": "2017-06-19T18:43:19.532Z" }
"""
现在坏了。日期有时会以小数秒返回,有时却不会。我用来解决该问题的方法是在映射代码中,我有一个转换函数,该函数尝试使用带和不带小数秒的dateFormats。我不太确定如何使用Codable处理它。有什么建议?
您可以使用两个不同的日期格式器(带和不带小数秒)并创建自定义的DateDecodingStrategy。如果在解析API返回的日期时失败,则可以按@PauloMattos的建议在注释中引发DecodingError:
iOS 9,macOS 10.9,tvOS 9,watchOS 2,Xcode 9或更高版本
自定义ISO8601DateFormatter:
extension Formatter {
static let iso8601withFractionalSeconds: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
return formatter
}()
static let iso8601: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXXXX"
return formatter
}()
}
习惯DateDecodingStrategy
:
extension JSONDecoder.DateDecodingStrategy {
static let customISO8601 = custom {
let container = try $0.singleValueContainer()
let string = try container.decode(String.self)
if let date = Formatter.iso8601withFractionalSeconds.date(from: string) ?? Formatter.iso8601.date(from: string) {
return date
}
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid date: \(string)")
}
}
习惯DateEncodingStrategy
:
extension JSONEncoder.DateEncodingStrategy {
static let customISO8601 = custom {
var container = $1.singleValueContainer()
try container.encode(Formatter.iso8601withFractionalSeconds.string(from: $0))
}
}
编辑/更新 :
Xcode 10•Swift 4.2或更高版本•iOS 11.2.1或更高版本
ISO8601DateFormatter
现在支持formatOptions
.withFractionalSeconds
:
extension Formatter {
static let iso8601withFractionalSeconds: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
return formatter
}()
static let iso8601: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime]
return formatter
}()
}
习惯DateDecodingStrategy
和DateEncodingStrategy
将与上面显示的相同。
// Playground testing
struct ISODates: Codable {
let dateWith9FS: Date
let dateWith3FS: Date
let dateWith2FS: Date
let dateWithoutFS: Date
}
let isoDatesJSON = """
{
"dateWith9FS": "2017-06-19T18:43:19.532123456Z",
"dateWith3FS": "2017-06-19T18:43:19.532Z",
"dateWith2FS": "2017-06-19T18:43:19.53Z",
"dateWithoutFS": "2017-06-19T18:43:19Z",
}
"""
let isoDatesData = Data(isoDatesJSON.utf8)
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .customISO8601
do {
let isoDates = try decoder.decode(ISODates.self, from: isoDatesData)
print(Formatter.iso8601withFractionalSeconds.string(from: isoDates.dateWith9FS)) // 2017-06-19T18:43:19.532Z
print(Formatter.iso8601withFractionalSeconds.string(from: isoDates.dateWith3FS)) // 2017-06-19T18:43:19.532Z
print(Formatter.iso8601withFractionalSeconds.string(from: isoDates.dateWith2FS)) // 2017-06-19T18:43:19.530Z
print(Formatter.iso8601withFractionalSeconds.string(from: isoDates.dateWithoutFS)) // 2017-06-19T18:43:19.000Z
} catch {
print(error)
}
问题内容: 我有以下代码片段: 运行此命令时,将其作为输出: 我期望: 我的意思是说我没有达到预期的月份。怎么了 问题答案: 尝试这个: is “month” (not ) is “day” (not ) 全部包含在SimpledocateFormat的javadoc中 仅供参考,你的格式仍然是有效的日期格式的原因是: is “minutes” is “day in year” 此外,你不需要投地
我正在Android中转换字符串到日期对象......该字符串来自服务器,形式为“2014-02-22”或类似的...我想把它转换成我的日期,我可以在我的应用程序中使用…我是用简单的日期格式,解析的方法来转换....但此语句引发分析异常...意思是它不是转换我的字符串..也就是“2014-02-22”……它应该转换,但它不....所以好心帮我一下.....我得到空的响应
问题内容: 我有一个字符串,例如date month year(31 08 2012)。我想将其转换为日期格式。 问题答案: 首先,您的格式有误,应该是
问题内容: 我有一列用作,我想将其选择为。 可能吗? 我的样本数据格式为;-> 问题答案: 正如MySQL所讲的,使用带有日期文本的字符串列作为日期字段,您可以 您还可以在子句中处理这些日期字符串。例如 您可以通过这种方式处理各种日期/时间布局。请参考该函数的格式说明符,以了解可以在中添加第二个参数的内容。
问题内容: 我学得很快,并且对将日期String转换为NSDate转换为string感到震惊。我正在以以下格式获取日期字符串:“2015年10月22日星期四07:45:17 +0000”。我需要以MM-dd-yyyy格式显示日期。我尝试了以下代码,但返回“ null”。 谁能帮忙哪里出问题了?期待帮助。提前致谢。 问题答案: 首先,您需要使用其格式将字符串转换为NSDate。然后,将更改为简单格式
问题内容: 我想将“ 2014-07-15 06:55:14.198000 + 00:00”此字符串日期转换为Swift中的NSDate。 问题答案: 试试这个: 要进行进一步查询,请分别检查 Foundation 框架的Objective- C和Swift的NSDateFormatter和DateFormatter类。 __ Swift 3及更高版本(包括Swift 4)