Spring框架中使用的Jackson序列化程序的默认行为如下:(来自spring-data-rest源代码):
/**
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSZ},
* e.g. "2000-10-31T01:30:00.000-05:00".
* <p>This is the default if no annotation value is specified.
*/
所以这种格式化的一个例子可能是2019-03-20T11:18:46.000+0000
。 Swift也有ISO8601解码器,但事实上,对于Swift来说,这个字符串由于毫秒而只有无效的格式。如果删除毫秒部分,swift可以成功反序列化字符串。
struct Test: Codable {
let createdAt: Date
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let data2 = "{\"createdAt\": \"2018-12-05T14:05:35.000+0000\"}".data(using: .utf8)!
let decoded2 = try! decoder.decode(Test.self, from: data2)
Swift指的是RFC 3339 https://www.ietf.org/rfc/rfc3339.txt,并没有提到毫秒。我的问题是 - 什么格式是正确的呢?如果某些东西是ISO格式的,应该严格定义,我通常不希望编写自定义反序列化器(swift)或定义序列化的自定义模式(spring)。
您应该设置iso8601选项。您可以使用ISO8601DateFormatter来完成。
struct Test: Codable {
let createdAt: Date
}
enum CustomDateDecodingStrategy {
private static let formatter: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [
.withFullDate,
.withFullTime,
.withTimeZone,
.withFractionalSeconds
]
return formatter
}()
static func decode(_ decoder: Decoder) throws -> Date {
let container = try decoder.singleValueContainer()
let dateStr = try container.decode(String.self)
if let date = formatter.date(from: dateStr) {
return date
} else {
throw NSError(domain: "date", code: -1, userInfo: nil)
}
}
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .custom(CustomDateDecodingStrategy.decode)
let data2 = "{\"createdAt\": \"2018-12-05T14:05:35.000+0000\"}".data(using: .utf8)!
let decoded2 = try! decoder.decode(Test.self, from: data2)
如果特定应用需要,可以包括小时,分钟或秒的小数部分。如果包含小数部分,则应省略低阶时间元素(如果有),小数部分应从整数部分除以ISO 31-0中指定的小数符号,即逗号[,]或句号[ ]。其中,逗号是首选标志。如果数字的大小小于1,则小数符号前面应按照3.6的两个零。
所以2018-12-05T14:05:35.000
是合法的。虽然RFC 3339没有按名称提及毫秒,但它确实谈到了“分数”,例如:
下面定义的格式仅包括一个很少使用的选项:一秒的分数。预计这将仅用于需要严格订购日期/时间戳或具有不寻常精度要求的应用程序。
和
ISO 8601还要求(在第5.3.1.3节中)如果小于1,则小数部分前进为“0”。 ISO 8601的附录B.2给出了小数分数前面没有“0”的例子。该语法假设第5.3.1.3节是正确的,附件B.2是错误的。