class TaskJuggler::WorkingHours
Class to store the working hours for each day of the week. The working hours are stored as Arrays of Fixnum intervals for each day of the week. A day off is modelled as empty Array for that week day. The start end end times of each working period are stored as seconds after midnight.
Attributes
Public Class Methods
Create a new WorkingHours object. The
method accepts a reference to an existing WorkingHours object in wh
. When
it's present, the new object will be a deep copy of the given object.
The Scoreboard object is not deep
copied. It will be copied on write.
# File lib/taskjuggler/WorkingHours.rb, line 31 def initialize(arg1 = nil, startDate = nil, endDate = nil, timeZone = nil) # One entry for every day of the week. Sunday === 0. @days = Array.new(7, []) @scoreboard = nil if arg1.is_a?(WorkingHours) # Create a copy of the passed WorkingHours object. wh = arg1 @timezone = wh.timezone 7.times do |day| hours = [] wh.days[day].each do |hrs| hours << hrs.dup end setWorkingHours(day, hours) end @startDate = wh.startDate @endDate = wh.endDate @slotDuration = wh.slotDuration # Make sure the copied scoreboard has been created, so we can share it # copy-on-write. wh.onShift?(0) @scoreboard = wh.scoreboard else slotDuration = arg1 if arg1.nil? || startDate.nil? || endDate.nil? raise "You must supply values for slotDuration, start and end dates" end @startDate = startDate @endDate = endDate @slotDuration = slotDuration # Create a new object with default working hours. @timezone = timeZone # Set the default working hours. Monday to Friday 9am - 5pm. # Saturday and Sunday are days off. 1.upto(5) do |day| @days[day] = [ [ 9 * 60 * 60, 17 * 60 * 60 ] ] end end end
Public Instance Methods
Return true of the given WorkingHours
object wh
is identical to this object.
# File lib/taskjuggler/WorkingHours.rb, line 83 def ==(wh) return false if wh.nil? || @timezone != wh.timezone || @startDate != wh.startDate || @endDate != wh.endDate || @slotDuration != wh.slotDuration 7.times do |d| return false if @days[d].length != wh.days[d].length # Check all working hour intervals @days[d].length.times do |i| return false if @days[d][i][0] != wh.days[d][i][0] || @days[d][i][1] != wh.days[d][i][1] end end true end
Since we want to share the scoreboard among instances with identical working hours, we need to prevent the scoreboard from being deep cloned. Calling the constructor with self in a re-defined #deep_clone method will do just that.
# File lib/taskjuggler/WorkingHours.rb, line 77 def deep_clone WorkingHours.new(self) end
Return the working hour intervals for a given day of the week.
dayOfWeek
must 0 for Sunday, 1 for Monday and so on. The
result is an Array that contains Arrays of 2 Fixnums.
# File lib/taskjuggler/WorkingHours.rb, line 136 def getWorkingHours(dayOfWeek) @days[dayOfWeek] end
Return true if arg is within the defined working hours. arg can be a TjTime object or a global scoreboard index.
# File lib/taskjuggler/WorkingHours.rb, line 142 def onShift?(arg) initScoreboard unless @scoreboard if arg.is_a?(TjTime) @scoreboard.get(arg) else @scoreboard[arg] end end
Set the working hours for a given week day. dayOfWeek
must be
0 for Sunday, 1 for Monday and so on. intervals
must be an
Array that contains an Array with 2 Fixnums for each working period. Each
value specifies the time of day as minutes after midnight. The first value
is the start time of the interval, the second the end time.
# File lib/taskjuggler/WorkingHours.rb, line 105 def setWorkingHours(dayOfWeek, intervals) # Changing the working hours requires the score board to be regenerated. @scoreboard = nil # Legal values range from 0 Sunday to 6 Saturday. if dayOfWeek < 0 || dayOfWeek > 6 raise "dayOfWeek out of range: #{dayOfWeek}" end intervals.each do |iv| if iv[0] < 0 || iv[0] > 24 * 60 * 60 || iv[1] < 0 || iv[1] > 24 * 60 * 60 raise "Time interval has illegal values: " + "#{time_to_s(iv[0])} - #{time_to_s(iv[1])}" end if iv[0] >= iv[1] raise "Interval end time must be larger than start time" end end @days[dayOfWeek] = intervals end
Return true only if all slots in the interval are offhour slots.
# File lib/taskjuggler/WorkingHours.rb, line 153 def timeOff?(interval) initScoreboard unless @scoreboard startIdx = @scoreboard.dateToIdx(interval.start) endIdx = @scoreboard.dateToIdx(interval.end) startIdx.upto(endIdx - 1) do |i| return false if @scoreboard[i] end true end
Set the time zone zone for the working hours. This will reset the @scoreboard.
# File lib/taskjuggler/WorkingHours.rb, line 128 def timezone=(zone) @scoreboard = nil @timezone = zone end
Returns the time interval settings for each day in a human readable form.
# File lib/taskjuggler/WorkingHours.rb, line 177 def to_s dayNames = %w( Sun Mon Tue Wed Thu Fri Sat ) str = '' 7.times do |day| str += "#{dayNames[day]}: " if @days[day].empty? str += "off" str += "\n" if day < 6 next end first = true @days[day].each do |iv| if first first = false else str += ', ' end str += "#{time_to_s(iv[0])} - #{time_to_s(iv[0])}" end str += "\n" if day < 6 end str end
Return the number of working hours per week.
# File lib/taskjuggler/WorkingHours.rb, line 166 def weeklyWorkingHours seconds = 0 @days.each do |day| day.each do |from, to| seconds += (to - from) end end seconds / (60 * 60) end
Private Instance Methods
# File lib/taskjuggler/WorkingHours.rb, line 207 def initScoreboard # The scoreboard is an Array of True/False values. It spans a certain # time period with one entry per time slot. @scoreboard = Scoreboard.new(@startDate, @endDate, @slotDuration, false) oldTimezone = nil # Active the appropriate time zone for the working hours. if @timezone oldTimezone = TjTime.setTimeZone(@timezone) end date = @startDate @scoreboard.collect! do |slot| # The weekday and seconds of the day needs to be calculated according # to the local timezone. weekday = date.wday secondsOfDay = date.secondsOfDay result = false @days[weekday].each do |iv| # Check the working hours of that day if they overlap with +date+. if iv[0] <= secondsOfDay && secondsOfDay < iv[1] # The time slot is a working slot. result = true break end end # Calculate date of next scoreboard slot date += @slotDuration result end # Restore old time zone setting. if @timezone && oldTimezone TjTime.setTimeZone(oldTimezone) end end
# File lib/taskjuggler/WorkingHours.rb, line 203 def time_to_s(t) "#{t >= 24 * 60 * 60 ? '24:00' : "#{t / 3600}:#{t % 3600}"}" end