Cha*_*ish 2 nsdateformatter ios swift
我有以下代码来解析ISO8601日期.
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
Run Code Online (Sandbox Code Playgroud)
问题有时候日期是这样的格式2018-01-21T20:11:20.057Z,有时候格式是这样的2018-01-21T20:11:20Z.
所以基本上它部分时间是.SSS毫秒级,有时则不是.
如何设置日期格式化程序以使该部分可选?
编辑
我忘了在我刚才意识到的问题中提到一些细节.所以我在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)
Run Code Online (Sandbox Code Playgroud)
_people以下是JSON对象的示例.
[
{
"name": "Bob",
"born": "2018-01-21T20:11:20.057Z"
},
{
"name": "Matt",
"born": "2018-01-21T20:11:20Z"
}
]
Run Code Online (Sandbox Code Playgroud)
我正在使用的API非常不一致,所以我必须处理多种类型的数据.
我创建了一个DateFormatter子类,尝试使用小数秒进行解析,然后回退到第二个不进行解析的内部DateFormatter.
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)
}
}
Run Code Online (Sandbox Code Playgroud)
我保持静态副本,因为它有点沉重.
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))")
Run Code Online (Sandbox Code Playgroud)
显然,您可以自定义它以满足您自己的格式需求.特别是,您应该根据典型的日期格式构建两个解析器(无论您是否期望MOSTLY小数秒,或大多数是整秒)
两个建议:
使用包含毫秒的日期格式转换字符串。如果返回,则将其nil转换为其他格式。
使用正则表达式从字符串中去除毫秒:
var dateString = "2018-01-21T20:11:20.057Z"
dateString = dateString.replacingOccurrences(of: "\\.\\d+", with: "", options: .regularExpression)
// -> 2018-01-21T20:11:20Z
Run Code Online (Sandbox Code Playgroud)编辑:
要使用它,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)
}
}
Run Code Online (Sandbox Code Playgroud)
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)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3068 次 |
| 最近记录: |