将 eBay timeLeft 转换为 Swift 3.0 TimeInterval

Convert eBay timeLeft to Swift 3.0 TimeInterval

我正在尝试将 eBay timeLeft 转换为 TimeInterval。 timeLeft 值是从 eBay 返回的。显然该值是 ISO 8601(请参阅 link 和下面的问题)。我相信 timeLeft 是相对于我进行 API 调用的时间间隔。

http://developer.ebay.com/Devzone/finding/CallRef/findItemsByKeywords.html

来自 eBay 参考:

searchResult.item.sellingStatus.timeLeft    

距离列表结束还有时间。持续时间以 ISO 8601 持续时间格式 (PnYnMnDTnHnMnS) 表示。对于已经结束的列表,剩余时间为 PT0S(零秒)。有关此时间格式的信息,请参阅 "duration" 类型。

P10DT4H38M16S

eBay 剩余时间格式:

P   = Pending (INDICATOR OF ISO8601 DURATION)
1Y  = 1 Year
2M  = 2 Months
2D  = Two Days
T   = Time Separator (M is ambiguous)
16H = Sixteen hours
2M  = Two minutes
40S = Forty seconds

我可以按如下方式格式化字符串,但是这个解决方案没有给我基于剩余时间属性的能力处理。例如。如果天数为 0,我不想显示“0 天”。 Ebay API ISO 8601 Date to timestamp

我的具体问题,有没有办法让这个 timeLeft 变成 swift 3.0 DateInterval,这样我就可以使用变量类型的原生函数?

我认为 eBay 在使用持续时间字段时犯了一个错误。它应该说明拍卖的开始和结束日期,以使事情变得更简单。日期计算很难。我还没有浏览完整个 API 文档,但我的脑海里浮现出这样的想法:

  • eBay 使用什么日历?公历、中国、波斯、佛教?都有不同的日月年概念。
  • 一个月可以持续 28 到 31 天。一年可以是 365 天或 366 天。如何计算持续时间代表多少秒?

话虽如此,这里有一个可能的 ISO 8601 持续时间字符串解析器:

struct ISO8601Duration {
    var years = 0
    var months = 0
    var weeks = 0
    var days = 0
    var hours = 0
    var minutes = 0
    var seconds = 0

    init?(string: String) {
        guard string.hasPrefix("P") else {
            return nil
        }

        let regex = try! NSRegularExpression(pattern: "(\d+)(Y|M|W|D|H|S)|(T)", options: [])
        let matches = regex.matches(in: string, options: [], range: NSMakeRange(0, string.utf16.count))
        guard matches.count > 0 else {
            return nil
        }

        var isTime = false
        let nsstr = string as NSString
        for m in matches {
            if nsstr.substring(with: m.range) == "T" {
                isTime = true
                continue
            }

            guard let value = Int(nsstr.substring(with: m.rangeAt(1))) else {
                return nil
            }
            let timeUnit = nsstr.substring(with: m.rangeAt(2))

            switch timeUnit {
            case "Y":
                self.years = value
            case "M":
                if !isTime {
                    self.months = value
                } else {
                    self.minutes = value
                }
            case "W":
                self.weeks = value
            case "D":
                self.days = value
            case "H":
                self.hours = value
            case "S":
                self.seconds = value
            default:
                return nil
            }
        }
    }

    func endDate(from date: Date = Date()) -> Date? {
        var components = DateComponents()
        components.year = self.years
        components.month = self.months
        components.day = self.weeks * 7 + self.days
        components.hour = self.hours
        components.minute = self.minutes
        components.second = self.seconds

        return Calendar(identifier: .gregorian).date(byAdding: components, to: date)
    }
}

let timeLeft = "P1DT13H24M17S"
if let duration = ISO8601Duration(string: timeLeft),
    let endDate = duration.endDate()
{
    print(endDate)
}