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

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

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

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 

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

 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 

如果有公共假期,您还可以查看假期gem 。 如果这样做,则必须定义所需的区域。 holidays-gem也允许使用子区域(例如us-va ……)

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

 require 'holidays' require 'holidays/us' require 'holidays/de' class Date 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 

注意: 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]}" } 

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

 ====us====== Today: Monday December 24 Next B-day: December 26 - Wednesday Previous B-day: December 23 - Sunday 

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

 ====de====== Today: Monday December 24 Next B-day: December 27 - Thursday Previous B-day: December 23 - Sunday 

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

 require 'holidays' require 'holidays/us' #~ require 'holidays/de' class Date 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 

我的测试代码:

 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 

请参阅test_2012_12_24_us()date.next_business_days(7,...您在2013年结束,期间的每个假期都得到尊重。

您可能需要计算将来从星期六或星期日开始的工作日。 星期一是星期二后的1个工作日,星期日的1个工作日也应该是星期二 – 应该忽略开始的周末日。 以下是:

 class Date def business_days_future(inc) date = skip_weekend inc.times do date = date + 1 date = date.skip_weekend end date end # If date is a saturday or sunday, advance to the following monday def skip_weekend if wday == 0 self + 1 elsif wday == 6 self + 2 else self end end end 

也许这个gem对你有用

https://github.com/bokmann/business_time

这使您可以从给定日期开始计算营业时间和天数

以下是两个日期之间工作日数的两个示例:

  1. http://codesnippets.joyent.com/posts/show/1209
    • 另见: http : //www.railsonwave.com/2007/1/30/calculate-the-number-of-working-days-between-two-dates
  2. http://www.ruby-forum.com/topic/93938#190402

这是一个Ruby假日gem:

我意识到这是一个老线程,但我只需要为自己工作这个,我正在寻找一个非常短的代码,如果一个企业有奇怪的开放日期(如“周日/周一关闭”),这些代码很容易修改“)。

 def next_business_day(from_day) workdays = [1,2,3,4,5,6] test_day = from_day + 1.day return workdays.include?(test_day.wday) ? test_day : next_business_day(test_day) end 

我想它可以再缩短到这样的东西,但我认为它变得不那么明显了

 def next_business_day(from_day) test_day = from_day + 1.day [1,2,3,4,5,6].include?(test_day.wday) ? test_day : next_business_day(test_day) end 

好吧,你可以使用昨天= 1.days.ago之类的东西来获取昨天的日期。 使用yesterday.strftime(’%w’)将星期几作为整数(0 =星期日,6 =星期六)。 如果昨天是0(星期日),那么一周的前一天将是3.days.ago …你明白了。

你可以使用明天= 1.days.since来获得明天的约会。

这是一种更快的方法,它使用简单的计算而不是迭代。

 class Time def shift_weekdays(num_weekdays) base = self # corner case: self falls on a Sat or Sun then treat like its the next Monday case self.wday when 0 base = self + 1.day when 6 base = self + 2.day end day_of_week = base.wday - 1 # Monday is 0 weekends = (day_of_week + num_weekdays) / 5 base + (weekends*2).days + num_weekdays.days end end 

该方法在类Time上,但也可以在Date类上使用。

 date = Date.today date.next_weekday date.prev_weekday 

这是实施:

 require 'business_time' date = Time.now next_workday(date) private def next_workday(date:) return date = date.next_weekday while date.workday? end