Days
我会从计算两个日期之间的(整日)天数开始:
d = (to_date - from_date).to_i
如果一切都失败了,我们会求助于这个Pd
D.
Weeks
周始终是7天,无论是月份还是闰年.我们可以通过divmod
来确定周差值:
w, r = d.divmod(7)
如果余数r
为零,则两个日期相隔exactlyw
周,或Pw
W.
Months
由于闰年和月份的天数不同,我会对剩下的两个 case 采取不同的方法.我将通过以下方式计算这两个日期之间的大约整月数:
m = (d / 30.436875).round
然后判断此值是否恰好完全匹配:
from_date.next_month(m) == to_date
如果是这样的话,我们有Pm
M个.
Years
多年来,我都会采取类似的方式:
y = m / 12
判断通过:
from_date.next_year(y) == to_date
Py
Y如果是真的
Conclusion
在一个方法中实现所有功能:(纯Ruby,无Rails)
def duration(from_date, to_date)
d = (to_date - from_date).to_i # number of days
m = (d / 30.436875).round # number of months
y = m / 12 # number of years
w, r = d.divmod(7) # number of weeks
return "P#{y}Y" if from_date.next_year(y) == to_date
return "P#{m}M" if from_date.next_month(m) == to_date
return "P#{w}W" if r == 0
"P#{d}D"
end
例如:
duration(Date.parse('2023/03/01'), Date.parse('2023/03/10')) #=> "P9D"
duration(Date.parse('2023/03/31'), Date.parse('2023/04/28')) #=> "P4W"
duration(Date.parse('2023/03/31'), Date.parse('2023/04/29')) #=> "P29D"
duration(Date.parse('2023/03/31'), Date.parse('2023/04/30')) #=> "P1M"
duration(Date.parse('2024/02/29'), Date.parse('2025/02/28')) #=> "P1Y"
duration(Date.parse('2024/02/29'), Date.parse('2024/03/29')) #=> "P1M"
duration(Date.parse('2023/01/31'), Date.parse('2023/02/28')) #=> "P1M"