【问题标题】:How to get a future date thanks to number of working days in ruby?由于红宝石的工作日数,如何获得未来的日期?
【发布时间】:2016-12-07 09:09:33
【问题描述】:

我想从开始日期计算结束日期。 我有工作日数(所以没有周日和周六)。 这是我的功能:

def ending_date(start_date, number_of_working_days)
  date = 0
  ending_date = start_date
   while date > number_of_working_days
    next if ending_date.sunday? || ending_date.saturday?
     finish = ending_date + 1.day unless date.saturday? or date.sunday?
     date += 1
   end
   finish
end

我得到nil。我不知道为什么。 如果 somedoby 可以帮助我解决这个问题,请:)

【问题讨论】:

  • date > number_of_working_days => 0 > number_of_working_days

标签: ruby-on-rails ruby timezone


【解决方案1】:

也可以直接计算ending_date,无需任何循环。每5个工作日就是一个周末!我将星期日的代码编写为 start_date,并在一周中的其他日子使用start_date.wday 对其进行了修改。星期六是个特例。

def ending_date(number_of_working_days, start_date = Date.today)
  if start_date.wday == 6 # Saturday is a special case
    start_date + number_of_working_days + (number_of_working_days-1)/5*2 + 1
  else
    start_date + number_of_working_days + (number_of_working_days-1+start_date.wday)/5*2
  end
end

我对许多 start_dates 和许多 number_of_working_days 进行了测试,它似乎工作正常。

不过,我找不到删除 if 语句的方法。

编辑:如果您使用ActiveSupport::TimeWithZone 对象,只需在调用ending_date 之前调用to_date

time = Time.zone.local(2016, 10, 15, 15, 30, 45)
puts time.class                   #=> ActiveSupport::TimeWithZone
puts ending_date(5, time.to_date) #=> 2016-10-21

【讨论】:

  • 我更喜欢这个解决方案,更容易阅读!但是我的开始日期格式是ActiveSupport::TimeWithZone 所以它不起作用,你知道我必须改变什么吗?我对日期格式感到很困惑,这不是一件容易的事
【解决方案2】:

枚举器似乎可以胜任,它可以为您提供比日期更多的信息:

require 'date'

def future_working_days(start_date = Date.today)
  date = start_date
  Enumerator.new do |yielder|
    loop do
      date += 1 # NOTE: Should start_date be included?
      yielder << date unless date.saturday? || date.sunday?
    end
  end
end

def ending_date(number_of_working_days, start_date = Date.today)
  future_working_days(start_date).find.with_index(1) { |_, i| i == number_of_working_days }
end

# Show the next 10 working days :
puts future_working_days.take(10).map(&:to_s).join('->') # 2016-12-08->2016-12-09->2016-12-12->2016-12-13->2016-12-14->2016-12-15->2016-12-16->2016-12-19->2016-12-20->2016-12-21

# Date after 5 working days :
puts ending_date(5) #=> 2016-12-14

# How many working days until the next Friday the 13th of a leap year
puts future_working_days.find_index{|date| date.friday? && date.day == 13 && Date.leap?(date.year)} #=> 851

注意事项:

  • ending_date 的参数已切换为允许 start_date 的默认日期
  • future_working_days 是一个无限枚举器。不要尝试future_working_days.to_aLazy 可能会有所帮助。
  • 今天应该包含在future_working_days中吗?

【讨论】:

  • 根据我的代码,我才意识到我最好在 javascript 中执行此方法! :( 我将在一个新问题中发布您的解决方案,以便在 js 中翻译它!随时提供帮助。再次感谢
  • 查看我的其他答案。在 javascript 中实现它应该非常简单。
【解决方案3】:

经过最少的更改,它应该如下所示:

def ending_date(start_date, number_of_working_days)
  date = 0
  while date < number_of_working_days
    start_date += 1
    unless start_date.saturday? || start_date.sunday?
      finish = start_date
      date += 1
    end
  end
  finish
end

#> ending_date(Date.today, 5)
#=> #<Date: 2016-12-14 ((2457737j,0s,0n),+0s,2299161j)>

但我更喜欢这样写这个方法:

def ending_date(date, number_of_working_days)
  result = []
  while result.size < number_of_working_days
    date += 1
    unless [6,0].include? date.wday
      result << date
    end
  end
  result 
end

# To take all the working dates
#> ending_date(Date.today, 5)
#=> [#<Date: 2016-12-08 ((2457731j,0s,0n),+0s,2299161j)>, #<Date: 2016-12-09 ((2457732j,0s,0n),+0s,2299161j)>, #<Date: 2016-12-12 ((2457735j,0s,0n),+0s,2299161j)>, #<Date: 2016-12-13 ((2457736j,0s,0n),+0s,2299161j)>, #<Date: 2016-12-14 ((2457737j,0s,0n),+0s,2299161j)>]

# To take last working date
#> ending_date(Date.today, 5).last
#=> #<Date: 2016-12-14 ((2457737j,0s,0n),+0s,2299161j)>

【讨论】:

  • 确实&gt; 是错误的方式!这种方式应该有效。但是我的控制台永远转动,没有任何事情发生,就好像它处于无限循环中一样。
猜你喜欢
  • 2019-05-16
  • 2011-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多