谁在以正确的方式实施ISO8601?斯威夫特还是春天?

时间:2019-04-02 08:25:37

标签: swift spring iso

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可以成功反序列化字符串。

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)。

2 个答案:

答案 0 :(得分:1)

您应该设置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)

答案 1 :(得分:1)

the ISO8601 2016 draft的第23页:

  

如果对于特定的应用程序是必需的,则可以包括小时,分钟或秒的十进制小数。如果包括小数部分,则应省略低阶时间元素(如果有的话),并且小数部分应从整数部分除以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是      错误。