我想将一对(START_AT,END_AT)转换为ISO 8601持续时间,只设置了1个周期.

例如:

  1. 2023/03/01:2023/03/10=>P9D(9天),而不是P1W2D(1周2天)
  2. 2023/03/31:2023/04/28=>P4W
  3. 2023/03/31:2023/04/29=>P29D(而不是P4W1D)
  4. 2023/03/31:2023/04/30=>P1M(因为03/31+1.月=04/30)
  5. 2024/02/29:2025/02/28=>P1Y(因为2024是闰年)
  6. 2024/02/29:2024/03/29=>P1M(因为是下个月的同一天)

在含糊其辞的情况下,我总是希望更大的时段获胜.

例如:

  • 2023/01/31:2023/02/28=>P1M和amp;P4W都是正确的,但我更喜欢P1M,因为月份和周

我知道这真的很具体,但也许有人对如何进行有一个 idea ?这似乎是一个人们已经解决的问题.我在互联网上找到的唯一资源是将持续时间(以秒为单位)转换为iso 8601,但它不能用于前面描述的一些特殊情况(例如,第四种情况).

推荐答案

Days

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

d = (to_date - from_date).to_i

如果一切都失败了,我们会求助于这个PdD.

Weeks

周始终是7天,无论是月份还是闰年.我们可以通过divmod来确定周差值:

w, r = d.divmod(7)

如果余数r为零,则两个日期相隔exactlyw周,或PwW.

Months

由于闰年和月份的天数不同,我会对剩下的两个 case 采取不同的方法.我将通过以下方式计算这两个日期之间的大约整月数:

m = (d / 30.436875).round

然后判断此值是否恰好完全匹配:

from_date.next_month(m) == to_date

如果是这样的话,我们有PmM个.

Years

多年来,我都会采取类似的方式:

y = m / 12

判断通过:

from_date.next_year(y) == to_date

PyY如果是真的

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"

Ruby-on-rails相关问答推荐

如何在Rails中创建没有字符串的查询

Ruby on Rails 身份验证:设计注册不起作用

Rails 7 - 富文本不显示附加的媒体内容

ActiveRecord 包括.指定包含的列

来自控制台的 ActionCable.server.broadcast

Rails 模型.有效吗?刷新自定义错误并错误地返回 true

ActiveRecord 回调列表

twitter bootstrap下拉突然不起作用

模型验证中的 Rails 国际化 (I18n):可能与否?

如何使用失败try 次数使设计可锁定

Rails:参数太少

Rails - 生产模式下的错误

我可以将默认值传递给 rails 生成迁移吗?

在 RoR 中引用同一个表的多个外键

Ruby 根据属性在数组中查找并返回对象

将 Rails 服务器绑定到 0.0.0.0 能给你带来什么?

为什么不对 Rspec + Selenium 使用共享的 ActiveRecord 连接?

如何在 Rails 4 中测试控制器关注点

如何测试也定义为辅助方法的 ApplicationController 方法?

为什么 Mac OS X 带有 ruby​​/rails?