计算Ruby中两个日期时间之间的工作时间

时间:2014-06-04 19:39:14

标签: ruby-on-rails ruby date datetime

我想在Ruby中计算两个日期之间的“早晨”和“晚上”工作时间。

“早上”工作时间从06:00:00开始,到21:59:59结束

“晚上”工作时间从22:00:00开始,到05:59:59结束

例如,员工在2014-06-04 21:45开始工作,并在2014-06-05 05:45完成,这意味着,总结应该是:

  • 0.25“早上”工作时间
  • 7.75“晚上”工作时间
  • 总共8个工作小时

3 个答案:

答案 0 :(得分:1)

这可以使用biz gem:

来完成
morning_schedule = Biz::Schedule.new do |config|
  config.hours = {
    mon: {'06:00' => '22:00'},
    tue: {'06:00' => '22:00'},
    wed: {'06:00' => '22:00'},
    thu: {'06:00' => '22:00'},
    fri: {'06:00' => '22:00'}
  }
end

evening_schedule = Biz::Schedule.new do |config|
  config.hours = {
    mon: {'00:00' => '06:00', '22:00' => '24:00'},
    tue: {'00:00' => '06:00', '22:00' => '24:00'},
    wed: {'00:00' => '06:00', '22:00' => '24:00'},
    thu: {'00:00' => '06:00', '22:00' => '24:00'},
    fri: {'00:00' => '06:00', '22:00' => '24:00'}
  }
end

# morning hours worked
morning_schedule.within(
  Time.new(2014, 6, 4, 21, 45),
  Time.new(2014, 6, 5, 5, 45)
)

# evening hours worked
evening_schedule.within(
  Time.new(2014, 6, 4, 21, 45),
  Time.new(2014, 6, 5, 5, 45)
)

确定每个工作时间类型的持续时间后,可以执行后续计算,例如工资系数。

答案 1 :(得分:0)

您可以使用执行此类计算的working_hours gem:https://github.com/intrepidd/working_hours

答案 2 :(得分:-2)

这是一个丑陋的实现(应该适用于任何时间范围):

def time_test(tstr1, tstr2)
  t1 = Time.parse(tstr1)
  t2 = Time.parse(tstr2)
  morning_seconds = 0
  evening_seconds = 0
  while t1 < t2 do
    # if we are starting during morning hours...
    if t1.hour >= 6 && t1.hour < 22
      # this sets the end of morning hours for the current day...
      tend = t1.change(hour: 22)
      # but our actual morning_end should be the lesser of the range end time
      # and the end of current days' working hours
      morning_end = tend < t2 ? tend : t2
      # increment our seconds with the difference between start time and morning end
      morning_seconds += morning_end - t1
      # set our start time to morning_end. if morning_end == t2, then we'll exit
      # the while loop, else we'll process some evening hours
      t1 = morning_end 
    # if we are starting during evening hours (at end of day)
    elsif t1.hour >= 22
      # same as above, except that the potential end time needs to increment the day
      # as well as the hour
      tend = t1.tomorrow.change(hour: 6)
      evening_end = tend < t2 ? tend : t2
      evening_seconds += evening_end - t1
      t1 = evening_end
    # if we are starting during evening hours (at beginning of day)
    elsif t1.hour < 6
      tend = t1.change(hour: 6)
      evening_end = tend < t2 ? tend : t2
      evening_seconds += evening_end - t1
      t1 = evening_end  
    end
  end
  { 
    morning: morning_seconds / 3600,
    evening: evening_seconds / 3600,
    total: (morning_seconds + evening_seconds) / 3600
  } 
end

time_test('2014-06-04 21:45', '2014-06-05 05:45')
# => {:morning=>0.25, :evening=>7.75, :total=>8.0}

这是一种稍微漂亮的递归方式:

def time_test(tstr1, tstr2)
  _t1 = Time.parse(tstr1)
  t2 = Time.parse(tstr2)
  runner = lambda do |t1, ms, es|
    return { 
      morning: ms / 3600, evening: es / 3600, total: (ms + es) / 3600
    } if t1 >= t2
    if t1.hour >= 6 && t1.hour < 22
      tend = t1.change(hour: 22)
      morning_end = tend < t2 ? tend : t2
      runner.call(morning_end, ms + (morning_end - t1), es)
    elsif t1.hour >= 22
      tend = t1.tomorrow.change(hour: 6)
      evening_end = tend < t2 ? tend : t2
      runner.call(evening_end, ms, es + (evening_end - t1))
    elsif t1.hour < 6
      tend = t1.change(hour: 6)
      evening_end = tend < t2 ? tend : t2
      runner.call(evening_end, ms, es + (evening_end - t1)) 
    end    
  end
  runner.call(_t1, 0, 0)
end