Open naoty opened 7 years ago
Hi @naoty, thanks for the great library and recent update!
I like this enhancement and was going to create a PR, but it was kind of tricky due to months not being a straight forward conversion. It's a WIP but this is what I have so far:
extension Date {
static func - (left: Date, right: Date) -> DateComponents {
return Calendar.current.dateComponents([.year, .month, .day, .hour, .minute, .second], from: right, to: left)
}
static func - (left: Date, right: Date) -> TimeInterval {
return left.timeIntervalSince(right)
}
}
extension TimeInterval {
func seconds(to component: Calendar.Component) -> Double {
switch component {
case .year:
return self / 31536000
case .month:
assertionFailure("Month component is not supported for conversion from seconds.")
return 0 //Fail
case .day:
return self.truncatingRemainder(dividingBy: 31536000) / 86400
case .hour:
return self.truncatingRemainder(dividingBy: 86400) / 3600
case .minute:
return self.truncatingRemainder(dividingBy: 3600) / 60
case .second:
return self
default:
assertionFailure("Specified component is not supported for conversion from seconds.")
return 0 //Fail
}
}
}
let date1 = Date()
let date2 = Date(timeIntervalSinceNow: -7200)
let component: DateComponents = date1 - date2
print(component) //year: 0 month: 0 day: 0 hour: 1 minute: 59 second: 59 isLeapMonth: false
let interval: TimeInterval = date1 - date2
print(interval.seconds(to: .year)) //0.000228
print(interval.seconds(to: .day)) //0.0833
print(interval.seconds(to: .hour)) //1.99
print(interval.seconds(to: .minute)) //59.99
print(interval) //7199.99
Any thoughts or suggestions on what to do about months or this approach in general?
Not my favorite API but we can do something like this also:
extension Date {
func minus(_ date: Date, to component: Calendar.Component) -> TimeInterval? {
guard component != .month else {
return Double(Calendar.current.dateComponents([.month], from: date, to: self).month!)
}
let seconds = timeIntervalSince(date)
switch component {
case .year:
return seconds / 31536000
case .day:
return seconds.truncatingRemainder(dividingBy: 31536000) / 86400
case .hour:
return seconds.truncatingRemainder(dividingBy: 86400) / 3600
case .minute:
return seconds.truncatingRemainder(dividingBy: 3600) / 60
case .second:
return seconds
default:
return nil
}
}
}
=> date1.minus(date2, to: .month)
@basememara Thanks!
As you said, the conversion between DateComponents
and TimeInterval
will be possible if we assume that 1 month always has 30 days and DST can be ignored.
I have obsoleted this conversion before at https://github.com/naoty/Timepiece/pull/30. So, I don't want to merge implementation on incorrect assumption.
Timepiece should use Calendar
API for calendrical calculation. Timepiece is a thin wrapper of Calendar
API. So, it cannot provide any APIs which Calendar
doesn't provide.
Your extension for Date
is good because this implementations are thin wrappers of Calendar
.