Swift DateFormatter可选毫秒

时间:2018-01-21 19:56:58

标签: ios swift nsdateformatter

我有以下代码来解析ISO8601日期。

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"

问题有时候日期的格式为2018-01-21T20:11:20.057Z,有时格式为2018-01-21T20:11:20Z

所以基本上部分时间它有.SSS毫秒部分,有时则没有。{/ p>

如何设置日期格式化程序以使该部分可选?

修改

我忘了在我刚才意识到的问题中提到一些细节。所以我在Swift 4中使用了JSON Codable功能。所以如果失败就会抛出错误。

所以我基本上有以下代码。

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(isoMilisecondDateFormatter())

return try decoder.decode([Person].self, from: _people)

_people的示例JSON对象如下。

[
    {
        "name": "Bob",
        "born": "2018-01-21T20:11:20.057Z"
    },
    {
        "name": "Matt",
        "born": "2018-01-21T20:11:20Z"
    }
]

与我合作的API非常不一致,所以我必须处理多种类型的数据。

2 个答案:

答案 0 :(得分:7)

我创建了一个DateFormatter子类,尝试使用小数秒进行解析,然后回退到第二个内部的DateFormatter,它不进行解析。

imgactive

我保留了静态副本,因为它有点重。

class OptionalFractionalSecondsDateFormatter: DateFormatter {

     // NOTE: iOS 11.3 added fractional second support to ISO8601DateFormatter, 
     // but it behaves the same as plain DateFormatter. It is either enabled
     // and required, or disabled and... anti-required
     // let formatter = ISO8601DateFormatter()
     // formatter.timeZone = TimeZone(secondsFromGMT: 0)
     // formatter.formatOptions = [.withInternetDateTime ] // .withFractionalSeconds

    static let withoutSeconds: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(identifier: "UTC")
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssXXX"
        return formatter
    }()

    func setup() {
        self.calendar = Calendar(identifier: .iso8601)
        self.locale = Locale(identifier: "en_US_POSIX")
        self.timeZone = TimeZone(identifier: "UTC")
        self.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSXXX" // handle up to 6 decimal places, although iOS currently only preserves 2 digits of precision
    }

    override init() {
        super.init()
        setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setup()
    }

    override func date(from string: String) -> Date? {
        if let result = super.date(from: string) {
            return result
        }
        return OptionalFractionalSecondsDateFormatter.withoutSeconds.date(from: string)
    }
}

显然,您可以自定义它以满足您自己的格式需求。特别是,您应该根据典型的日期格式构建两个解析器(无论您是期望MOSTLY小数秒,还是大多数整秒)

答案 1 :(得分:2)

两个建议:

  • 使用包含毫秒的日期格式转换字符串。如果它返回server.name: kibana server.host: "0" elasticsearch.url: http://elasticsearch-5-6:9200 xpack.monitoring.ui.container.elasticsearch.enabled: false xpack.security.enabled: false ## Above I tired this - not working #elasticsearch.username: elastic #elasticsearch.password: changeme #xpack.monitoring.ui.container.elasticsearch.enabled: false #xpack.monitoring.ui.container.elasticsearch.enabled: true # Extra: ssl.verificationMode: false ,则将其转换为其他格式。

  • 使用正则表达式从字符串中删除毫秒:

    nil

修改

要与var dateString = "2018-01-21T20:11:20.057Z" dateString = dateString.replacingOccurrences(of: "\\.\\d+", with: "", options: .regularExpression) // -> 2018-01-21T20:11:20Z 一起使用,您必须编写自定义初始值设定项,指定Codable不起作用

dateDecodingStrategy
struct Foo: Decodable {
    let birthDate : Date
    let name : String

    private enum CodingKeys : String, CodingKey { case born, name }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        var rawDate = try container.decode(String.self, forKey: .born)
        rawDate = rawDate.replacingOccurrences(of: "\\.\\d+", with: "", options: .regularExpression)
        birthDate = ISO8601DateFormatter().date(from: rawDate)!
        name = try container.decode(String.self, forKey: .name)
    }
}