【问题标题】:Who is implementing the ISO8601 in correct way? Swift or Spring?谁以正确的方式实施 ISO8601?斯威夫特还是春天?
【发布时间】:2023-04-07 06:06:03
【问题描述】:

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

【问题讨论】:

    标签: swift spring iso


    【解决方案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)
    

    【讨论】:

      【解决方案2】:

      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 节中)小数部分 如果小于统一,则以“0”开头。 ISO 8601 附录 B.2 给出了小数部分前面没有“0”的例子。 该语法假定第 5.3.1.3 节是正确的并且附件 B.2 是 出错了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-07-22
        • 2017-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-08
        • 2017-11-13
        相关资源
        最近更新 更多