3

I am trying to convert the eBay timeLeft to a TimeInterval. The timeLeft value is returned from eBay as. Apparently the value is ISO 8601 (see link and question below). I believe the timeLeft is an interval relative to when I made the API call.

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

From eBay reference:

searchResult.item.sellingStatus.timeLeft    

Time left before the listing ends. The duration is represented in the ISO 8601 duration format (PnYnMnDTnHnMnS). For listings that have ended, the time left is PT0S (zero seconds). See the "duration" type for information about this time format.

P10DT4H38M16S

Such that eBay Time Left Format:

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

I can format the string as follows, but this solution doesn't give me the ability process based on the attributes of the time left. For example. If the days are 0, I dont want to show "0 days". Ebay API ISO 8601 Date to timestamp

My specific question, is there a way to get this timeLeft into a swift 3.0 DateInterval so that I can use the functions native to the variable type?

Community
  • 1
  • 1
Jacksonsox
  • 1,114
  • 15
  • 25

1 Answers1

1

I think eBay made a mistake in going with the duration field. It should state the start and end date of the auction to make things simpler. Date calculation is hard. I haven't gone through the whole API documentation yet, but just off the top of my mind:

  • What calendar does eBay use? Gregorian, Chinese, Persian, Buddhist? All have different concepts of day, month and year.
  • A month can last between 28 and 31 days. A year can be 365 or 366 days. How can you calculate how many seconds that a duration represents?

Having said that, here's a possible parser for the ISO 8601 duration string:

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)
}
Code Different
  • 90,614
  • 16
  • 144
  • 163
  • Thank you! This solution works perfectly. Here is the output of the timeLeft value relative to the endTime (which is actually a date). Looks like the values from eBay can be, or are, off by 1 second. `endDate from timeLeft 2017-04-02 02:34:03 +0000 and endTime 2017-04-02T02:34:04.000Z and formatted endTime 2017-04-02 02:34:04 +0000 endDate from timeLeft 2017-03-27 04:20:45 +0000 and endTime 2017-03-27T04:20:46.000Z and formatted endTime 2017-03-27 04:20:46 +0000` – Jacksonsox Mar 24 '17 at 04:12