如何计算Rails中的下一个和上一个工作日?
答案 0 :(得分:16)
据我了解,这是你在找什么? (测试过)
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
答案 1 :(得分:10)
使用holidays-gem,如果有公共假期,您还可以查看。如果这样做,则必须定义所需的区域。 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
注意: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/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
我的测试代码:
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年结束,此期间的每个假期都得到尊重。
答案 2 :(得分:5)
reset()
答案 3 :(得分:3)
您可能需要计算将来从星期六或星期日开始的工作日。 星期一是星期二后的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
答案 4 :(得分:3)
答案 5 :(得分:1)
以下是两个日期之间工作日数的两个示例:
答案 6 :(得分:1)
我意识到这是一个老线程,但我只需要为自己解决这个问题而且我正在寻找一个非常短的代码,如果一个企业有一些奇怪的开放日(如“关闭”),这些代码很容易修改周日/周一“)。
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
答案 7 :(得分:0)
好吧,您可以使用昨天= 1.days.ago 之类的内容来获取昨天的日期。使用 yesterday.strftime('%w')将星期几作为整数(0 =星期日,6 =星期六)。如果昨天是0(星期日),那么一周的前一天将是3.days.ago ...你明白了。
您可以使用明天= 1.days.since 来获取明天的约会。
答案 8 :(得分:0)
这是一种更快的方法,它使用简单的计算而不是在几天内迭代。
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类上使用。
答案 9 :(得分:0)
这是实施:
require 'business_time'
date = Time.now
next_workday(date)
private
def next_workday(date:)
return date = date.next_weekday while date.workday?
end
答案 10 :(得分:0)
这是我在生产计划脚本中使用的一种方法:
require 'date'
def shift_business_days(date, incr)
date = Date.parse(date.to_s)
incr.abs.times do
date += (incr < 0 ? -1 : 1)
while date.saturday? || date.sunday? do
date += (incr < 0 ? -1 : 1)
end
end
date
end
以日期和正负整数incr
作为参数,并以incr
天为单位递增或递减日期,跳过周末。这具有能够处理Date / Time对象或Date.parse可以处理的任何日期字符串的附加好处。
例如:
# (today is 2019-03-08)
shift_business_days(Time.now, 2)
##=> #<Date: 2019-03-12 ((2458555j,0s,0n),+0s,2299161j)>
shift_business_days('5/20', -10)
##=> #<Date: 2019-05-06 ((2458610j,0s,0n),+0s,2299161j)>
答案 11 :(得分:0)
如果在轨道上运行,则可以创建config / initializers / date_time.rb
class DateTime
def next_business_day
# if its a friday saturday or sunday
if self.day > 4
# calculate the remaining days to add to the current day
remaining_days = 7 - self.day + 1
return remaining_days.days.from_now
else
# return tomorrow
return self.tomorrow
end
end
end
用法:
a = DateTime.now
a.next_business_day
=> Mon, 08 Jun 2020 13:46:13 UTC +00:00