【问题标题】:Swift - Retrieve timezone from ISO8601 date stringSwift - 从 ISO8601 日期字符串中检索时区
【发布时间】:2018-05-17 06:12:52
【问题描述】:

我有日期以这种格式保存在数据库中 - “yyyy-MM-dd'T'HH:mm:ssZ”。例如,“2018-05-17T11:15:00+0330”。时区各不相同,无论用户的本地时区是什么。

我想检索并显示像“2018 年 5 月 17 日 11.15AM”这样的日期,将日期/时间与保存时保持在同一时区。我该怎么做?

我试过了。

let dateString = "2018-05-17T11:15:00+0330"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
//formatter.timeZone = ???
print(formatter.date(from: dateString))

但是我得到了本地时区的 Date 对象,并将其转换为日期字符串也会显示我本地时区的日期。

在 Swift 中有这样的东西吗,https://stackoverflow.com/a/46216251/1373592

谢谢。

【问题讨论】:

    标签: swift


    【解决方案1】:

    你真正想做的是忽略时区。

    您可以从日期字符串中去掉最后 5 个字符,以一种格式对其进行解析,然后将其格式化为另一种格式:

    let dateString = "2018-05-17T11:15:00+0330"
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
    let date = formatter.date(from: String(dateString.dropLast(5)))! // note the stripping off here
    formatter.dateFormat = "MMMM d, yyyy hh.mma"
    print(formatter.string(from: date))
    

    请注意,您无法将该日期与其他日期进行比较,因为您已经剥离了它的时区。

    另外,SwiftDate 是一个类似于 JodaTime 的库。

    【讨论】:

    • 这给出了最终字符串的正确输出,但 date 位于错误的时区,如果需要与其他日期进行任何比较,您将得到意想不到的结果。
    • @rmaddy 是的,这是真的。添加了警告。
    【解决方案2】:

    这是对TimeZone 的一个小扩展,我刚刚开始。您可以使用它从 ISO8601 日期字符串创建 TimeZone。它将以下列格式处理字符串中的时区:

    • Z(UTC 时间)
    • +/-HH
    • +/-HHmm
    • +/-HH:mm

    这是扩展名:

    extension TimeZone {
        init?(iso8601: String) {
            let tz = iso8601.dropFirst(19) // remove yyyy-MM-ddTHH:mm:ss part
            if tz == "Z" {
                self.init(secondsFromGMT: 0)
            } else if tz.count == 3 { // assume +/-HH
                if let hour = Int(tz) {
                    self.init(secondsFromGMT: hour * 3600)
                    return
                }
            } else if tz.count == 5 { // assume +/-HHMM
                if let hour = Int(tz.dropLast(2)), let min = Int(tz.dropFirst(3)) {
                    self.init(secondsFromGMT: (hour * 60 + min) * 60)
                    return
                }
            } else if tz.count == 6 { // assime +/-HH:MM
                let parts = tz.components(separatedBy: ":")
                if parts.count == 2 {
                    if let hour = Int(parts[0]), let min = Int(parts[1]) {
                        self.init(secondsFromGMT: (hour * 60 + min) * 60)
                        return
                    }
                }
            }
    
            return nil
        }
    }
    

    还有一个测试:

    print(TimeZone(iso8601: "2018-05-17T11:15:00+0330"))
    

    您可以结合此解析和格式化,以便最终结果在原始时区中。

    let dateString = "2018-05-17T11:15:00+0330"
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
    formatter.locale = Locale(identifier: "en_US_POSIX")
    if let date = formatter.date(from: dateString), let tz = TimeZone(iso8601: dateString) {
        let newFmt = DateFormatter()
        newFmt.dateStyle = .medium
        newFmt.timeStyle = .short
        newFmt.timeZone = tz
        let newString = newFmt.string(from: date)
        print(newString)
    }
    

    【讨论】:

    • 我认为这处理负偏移不正确。例如。 “2020-01-01T09:15:00-02:15”从 GMT 产生 -6300 秒而不是 -8100 秒,因为此代码将小时部分视为负数,而将分钟部分视为正数。
    猜你喜欢
    • 2023-03-18
    • 2014-11-14
    • 2018-04-06
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多