如何在Rails中计算下一个工作日?

Sub*_*Rao 10 ruby ruby-on-rails

如何计算Rails中的下一个和上一个工作日?

Fel*_*Ogg 18

据我了解,这是你在找什么?(测试过)

require 'date'
def next_business_day(date)
  skip_weekends(date, 1)
end    

def previous_business_day(date)
  skip_weekends(date, -1)
end

def skip_weekends(date, inc = 1)
  date += inc
  while date.wday == 0 || date.wday == 6
    date += inc
  end   
  date
end
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式测试它:

begin
  t = Date.new(2009,9,11) #Friday, today
  puts "Today: #{Date::DAYNAMES[t.wday]} #{Date::MONTHNAMES[t.mon]} #{t.day}"
  nextday = next_business_day(t)
  puts "Next B-day: #{Date::MONTHNAMES[nextday.mon]} #{nextday.day}"
  previousday = previous_business_day(nextday)
  puts "back to previous: #{Date::MONTHNAMES[previousday.mon]} #{previousday.day}"
  yesterday = previous_business_day(previousday)
  puts "yesterday: #{Date::MONTHNAMES[yesterday.mon]} #{yesterday.day}"  
end  
Run Code Online (Sandbox Code Playgroud)

  • 如果您的日期是星期日,则上述情况不起作用,如果您尝试从星期日起增加7天,则会无限循环. (3认同)
  • 我认为在你的`skip_weekends`方法`date.wday%7`是不必要的,`date.wday`总是在`0..6`之间.所以它可能就像`while [6,0] .include?(date.wday)do` (2认同)

knu*_*nut 10

随着假期,宝石,你也可以检查,如果有一个公共假日.如果这样做,则必须定义所需的区域.holidays-gem也允许使用子区域(例如us-va ......)

德国(德)和美国(美国)假期的示例代码.

require 'holidays'
require 'holidays/us'
require 'holidays/de'
require 'holidays/core_extensions/date'
class Date
  include Holidays::CoreExtensions::Date #provide Date#holiday?

  def next_business_day(region=:any)
    skip_weekends_and_holidays(1,region)
  end    

  def previous_business_day(region=:any)
    skip_weekends_and_holidays(-1,region)
  end

  def skip_weekends_and_holidays(inc, region = :any)
    date = self + inc
    while (date.wday == 6 or date.holiday?(region) ) do
      date += inc
    end   
    date
  end
end
Run Code Online (Sandbox Code Playgroud)

注意:skip_weekends_and_holidays不增加工作日.如果您从星期一起增加5天,则在星期一结束(除非本周一不是假日).如果在5天内有假期,则会有额外的增量.

一些测试代码:

[
  Date.new(2012,6,8), #Friday
  Date.new(2012,6,10), #Monday
  Date.new(2012,6,9), #Sunday
  Date.new(2012,12,24), #Christmas eve
  Date.new(2012,12,26), #After Christmas 
].each{|t|
  %w{us de}.each{|region|
    puts "====#{region}======"
    puts "Today: #{Date::DAYNAMES[t.wday]} #{Date::MONTHNAMES[t.mon]} #{t.day}"
    nextday = t.next_business_day(region)
    puts "Next B-day: #{Date::MONTHNAMES[nextday.mon]} #{nextday.day} - #{Date::DAYNAMES[nextday.wday]}"
    previousday = t.previous_business_day(region)
    puts "Previous B-day: #{Date::MONTHNAMES[previousday.mon]} #{previousday.day} - #{Date::DAYNAMES[previousday.wday]}"
  }
Run Code Online (Sandbox Code Playgroud)

结果摘录(圣诞节前夕):

====us======
Today: Monday December 24
Next B-day: December 26 - Wednesday
Previous B-day: December 23 - Sunday
Run Code Online (Sandbox Code Playgroud)

德国有两个免费日(25 + 26.12):

====de======
Today: Monday December 24
Next B-day: December 27 - Thursday
Previous B-day: December 23 - Sunday
Run Code Online (Sandbox Code Playgroud)

更新:我制作了另一个版本来确定多个工作日:

require 'holidays'
require 'holidays/us'
require 'holidays/core_extensions/date'
#~ require 'holidays/de'
class Date
  include Holidays::CoreExtensions::Date #provide Date#holiday?
  def next_business_day(region=:any)
    next_business_days(1,region)
  end    

  def next_business_days(inc, region=:any)
    date = self
    inc.times{
      date = date.next
      while (date.wday == 6 or date.holiday?(region) ) do
        date = date.next
      end
    }
    date
  end    

  def previous_business_day(region=:any)
    previous_business_days(1,region)
  end

  def previous_business_days(inc, region=:any)
    date = self
    inc.times{
      date = date.prev_day
      while (date.wday == 6 or date.holiday?(region) ) do
        date = date.prev_day
      end
    }
    date
  end    


end
Run Code Online (Sandbox Code Playgroud)

我的测试代码:

require 'test/unit'
class BDay_Test < Test::Unit::TestCase
  def test_2012_06_08_us()
    date = Date.new(2012, 6, 8)
    assert_equal( Date.new(2012, 06, 10), date.next_business_day('us'))
    assert_equal( Date.new(2012, 06,  7), date.previous_business_day('us'))

    assert_equal( Date.new(2012, 06, 17), date.next_business_days(7, 'us'))
    assert_equal( Date.new(2012, 05, 31), date.previous_business_day(7, 'us'))
  end
  def test_2012_06_08_de()
    date = Date.new(2012, 6, 8)
    assert_equal( Date.new(2012, 06, 10), date.next_business_day('de'))
    assert_equal( Date.new(2012, 06,  7), date.previous_business_day('de'))

    assert_equal( Date.new(2012, 06, 17), date.next_business_days(7, 'de'))
    assert_equal( Date.new(2012, 05, 31), date.previous_business_day(7, 'de'))
  end
  def test_2012_06_10_us()
    date = Date.new(2012, 6, 10)
    assert_equal( Date.new(2012, 06, 11), date.next_business_day('us'))
    assert_equal( Date.new(2012, 06,  8), date.previous_business_day('us'))

    assert_equal( Date.new(2012, 06, 18), date.next_business_days(7, 'us'))
    assert_equal( Date.new(2012, 06,  1), date.previous_business_day(7, 'us'))
  end
  def test_2012_06_10_de()
    date = Date.new(2012, 6, 10)
    assert_equal( Date.new(2012, 06, 11), date.next_business_day('de'))
    assert_equal( Date.new(2012, 06,  8), date.previous_business_day('de'))

    assert_equal( Date.new(2012, 06, 18), date.next_business_days(7, 'de'))
    assert_equal( Date.new(2012, 06,  1), date.previous_business_day(7, 'de'))
  end
  def test_2012_06_09_us()
    date = Date.new(2012, 6, 9)
    assert_equal( Date.new(2012, 06, 10), date.next_business_day('us'))
    assert_equal( Date.new(2012, 06,  8), date.previous_business_day('us'))

    assert_equal( Date.new(2012, 06, 17), date.next_business_days(7, 'us'))
    assert_equal( Date.new(2012, 06,  1), date.previous_business_day(7, 'us'))
  end
  def test_2012_06_09_de()
    date = Date.new(2012, 6, 9)
    assert_equal( Date.new(2012, 06, 10), date.next_business_day('de'))
    assert_equal( Date.new(2012, 06,  8), date.previous_business_day('de'))

    assert_equal( Date.new(2012, 06, 17), date.next_business_days(7, 'de'))
    assert_equal( Date.new(2012, 06,  1), date.previous_business_day(7, 'de'))
  end
  def test_2012_12_24_us()
    date = Date.new(2012, 12, 24)
    assert_equal( Date.new(2012, 12, 26), date.next_business_day('us'))
    assert_equal( Date.new(2012, 12, 23), date.previous_business_day('us'))

    assert_equal( Date.new(2013, 01,  3), date.next_business_days(7, 'us'))
    assert_equal( Date.new(2012, 12, 16), date.previous_business_day(7, 'us'))
  end
  def test_2012_12_24_de()
    date = Date.new(2012, 12, 24)
    assert_equal( Date.new(2012, 12, 27), date.next_business_day('de'))
    assert_equal( Date.new(2012, 12, 23), date.previous_business_day('de'))

    assert_equal( Date.new(2013, 01,  4), date.next_business_days(7, 'de'))
    assert_equal( Date.new(2012, 12, 16), date.previous_business_day(7, 'de'))
  end
  def test_2012_12_26_us()
    date = Date.new(2012, 12, 26)
    assert_equal( Date.new(2012, 12, 27), date.next_business_day('us'))
    assert_equal( Date.new(2012, 12, 24), date.previous_business_day('us'))

    assert_equal( Date.new(2013, 01,  4), date.next_business_days(7, 'us'))
    assert_equal( Date.new(2012, 12, 17), date.previous_business_day(7, 'us'))
  end
  def test_2012_12_26_de()
    date = Date.new(2012, 12, 26)
    assert_equal( Date.new(2012, 12, 27), date.next_business_day('de'))
    assert_equal( Date.new(2012, 12, 24), date.previous_business_day('de'))

    assert_equal( Date.new(2013, 01,  4), date.next_business_days(7, 'de'))
    assert_equal( Date.new(2012, 12, 17), date.previous_business_day(7, 'de'))
  end

end    
Run Code Online (Sandbox Code Playgroud)

看到test_2012_12_24_us()date.next_business_days(7,...你在2013年结束,这个时期的每个假期都得到尊重.


小智 6

date = Date.today
date.next_weekday
date.prev_weekday
Run Code Online (Sandbox Code Playgroud)