如何确定今天的日期是否在日期范围内?

89

我有一个带有start_timeend_time的事件,并想检查事件是否正在进行中。那就是要检查今天的日期是否在两个日期之间。

你会如何在函数中实现这个功能?

9个回答

259
在 Ruby 1.9.2 中,=== 不起作用,我会收到一个错误:
irb(main):019:0> (Time.now .. (Time.now+1)) === Time.now
TypeError: can't iterate from Time
    from (irb):19:in `each'
    from (irb):19:in `include?'
    from (irb):19:in `include?'
    from (irb):19:in `==='
    from (irb):19
    from /opt/ruby192/bin/irb:12:in `<main>'

请使用#cover?代替:

irb(main):002:0> (Time.now..Time.now+4).cover?(Time.now)
=> true
irb(main):003:0> (Time.now..Time.now+4).cover?(Time.now+10)
=> false

2
这就是我喜欢 Ruby 的原因,你总能发现另一个很棒的方法来完成工作! - daniel
很好,正是我需要的。我不知道cover?方法。 - Ryan Rebo
2
这也适用于 Date 类型 (Date.yesterday..Date.tomorrow).cover?(Date.today) => true - Amit Patel
1
Ruby很美丽!谢谢! - Ele
=== works fine in Ruby 1.9.2. You just forgot the .to_i - DigitalRoss
我本来以为 my_date.in?(my_range) 可以工作,但显然它做了其他的事情,而在 Ruby 2.3/Rails 5 中 cover? 却可以正常工作。 - Cyril Duchon-Doris

66

使用 ===


实际上,有一个运算符可以做到这一点。创建一个 Range 对象,然后使用 === 运算符将 Time 对象与其进行比较。

start   = Time.now.to_i

range   = start..(start + 2)
inside  = start + 1
outside = start + 3        # ok, now...

range === inside  # true
range === outside # false


更新post-comment-flood:这个版本在任何地方都能正常工作。(在Rails、Ruby 1和Ruby 2中)早期的irb示例也可以正常工作,但交互式示例在某些实验中并未始终正确重现。这个示例更容易复制粘贴。


1
无法在 Ruby 1.8.7 上的 Rails 3 中工作,因此我更喜欢 @heathd 的答案。 - Sandro L
3
在 Ruby 2.0 中出现了 TypeError: Can't iterate from time 错误。 - Pencilcheck
3
这里有什么问题?像其他两个评论一样,我也按照这个代码尝试过,但出现了相同的错误。为什么有19个人给这个答案点赞?它以前有用过吗?heathd的答案对我有效。 - Ryan
也不适用于我。也许在旧版本中可以,但现在似乎不能了。 - stuckj
3
请注意:为了使其正常工作,您需要将日期转换为.to_i然后使用===来查看它们是否在范围内。在我看来,.coverage?对于日期是更好的解决方案。 - erroric
显示剩余5条评论

40
如果您正在使用Rails,您可以使用TimeWithZone#between?。然后您会得到如下内容:
> start_time = Time.zone.parse('12pm')      => Thu, 26 Jul 2012 12:00:00 EDT -04:00
> end_time = start_time + 1.hour            => Thu, 26 Jul 2012 13:00:00 EDT -04:00
> inside = Time.zone.parse('12:30pm')       => Thu, 26 Jul 2012 12:30:00 EDT -04:00
> outside = Time.zone.parse('1:30pm')       => Thu, 26 Jul 2012 13:30:00 EDT -04:00
> inside.between?(start_time, end_time)     => true
> outside.between?(start_time, end_time)    => false

21

由于日期类包含Comparable模块,每个日期对象都有一个between?方法。

require 'date'

today           = Date.today
tomorrow        = today + 1
one_month_later = today >> 1

tomorrow.between?(today, one_month_later) # => true

1
课程时间也是重要的。 - adass
1
这比被接受的答案更易读。 +1 使用 Ruby 的能力正确 :) - thutt

6

summary

  d1      = DateTime.parse('2018/04/01')
  d2      = DateTime.parse('2018/04/29')
  outside = DateTime.parse('2018/04/30')
  inside  = DateTime.parse('2018/04/15')

  # include?
  (d1...d2).include?(d1)      # true
  (d1...d2).include?(d2)      # false
  (d1...d2).include?(outside) # false
  (d1...d2).include?(inside)  # true

  (d1..d2).include?(d1)      # true
  (d1..d2).include?(d2)      # true
  (d1..d2).include?(outside) # false
  (d1..d2).include?(inside)  # true

  # ===
  (d1...d2) === d1      # true
  (d1...d2) === d2      # false
  (d1...d2) === outside # false
  (d1...d2) === inside  # true

  (d1..d2) === d1      # true
  (d1..d2) === d2      # true
  (d1..d2) === outside # false
  (d1..d2) === inside  # true

  # cover?
  (d1...d2).cover?(d1)      # true
  (d1...d2).cover?(d2)      # false
  (d1...d2).cover?(outside) # false
  (d1...d2).cover?(inside)  # true

  (d1..d2).cover?(d1)      # true
  (d1..d2).cover?(d2)      # true
  (d1..d2).cover?(outside) # false
  (d1..d2).cover?(inside)  # true

  # between?
  d1.between?(d1, d2)       # true
  d2.between?(d1, d2)       # true
  outside.between?(d1, d2)  # false
  inside.between?(d1, d2)   # true

5
如果您正在使用Rails,您可以尝试以下方法:
ruby-1.8.7-p299 :015 > a = DateTime.now
 => Fri, 02 Dec 2011 11:04:24 -0800 
ruby-1.8.7-p299 :016 > (a.beginning_of_day..a.end_of_day).include_with_range? a
 => true 
ruby-1.8.7-p299 :017 > (a.beginning_of_day..a.end_of_day).include_with_range? a+10.days
 => false 
ruby-1.8.7-p299 :018 > (a.beginning_of_day..a.end_of_day).include_with_range? a+25.hours
 => false 
ruby-1.8.7-p299 :019 > (a.beginning_of_day..a.end_of_day).include_with_range? a+2.hours
 => true 

注意:我只是使用了beginning_of_dayend_of_day来提供一个简单的范围。重要的部分是include_with_range?方法在一个范围内。

看起来 ActiveSupport 提供的 Range#include_with_range? 方法只是简单地使用 #include? 添加了检查一个范围是否包含另一个范围的功能,例如:(1..5).include?(1..5)。除此之外,它的行为与 Ruby 的本地 include?方法完全相同。由于您的参数不是另一个范围,因此这个 ActiveSupport 扩展没有任何区别。无论如何,您应该只调用 include? 而不是 include_with_range?,因为 include_with_range? 只是 include? 的别名(使用 alias_method_chain)。 - Tyler Rick
a = DateTime.now; (a.beginning_of_day..a.end_of_day).include_with_range?(a) 在我尝试在Rails 3.2.8和ruby-1.9.3-p194的控制台中运行时返回false(而不是true)。然而,(a.beginning_of_day..a.end_of_day).cover?(a) 返回true,所以我会使用它。 - Tyler Rick
一个有效的观点。不确定为什么我选择使用include_with_range,因为这不是将范围与范围进行比较的情况。可能是某种脑肿瘤。很好地发现了问题,谢谢@TylerRick。@heathd的答案确实是最好的。 - sorens

4

使用Ruby检查当前日期是否在两个日期之间。

currentDate = DateTime.now
start_date = "2017-03-31"
end_date = "2018-03-31"
currentDate.between?(start_date, end_date)

**Out Put Will be** true or false

4
如果它们是时间戳:
def in_progress?
  (start_time..end_time).include?(Time.now)
end
如果它们是时间戳:

对于我在1.9.2上,这会出现一个错误 TypeError: can't iterate from Time - Benjamin Oakes

0
这可能会帮助到某些人。
Ruby只能理解格式为以下形式的日期,以进行计算:
.strftime('%Y/%m/%d')

不是

.strftime('%d/%m/%Y')

如果你用错误的方式去做,它会给你一个错误的结果。

现在这个功能已经完美了。

   if tmpadd182.between?(datebeginingmonth, dateendofmonth)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接