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?
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:
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)
}