首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Swift DateFormatter可选毫秒

Swift DateFormatter可选毫秒
EN

Stack Overflow用户
提问于 2018-01-21 19:56:57
回答 2查看 8.1K关注 0票数 8

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

代码语言:javascript
复制
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毫秒部分,而其他时候则没有。

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

编辑

我忘了在我刚刚意识到的问题中提到一些细节。所以我在Swift 4中使用了JSON可编码特性,所以如果它失败了,它就会抛出一个错误。

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

代码语言:javascript
复制
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对象示例如下。

代码语言:javascript
复制
[
    {
        "name": "Bob",
        "born": "2018-01-21T20:11:20.057Z"
    },
    {
        "name": "Matt",
        "born": "2018-01-21T20:11:20Z"
    }
]

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-01-21 20:06:03

有两项建议:

  • 使用日期格式(包括毫秒)转换字符串。如果它返回nil,则将其转换为其他格式。
  • 用正则表达式从字符串中删除毫秒: var dateString = "2018-01-21T20:11:20.057Z“dateString = dateString.replacingOccurrences(of:"\.\d+",with:”\.\d+“,options:.regularExpression) // -> 2018-01-21T20:11:20Z

编辑:

要将它与Codable一起使用,您必须编写自定义初始化程序,指定dateDecodingStrategy不工作。

代码语言:javascript
复制
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)
    }
}
代码语言:javascript
复制
let jsonString = """
[{"name": "Bob", "born": "2018-01-21T20:11:20.057Z"}, {"name": "Matt", "born": "2018-01-21T20:11:20Z"}]
"""

do {
    let data = Data(jsonString.utf8)
    let result = try JSONDecoder().decode([Foo].self, from: data)
    print(result)
} catch {
    print("error: ", error)
}
票数 9
EN

Stack Overflow用户

发布于 2018-05-10 20:32:35

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

代码语言:javascript
复制
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)
    }
}

因为它有点重,所以我在附近保存了一个静态副本。

代码语言:javascript
复制
extension DateFormatter {
    static let iso8601 = OptionalFractionalSecondsDateFormatter()
}

let str1 = "2018-05-10T21:41:30Z"
let str2 = "2018-05-10T21:41:30.54634Z"
let d1 = DateFormatter.iso8601.date(from: str1)
let d2 = DateFormatter.iso8601.date(from: str2)
DDLogInfo("d1 is \(String(describing: d1))")
DDLogInfo("d2 is \(String(describing: d2))")

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

票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48371082

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档