将两个日期之间的差值转换为Ruby中的iso8601持续时间(如果需要,还可以使用Rails)

oknrviil  于 12个月前  发布在  Ruby
关注(0)|答案(1)|浏览(178)

我想转换一对夫妇(开始_在,结束_在)到一个iso 8601的持续时间,只有一个周期设置。
举例来说:

  1. 2023/03/01:2023/03/10 =>P9 D(9天)而非P1 W2 D(1周2天)
  2. 2023/03/31:2023/04/28 =>P4W
  3. 2023/03/31:2023/04/29 =>P29 D(而不是P4 W1 D)
  4. 2023/03/31:2023/04/30 =>P1 M(因为03/31 + 1.month = 04/30)
  5. 2024/02/29:2025/02/28 =>P1 Y(因为2024年是闰年)
  6. 2024/02/29:2024/03/29 =>P1 M(因为是同一天,下个月)
    在模棱两可的情况下,我总是希望更大的时期获胜。
    举例来说:
  • 2023/01/31:2023/02/28 =>P1 M&P4 W都是正确的,但我更喜欢P1 M,因为月>周

我知道这是非常具体的,但也许有人有一个想法如何进行?这似乎是一个问题的人已经解决了.我在互联网上找到的唯一的资源是转换一个持续时间(秒)到iso 8601,但它不能为前面描述的一些特殊情况下(例如,第4个)工作.

46qrfjad

46qrfjad1#

我会从计算两个日期之间的(整)天差开始:

d = (to_date - from_date).to_i

字符串
如果其他方法都失败了,我们就用这个作为PdD

无论月份或闰年,周总是7天。我们可以通过divmod确定周差:

w, r = d.divmod(7)


如果余数r为零,则这两个日期相隔 * 正好 * w周,或PwW

由于闰年和闰月有不同的天数,我会对剩下的两种情况采取不同的方法。我会通过以下方式计算日期之间的完整月份的近似数量:(30.436875是包含闰年的average number of days in a month

m = (d / 30.436875).round


然后检查这个值是否恰好是精确匹配:

from_date.next_month(m) == to_date


如果是,则有PmM

多年来,我一直采取类似的方法:

y = m / 12


检查通过:

from_date.next_year(y) == to_date


如果为真,则给出PyY

总结

一切都在一个方法中:(纯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"

相关问题