Class: Timecalculator::Calculator

Inherits:
Object
  • Object
show all
Defined in:
lib/timecalculator/calculator.rb

Instance Method Summary collapse

Constructor Details

#initialize(**options) ⇒ Calculator

def initialize(day_hour_begin = 9, day_hour_end = 18, lunch_time=13, holidays = [])



6
7
8
9
10
11
# File 'lib/timecalculator/calculator.rb', line 6

def initialize(**options)
  @day_hour_begin = options.fetch(:day_hour_begin, 9)
  @day_hour_end = options.fetch(:day_hour_end, 18)
  @lunch_time = options.fetch(:lunch_time, [13])
  @holidays = options.fetch(:holidays, []).reject { |e| e.to_s.empty? }.map(&:to_date)
end

Instance Method Details

#batch_working_minutes_between_to_datetimes(dates = []) ⇒ Object



13
14
15
16
17
# File 'lib/timecalculator/calculator.rb', line 13

def batch_working_minutes_between_to_datetimes(dates = [])
  dates.reduce(0) do |sum, batch|
    sum + working_minutes_between_to_datetimes(DateTime.parse(batch.first), DateTime.parse(batch.last))
  end
end

#datetime_from_date_and_time(date, hour) ⇒ Object



51
52
53
# File 'lib/timecalculator/calculator.rb', line 51

def datetime_from_date_and_time(date, hour)
  DateTime.new(date.year, date.month, date.day, hour, 0, 0, now.zone)
end

#days_between_dates(date1, date2) ⇒ Object



109
110
111
# File 'lib/timecalculator/calculator.rb', line 109

def days_between_dates(date1, date2)
  (date1.to_date...date2.to_date)
end

#ending_time(date_time) ⇒ Object



71
72
73
74
75
76
77
78
79
80
# File 'lib/timecalculator/calculator.rb', line 71

def ending_time(date_time)
  hour = date_time.fetch(:h, 0)
  minute = date_time.fetch(:m, 0)
  if hour == @lunch_time.include?(hour)
    minute = 0
  elsif hour >= @day_hour_end
    hour, minute = @day_hour_end, 0
  end
  { h: hour, m: minute }
end

#full_day_minutesObject



86
87
88
# File 'lib/timecalculator/calculator.rb', line 86

def full_day_minutes
  @full_day_minutes ||= (@day_hour_end - @day_hour_begin - @lunch_time.count) * 60
end

#full_day_minutes_between_dates(date1, date2) ⇒ Object



39
40
41
# File 'lib/timecalculator/calculator.rb', line 39

def full_day_minutes_between_dates(date1, date2)
  working_days_between_dates(date1, date2).count * full_day_minutes
end

#full_day_minutes_between_dates_with_boundaries(dt1, dt2) ⇒ Object



29
30
31
32
33
34
35
36
37
# File 'lib/timecalculator/calculator.rb', line 29

def full_day_minutes_between_dates_with_boundaries(dt1, dt2)
  minutes = 0
  unless holiday?(dt1) || dt1.hour >= @day_hour_end
    minutes += working_minutes_between_to_times({ h: dt1.hour, m: dt1.minute }, { h: @day_hour_end })
  end
  minutes += full_day_minutes_between_dates(dt1, dt2)
  minutes += working_minutes_between_to_times({ h: @day_hour_begin }, { h: dt2.hour, m: dt2.minute }) unless holiday?(dt2)
  minutes
end

#holiday?(date) ⇒ Boolean

Returns:

  • (Boolean)


123
124
125
126
127
# File 'lib/timecalculator/calculator.rb', line 123

def holiday?(date)
  return false unless date

  @holidays.include?(date.to_date)
end

#lunch_time(time1, time2) ⇒ Object



55
56
57
58
# File 'lib/timecalculator/calculator.rb', line 55

def lunch_time(time1, time2)
  time_range = (time1...time2)
  @lunch_time.reduce(0) { |sum, lunch_time| sum + (time_range.cover?(lunch_time) ? 60 : 0) }
end

#min_max_time(time1 = {}, time2 = {}) ⇒ Object



99
100
101
102
103
104
105
106
107
# File 'lib/timecalculator/calculator.rb', line 99

def min_max_time(time1 = {}, time2 = {})
  if time1.fetch(:h, 0) == time2.fetch(:h, 0)
    { min: time1.fetch(:m, 0) < time2.fetch(:m, 0) ? time1 : time2,
      max: time1.fetch(:m, 0) > time2.fetch(:m, 0) ? time1 : time2 }
  else
    { min: time1.fetch(:h, 0) < time2.fetch(:h, 0) ? time1 : time2,
      max: time1.fetch(:h, 0) > time2.fetch(:h, 0) ? time1 : time2 }
  end
end

#minutes_between_two_times(time1 = {}, time2 = {}) ⇒ Object



90
91
92
93
94
95
96
97
# File 'lib/timecalculator/calculator.rb', line 90

def minutes_between_two_times(time1 = {}, time2 = {})
  sorted_times = min_max_time(time1, time2)
  max_h = sorted_times[:max].fetch(:h, 0)
  min_h = sorted_times[:min].fetch(:h, 0)
  max_m = sorted_times[:max].fetch(:m, 0)
  min_m = sorted_times[:min].fetch(:m, 0)
  ((max_h - min_h) * 60) + (max_m - min_m)
end

#start_time(date_time) ⇒ Object



60
61
62
63
64
65
66
67
68
69
# File 'lib/timecalculator/calculator.rb', line 60

def start_time(date_time)
  hour = date_time.fetch(:h, 0)
  minute = date_time.fetch(:m, 0)
  if @lunch_time.include?(hour)
    hour, minute = hour + 1, 0
  elsif hour < @day_hour_begin
    hour, minute = @day_hour_begin, 0
  end
  { h: hour, m: minute }
end

#weekdaysObject



113
114
115
# File 'lib/timecalculator/calculator.rb', line 113

def weekdays
  @weekdays ||= [0, 6]
end

#weekend?(date) ⇒ Boolean

Returns:

  • (Boolean)


117
118
119
120
121
# File 'lib/timecalculator/calculator.rb', line 117

def weekend?(date)
  return false unless date

  weekdays.include?(date.wday)
end

#working_day?(date) ⇒ Boolean

Returns:

  • (Boolean)


129
130
131
# File 'lib/timecalculator/calculator.rb', line 129

def working_day?(date)
  !(weekend?(date) || holiday?(date))
end

#working_days_between_dates(date1, date2) ⇒ Object



82
83
84
# File 'lib/timecalculator/calculator.rb', line 82

def working_days_between_dates(date1, date2)
  days_between_dates(date1 + 1, date2).filter { |date| working_day?(date) }
end

#working_minutes_between_to_datetimes(dt1, dt2) ⇒ Object



19
20
21
22
23
24
25
26
27
# File 'lib/timecalculator/calculator.rb', line 19

def working_minutes_between_to_datetimes(dt1, dt2)
  if dt1.to_date == dt2.to_date
    working_minutes_between_to_times({ h: dt1.hour, m: dt1.minute }, { h: dt2.hour, m: dt2.minute })
  elsif dt1 < dt2
    full_day_minutes_between_dates_with_boundaries(dt1, dt2)
  else
    full_day_minutes_between_dates_with_boundaries(dt2, dt1)
  end
end

#working_minutes_between_to_times(time1, time2) ⇒ Object



43
44
45
46
47
48
49
# File 'lib/timecalculator/calculator.rb', line 43

def working_minutes_between_to_times(time1, time2)
  sorted_times = min_max_time(time1, time2)
  start_time = start_time(sorted_times[:min])
  ending_time = ending_time(sorted_times[:max])
  offset = minutes_between_two_times(start_time, ending_time)
  offset - lunch_time(start_time[:h], ending_time[:h])
end