【问题标题】:Find number of months between two Dates in Ruby on Rails在 Ruby on Rails 中查找两个日期之间的月数
【发布时间】:2012-03-14 18:38:13
【问题描述】:

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

【问题讨论】:

标签: ruby-on-rails ruby date ruby-on-rails-3.1


【解决方案1】:

如果你想要真正的月份,那么你必须考虑,下一个代码会计算这个。

# get the real years between date, it consider the months and days
def years_between_dates(since_date, until_date)
  years = until_date.year - since_date.year
  if (until_date.month < since_date.month) ||
     (until_date.month == since_date.month && since_date.day > until_date.day)
    years -= 1
  end
  years
end

# Get the months between dates, it consider the days
def difference_between_dates_in_months(since_date, until_date)
  months = (years_between_dates(since_date, until_date) * 12)
  until_month = until_date.month
  since_month = since_date.month

  if until_month > since_month
    months += since_month - until_month
  elsif until_month < since_month
    months += 12 - since_month + until_month
  end

  months -= 1 if(since_date.day > until_date.day)

  months
end

【讨论】:

    【解决方案2】:

    这个怎么样?我发现它很干净

    ((date2 - date1) / 1.month).round
    

    【讨论】:

      【解决方案3】:

      任何情况的解决方案

      (date1..date2).map { |date| date.strftime('%m.%Y') }.uniq.size
      

      【讨论】:

        【解决方案4】:

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

        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
        

        【讨论】:

          【解决方案5】:

          这是一个暴力破解变体:

          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

          【讨论】:

            【解决方案6】:

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

            【讨论】:

            • 非常好的解决方案!干净、简单,甚至可以跨年工作——即 2018 年 2 月至 2017 年 12 月之间的月份范围。
            • 需要考虑小时、分钟和秒 ((date2 - date1).to_f / 60 / 60 / 24 / 365 * 12).round
            • @scarver2 你从计算中得到的数字很离谱。我们所做的只是将几天转换为几个月,它并不是非常准确,因为它假设每月有 30.4167 天,但它非常接近,然后无论如何都会四舍五入。
            【解决方案7】:

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

            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
            【解决方案8】:
            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
            

            【讨论】:

            • 如果您能详细说明一下会有用吗?一般来说,SO 的答案包括对代码的作用以及为什么它作为解决方案起作用的解释
            【解决方案9】:
            start_date = Date.today
            end_date   = Date.today+90
            months = (end_date.month+end_date.year*12) - (start_date.month+start_date.year*12)
            
            //months = 3
            

            【讨论】:

              【解决方案10】:

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

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

              【讨论】:

              • 回到最初的问题,您可以将天数相加(就像您对第一个天做的那样)并取总和的平均值。
              【解决方案11】:

              我发现的另一个解决方案(基于此处已发布的解决方案构建)适用于如果您希望结果包含一个月的分数。例如距离是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...
              

              【讨论】:

              • 如果您希望只显示实际经过的月份,请尝试用地板绕圈
              【解决方案12】:

              更准确的答案是考虑远方的日子。

              例如,如果您考虑到28/4/20001/5/2000 的月份距离是0 而不是1,那么您可以使用:

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

              【讨论】:

              • 例如用于计算某人收到工资的次数总是在每月的 22 日
              【解决方案13】:

              试试看

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

              【讨论】:

              • irb&gt;Time.at("2014-10-01".to_time - "2014-12-01".to_time).month =&gt; 10(我放弃了格式化……想不通)
              • 即使您使用 Date 对象,@toby-joiner 的评论仍然是正确的。原因是 - 是 -2 个月,但 Time.at(-2months).month 给出的月份相当于 -2(即 -2 % 12 #=> 10)。如果两个月相继出现并且相隔不到一年,您建议的方法将有效,但如果两个月的顺序相反(例如 10 月 - 12 月)或两个月相隔一年以上,则该方法将失败。
              • 我喜欢它背后的想法,但如果日期跨度变得非常长,那就不正确了。在我的Date.new(2014, 10, 31), Date.new(1997, 4, 30) 示例中,我收到了 213 个月而不是 210 个月。原因是1.month.seconds 是 30 天的秒数,而不是一个月的平均秒数。投反对票,以便其他人保持无错误。
              • 如果您选择的月份不是 30 天,这将不起作用
              • 这个方法不太准确。
              【解决方案14】:
              (date2.year * 12 + date2.month) - (date1.year * 12 + date1.month)
              

              更多信息http://www.ruby-forum.com/topic/72120

              【讨论】:

              • 此解决方案不考虑天数。 28/4/2000 和 1/5/2000 之间的月数不是 1 个月,而是 0。
              • 我需要一个而不考虑天数,所以这对我有用。 +1
              • 这个好答案的另一个变体:(12 * (date2.year - date1.year) + date2.month - date1.month).abs if date1 &amp;&amp; date2
              • 如果我们尝试获取 2 年之间的月份,即 2017-05-20 到 2018-05-20,它显示的月数不正确。输出显示 1 个月。
              • @CuriousDeveloper 它显示正确的月份,即 12
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-03-23
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多