【问题标题】:Calculate how many n.months between two dates计算两个日期之间的 n.months
【发布时间】:2021-05-10 09:19:22
【问题描述】:

我想按月计算两个日期之间的距离:

问:start_date + n.months >= end_dates,变量n是什么?

start_date = Date.parse('2021-01-31')
end_date = Date.parse('2021-02-28')

## start_date + 1.months = 2021-02-28
## The answer 1 month, which is more clearable for human using
## Don't want to find the answer like 28 days or 0.93 month. (30 day a month)

首先我试着让每个月是 30.days,但是答案会对一些特殊的日期有一些偏差。每个月的日期都不一样,End of Feb month 上的日期总是问题。

然后我尝试安装像date_difftime_difference...这样的gem,但是没有方法可以做到这一点,大部分输出是28天而不是1个月。

为了简单的方法,我可以很容易地做迭代循环来找到n,比如:

start_date = Date.parse('2021-01-31')
end_date = Date.parse('2021-02-28')

def calc_diff(start_date, end_date)
  n = 0
  while start_date + n.months < end_date
     n += 1
  end
  n
end

有没有更好的方法来查找两个日期之间的 n 月份,但不使用循环?

谢谢。

【问题讨论】:

  • @AniketShivamTiwari 不,大多数答案将年份设置为每月 365 天和 30 天,或者不处理日期列(仅处理日期的月份和年份)。它会在月底(尤其是二月)引起问题。
  • 当我再次想到你的问题时,我看到你的目标是 more clearable for human using 这意味着从 31-1 到 29-2 是 1 个月,所以我想知道 29-2 到 31-3 是否也是仅仅 1 个月(人类的观点)还是 2 个月?

标签: ruby-on-rails ruby date


【解决方案1】:

我对问题的理解与下面的例子是一致的。我计算了Date 对象date1date2 之间的差异,其中date2 &gt;= date1

require 'date'
def months_between(date1, date2)
  12*(date2.yr - date1.yr) + date2.mon - date1.mon + date2.day > date1.day ? 1 : 0
end
months_between Date.new(2020, 1, 22), Date.new(2020, 3, 21) #=> 2
months_between Date.new(2020, 1, 22), Date.new(2020, 3, 22) #=> 2 
months_between Date.new(2020, 1, 22), Date.new(2020, 3, 23) #=> 3
months_between Date.new(2020, 1, 22), Date.new(2021, 3, 21) #=> 14
months_between Date.new(2020, 1, 22), Date.new(2021, 3, 22) #=> 14
months_between Date.new(2020, 1, 22), Date.new(2021, 3, 23) #=> 15

【讨论】:

    【解决方案2】:
    # find minimum n so that `start_date + n.months >= end_dates`
    def calc_diff(start_date, end_date)
     diff = (end_date.yday - start_date.yday) / 30
     return diff if start_date + diff.months >= end_date
     diff + 1
    end
    
    calc_diff(Date.parse('2021-01-31'), Date.parse('2021-02-28')) # 1
    calc_diff(Date.parse('2021-01-31'), Date.parse('2021-04-30')) # 3
    calc_diff(Date.parse('2021-01-31'), Date.parse('2021-05-31')) # 4
    calc_diff(Date.parse('2021-02-01'), Date.parse('2021-06-01')) # 4
    calc_diff(Date.parse('2021-02-01'), Date.parse('2021-06-02')) # 5
    
    

    【讨论】:

    • 感谢您的回答。我将尝试添加另一个条件来控制开始日期和结束日期是否是不同的年份。
    • 很好,我错过了那个案例。
    【解决方案3】:

    感谢@Cary 和@Lam 的回答。

    这是我找到n month的答案。

    # try to find the minimum n month between start_date and target_date
    def calc_diff(start_date, target_date)
      months_diff = (target_date.year * 12 + target_date.month) - (start_date.year * 12 + start_date.month)
    
      ## need to check the end of month because some special case
      ## start date: 2020-01-31 ; end date 2020-06-30
      ## the minimum n month must be 5
      ## another special case of Feb must consider (test case 15)
    
      if start_date.day > target_date.day && !((start_date == start_date.end_of_month || target_date.month == 2) && (target_date == target_date.end_of_month))
        months_diff = months_diff - 1
      end
      puts months_diff # it will show the minimum whole n month
    
      # the target_date will between inside
      # (start_date + months_diff.months) <= target_date < (start_date + (months_diff + 1).months) 
      (start_date + months_diff.months)..(start_date + (months_diff + 1).months) 
    end
    

    测试用例:

    ## test case 1
    ## 6/15 - 7/15  => n = 5
    calc_diff(Date.parse('2020-01-15'), Date.parse('2020-06-19'))
    
    ## test case 2
    ## 7/15 - 8/15  => n = 6
    calc_diff(Date.parse('2020-01-15'), Date.parse('2020-07-15')) 
    
    ## test case 3
    ## 5/15 - 6/15  => n = 4
    calc_diff(Date.parse('2020-01-15'), Date.parse('2020-06-01')) 
    
    ## test case 4 (special case)
    ## 6/30 - 7/31  => n = 5
    calc_diff(Date.parse('2020-01-31'), Date.parse('2020-06-30'))
    
    ## test case 5
    ## 7/30 - 8/30  => n = 4
    calc_diff(Date.parse('2020-04-30'), Date.parse('2020-07-31'))
    
    ## test case 6
    ## 6/30 - 7/30  => n = 2
    calc_diff(Date.parse('2020-04-30'), Date.parse('2020-06-30'))  
    
    ## test case 7
    ## 5/31 - 6/30  => n = 4
    calc_diff(Date.parse('2020-01-31'), Date.parse('2020-05-31'))
    
    ## test case 8
    ## 2/29 - 3/31  => n = 1
    calc_diff(Date.parse('2020-01-31'), Date.parse('2020-02-29'))
    
    ## test case 9
    ## 6/29 - 7/29  => n = 4
    calc_diff(Date.parse('2020-02-29'), Date.parse('2020-06-30'))
    
    ## test case 10
    ## 7/29 - 8/29  => n = 5
    calc_diff(Date.parse('2020-02-29'), Date.parse('2020-07-31'))
    
    ## test case 11
    ## 1/31 - 2/29  => n = 0
    calc_diff(Date.parse('2020-01-31'), Date.parse('2020-02-28'))
    
    ## test case 12
    ## 2/29 - 3/31  => n = 1
    calc_diff(Date.parse('2020-01-31'), Date.parse('2020-03-01'))
    
    ## test case 13
    ## 1/17 - 2/17  => n = 0
    calc_diff(Date.parse('2020-01-17'), Date.parse('2020-01-17'))
    
    ## test case 14
    ## 1/17 - 2/17  => n = 0
    calc_diff(Date.parse('2020-01-17'), Date.parse('2020-01-18'))
    
    ## test case 15 (special case)
    ## 1/30 - 2/29  => n = 1
    calc_diff(Date.parse('2019-12-30'), Date.parse('2020-02-28'))
    
    ## test case 16
    ## 2/29 - 3/30  => n = 2
    calc_diff(Date.parse('2019-12-30'), Date.parse('2020-02-29'))
    
    

    【讨论】:

      猜你喜欢
      • 2013-03-30
      • 1970-01-01
      • 2012-01-31
      • 1970-01-01
      • 1970-01-01
      • 2010-09-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多