在Ruby on Rails中查找两个日期之间的月数


95

我有两个Ruby on Rails DateTime对象。如何找到它们之间的月数?(请记住,它们可能属于不同的年份)


5
提出了质疑,并在这里找到答案:stackoverflow.com/questions/5887756/...
蒂姆·巴斯

感谢您指出。我搜寻了但没有偶然发现。
phoenixwizard'2


我宁愿数字链接。我是通过Massimiliano Peluso提到的方法完成的
phoenixwizard,2012年

只要我给它供您参考..谢谢..反正
sangeethkumar

Answers:


179
(date2.year * 12 + date2.month) - (date1.year * 12 + date1.month)

有关更多信息,请访问http://www.ruby-forum.com/topic/72120


25
此解决方案不会考虑几天。2000
4

15
我需要一个不用考虑几天的东西,所以对我有用。+1
WattsInABox

1
这个好答案的另一个变种:(12 * (date2.year - date1.year) + date2.month - date1.month).abs if date1 && date2
Stepan Zakharov

如果我们尝试获取2年(即2017-05-20至2018-05-20)之间的月份,则显示的月份数不正确。输出显示1个月。
Curious Developer

1
@CuriousDeveloper显示正确的月份,即12
ts

40

一个更准确的答案将考虑距离的天数。

例如,如果你考虑到从一个月的距离28/4/20001/5/20000不是1,那么你可以使用:

(date2.year - date1.year) * 12 + date2.month - date1.month - (date2.day >= date1.day ? 0 : 1)

1
例如,为了计算某人总是
Matthias

15

尝试一下

((date2.to_time - date1.to_time)/1.month.second).to_i

irb>Time.at("2014-10-01".to_time - "2014-12-01".to_time).month => 10 (我放弃格式化...
无法解决

即使使用Date对象,@ toby-joiner的注释仍然正确。原因是<October>-<December>是-2个月,但是Time.at(-2months).month给出的月份等价于-2(即-2%12#=> 10)。如果两个月紧接着相隔不到一年,则建议的方法将起作用,但是如果两个月的顺序相反(例如,十月至十二月),或者两个月相隔一年以上,则该方法将失败。
elreimundo 2015年

2
我喜欢这个主意,但如果日期跨度真的很长,那是不正确的。以我为例,Date.new(2014, 10, 31), Date.new(1997, 4, 30)我收到了213个月而不是210个月。这样做的原因是1.month.seconds30天的秒数,而不是一个月的平均秒数。拒绝投票,以便其他人保持无错误。
乔·埃弗特

1
如果您选择不是30天的月份,则无法使用
dima

2
这种方法不是很准确。
vagabond

9

您可以将问题改写为“日期的月份的开始之间有多少第一天”,然后使用功能样式的数据转换:

(date1.beginning_of_month...date2.beginning_of_month).select { |date| date.day == 1 }.size

回到原始问题,您可以将天数相加(就像处理第一个问题一样),然后取总和的平均值。
乔·埃弗特

9

假设两个都是日期: ((date2 - date1).to_f / 365 * 12).round 简单。


非常好的解决方案!整洁,简单,甚至可以多年使用,即从2018年2月到2017
。– jeffdill2 '18年

1
需要考虑数小时,数分钟和数秒 ((date2 - date1).to_f / 60 / 60 / 24 / 365 * 12).round
scarver2 '18

1
@ scarver2您从计算中获得的数字远未达到。我们正在做的只是花几天时间并将其转换成几个月,这并不是非常准确,因为它假设每月30.4167天,但是它非常接近,然后无论如何都会四舍五入。
Andreykul


2

我发现的另一个解决方案(已经建立在这里发布的解决方案的基础上)是为了让您将结果包括一个月的零头。例如,距离为1.2 months

((date2.to_time - date1.to_time)/1.month.second).round(1) #Tenth of a month Ex: 1.2
((date2.to_time - date1.to_time)/1.month.second).round(2) #Hundreth, ex: 1.23 months
etc...

1
如果您只想显示实际上已过去的月份,请尝试用地板拉紧轮
Matthias

2
def difference_in_months(date1, date2)
  month_count = (date2.year == date1.year) ? (date2.month - date1.month) : (12 - date1.month + date2.month)
  month_count = (date2.year == date1.year) ? (month_count + 1) : (((date2.year - date1.year - 1 ) * 12) + (month_count + 1))
  month_count
end

1
如果您可以详细说明这一点,将很有用?通常,关于SO的答案包括有关代码的作用及其为何作为解决方案的解释
单一实体

1

我需要两个日期之间的确切月份数(包括小数),并为此编写了以下方法。

def months_difference(period_start, period_end)
  period_end = period_end + 1.day
  months = (period_end.year - period_start.year) * 12 + period_end.month - period_start.month - (period_end.day >= period_start.day ? 0 : 1)
  remains = period_end - (period_start + months.month)

  (months + remains/period_end.end_of_month.day).to_f.round(2)
end

如果比较一下,例如9月26日至9月26日(同一天),我将其计算为1天。如果不需要,可以删除方法的第一行:period_end = period_end + 1.day

它通过以下规格:

expect(months_difference(Date.new(2017, 8, 1), Date.new(2017, 8, 31))).to eq 1.0
expect(months_difference(Date.new(2017, 8, 1), Date.new(2017, 8, 30))).to eq 0.97
expect(months_difference(Date.new(2017, 8, 1), Date.new(2017, 10, 31))).to eq 3.0
# Overlapping february (28 days) still counts Feb as a full month
expect(months_difference(Date.new(2017, 1, 1), Date.new(2017, 3, 31))).to eq 3.0
expect(months_difference(Date.new(2017, 2, 10), Date.new(2017, 3, 9))).to eq 1.0
# Leap year
expect(months_difference(Date.new(2016, 2, 1), Date.new(2016, 2, 29))).to eq 1.0

顺便说一句,它依赖于Rails的ActiveSupport
mtrolle's

1

这是一个蛮力强迫的变种:

date1 = '2016-01-05'.to_date
date2 = '2017-02-27'.to_date
months = 0

months += 1 while (date2 << (count+1)) >= date1
puts months # => 13

date2 必须始终大于 date1


0

这是另一种方法。这将有助于计算两个日期之间的整个月数

def months_difference(date_time_start, date_time_end)
  curr_months = 0
  while (date_time_start + curr_months.months) < date_time_end
    curr_months += 1
  end
  curr_months -= 1 if (date_time_start + curr_months.months) > date_time_end
  curr_months.negative? ? 0 : curr_months
end
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.