lib/workpattern/week.rb in workpattern-0.2.0 vs lib/workpattern/week.rb in workpattern-0.3.0
- old
+ new
@@ -1,16 +1,32 @@
module Workpattern
- # Represents working and resting times of each day in a week from one date to another.
- # The two dates could be the same day or they could be several weeks or years apart.
+ # @author Barrie Callender
+ # @!attribute values
+ # @return [Array] each day of the week
+ # @!attribute days
+ # @return [Fixnum] number of days in the week
+ # @!attribute start
+ # @return [DateTime] first date in the range
+ # @!attribute finish
+ # @return [DateTime] last date in the range
+ # @!attribute week_total
+ # @return [Fixnum] total number of minutes in a week
+ # @!attribute total
+ # @return [Fixnum] total number of minutes in the range
+ #
+ # Represents working and resting periods for each day in a week for a specified date range.
#
class Week
attr_accessor :values, :days, :start, :finish, :week_total, :total
-
- # :call-seq: new(start,finish,type) => Week
- #
+
+ # Initialises an instance of class Week
+ # @param [DateTime] start first date in the range
+ # @param [DateTime] finish last date in the range
+ # @param [Fixnum] type working (1) or resting (0)
+ # @return [Week] newly initialised Week object
#
def initialize(start,finish,type=1)
hours_in_days_in_week=[24,24,24,24,24,24,24]
@days=hours_in_days_in_week.size
@values=Array.new(7) {|index| Day.new(type)}
@@ -18,10 +34,13 @@
@finish=DateTime.new(finish.year,finish.month,finish.day)
set_attributes
end
+ # Duplicates the current Week object
+ # @return [Week] a duplicated instance of the current Week object
+ #
def duplicate()
duplicate_week=Week.new(@start,@finish)
duplicate_values=Array.new(@values.size)
@values.each_index {|index|
duplicate_values[index]=@values[index].duplicate
@@ -34,51 +53,75 @@
duplicate_week.total=@total
duplicate_week.refresh
return duplicate_week
end
+ # Recalculates the attributes that defines a Week object.
+ # This was made public for #duplicate to work
+ #
def refresh
set_attributes
end
+ # Changes the date range.
+ # This method calls #refresh to update the attributes.
+ #
def adjust(start,finish)
@start=DateTime.new(start.year,start.month,start.day)
@finish=DateTime.new(finish.year,finish.month,finish.day)
refresh
end
+ # Sets a range of minutes in a week to be working or resting. The parameters supplied
+ # to this method determine exactly what should be changed
+ # @param [Hash] days identifies the days to be included in the range
+ # @param [DateTime] from_time where the time portion is used to specify the first minute to be set
+ # @param [DateTime] to_time where the time portion is used to specify the last minute to be set
+ # @param [Fixnum] type where a 1 sets it to working and a 0 to resting
def workpattern(days,from_time,to_time,type)
DAYNAMES[days].each {|day| @values[day].workpattern(from_time,to_time,type)}
refresh
end
+ # Calculates a new date by adding or subtracting a duration in minutes.
+ # @param [DateTime] start original date
+ # @param [Fixnum] duration minutes to add or subtract
+ # @param [Boolean] midnight flag used for subtraction that indicates the start date is midnight
+ #
def calc(start,duration, midnight=false)
- return start,duration if duration==0
+ return start,duration,false if duration==0
return add(start,duration) if duration > 0
+ return subtract(@start,duration, midnight) if (@total==0) && (duration <0)
return subtract(start,duration, midnight) if duration <0
end
+ # Comparison — Returns an integer (-1, 0, or +1) if week is less than, equal to, or greater than other_week
+ # @param [Week] other_week object to compare to
+ # @return [Integer] -1,0 or +1 if week is less than, equal to or greater than other_week
def <=>(obj)
if @start < obj.start
return -1
elsif @start == obj.start
return 0
else
return 1
end
end
- # :call-seq: working?(start) => Boolean
- # Returns true if the given minute is working and false if it isn't
+ # Returns true if the supplied DateTime is working and false if resting
+ # @param [DateTime] start DateTime to be tested
+ # @return [Boolean] true if the minute is working otherwise false if it is a resting minute
#
def working?(start)
@values[start.wday].working?(start)
end
-
- # :call-seq: diff(start,finish) => Duration, Date
- # Returns the difference in minutes between two times.
+ # Returns the difference in minutes between two DateTime values.
+ # @param [DateTime] start starting DateTime
+ # @param [DateTime] finish ending DateTime
+ # @return [Fixnum] number of minutes
+ # @return [DateTime] start date for rest of calculation. The calculation is complete when this is the same as the finish date
#
def diff(start,finish)
start,finish=finish,start if ((start <=> finish))==1
# calculate to end of day
#
@@ -92,10 +135,12 @@
return duration, start
end
private
+ # Recalculates all the attributes for a Week object
+ #
def set_attributes
@total=0
@week_total=0
days=(@finish-@start).to_i + 1 #/60/60/24+1
if (7-@start.wday) < days and days < 8
@@ -111,22 +156,35 @@
@total+=week_total * days / 7
@week_total=week_total if days != 0
end
end
+ # Calculates the total number of minutes between two dates
+ # @param [DateTime] start is the first date in the range
+ # @param [DateTime] finish is the last date in the range
+ # @return [Fixnum] total number of minutes between supplied dates
+ #
def total_hours(start,finish)
total=0
start.upto(finish) {|day|
total+=@values[day].total
}
return total
end
+ # Adds a duration in minutes to a date
+ # @param [DateTime] start original date
+ # @param [Fixnum] duration minutes to add
+ # @param [Boolean] midnight flag used for subtraction that indicates the start date is midnight
+ # @return [DateTime] the calculated date
+ # @return [Fixnum] the number of minutes still to be added
+ # @return [Boolean] Always false, this is the flag used for subtraction
+ #
def add(start,duration)
# aim to calculate to the end of the day
- start,duration = @values[start.wday].calc(start,duration)
- return start,duration if (duration==0) || (start.jd > @finish.jd)
+ start,duration = @values[start.wday].calc(start,duration)
+ return start,duration,false if (duration==0) || (start.jd > @finish.jd)
# aim to calculate to the end of the next week day that is the same as @finish
while((duration!=0) && (start.wday!=@finish.next_day.wday) && (start.jd <= @finish.jd))
if (duration>@values[start.wday].total)
duration = duration - @values[start.wday].total
start=start.next_day
@@ -136,33 +194,41 @@
else
start,duration = @values[start.wday].calc(start,duration)
end
end
- return start,duration if (duration==0) || (start.jd > @finish.jd)
+ return start,duration,false if (duration==0) || (start.jd > @finish.jd)
- #while duration accomodates full weeks
+ # while duration accomodates full weeks
while ((duration!=0) && (duration>=@week_total) && ((start.jd+6) <= @finish.jd))
duration=duration - @week_total
start=start+7
end
- return start,duration if (duration==0) || (start.jd > @finish.jd)
+ return start,duration,false if (duration==0) || (start.jd > @finish.jd)
- #while duration accomodates full days
+ # while duration accomodates full days
while ((duration!=0) && (start.jd<= @finish.jd))
if (duration>@values[start.wday].total)
duration = duration - @values[start.wday].total
start=start.next_day
else
start,duration = @values[start.wday].calc(start,duration)
end
end
- return start, duration
+ return start, duration, false
end
-
+
+ # Subtracts a duration in minutes from a date
+ # @param [DateTime] start original date
+ # @param [Fixnum] duration minutes to subtract - always a negative
+ # @param [Boolean] midnight flag indicates the start date is midnight when true
+ # @return [DateTime] the calculated date
+ # @return [Fixnum] the number of minutes still to be subtracted
+ # @return [Boolean] When set to true indicates the time is midnight on the given date
+ #
def subtract(start,duration,midnight=false)
# Handle subtraction from start of day
if midnight
start,duration=minute_b4_midnight(start,duration)
@@ -216,25 +282,45 @@
return start, duration , midnight
end
+ # Supports calculating from midnight by updating the given duration depending on whether the
+ # last minute in the day is resting or working. It then sets the time to this minute.
+ # @param [DateTime] start is the date whose midnight is to be used as the start date
+ # @param [Fixnum] duration is the number of minutes to subtract
+ # @return [DateTime] the date with a time of 23:59
+ # @return [Fixnum] the duration adjusted according to whether 23:59 is resting or not
+ #
def minute_b4_midnight(start,duration)
+ start -= start.hour * HOUR
+ start -= start.min * MINUTE
duration += @values[start.wday].minutes(23,59,23,59)
start = start.next_day - MINUTE
return start,duration
end
+ # Calculates the date and time after the last working minute of the current date
+ # @param [DateTime] start is the current date
+ # @return [DateTime] the new date
+ #
def after_last_work(start)
if @values[start.wday].last_hour.nil?
return start.next_day
else
start = start + HOUR * (@values[start.wday].last_hour - start.hour)
start = start + MINUTE * (@values[start.wday].last_min - start.min + 1)
return start
end
end
+ # Calculates the difference between two dates that exist in this Week object.
+ # @param [DateTime] start first date
+ # @param [DateTime] finish last date
+ # @param [DateTime] finish_on the range to be used in this Week object.
+ # @return [DateTime] new date for rest of calculation otherwise same as finish if completed calculation
+ # @return [Fixnum] total number of minutes calculated thus far.
+ #
def diff_detail(start,finish,finish_on)
duration, start=@values[start.wday].diff(start,finish)
#rest of week to finish day
while (start.wday<finish.wday) do
duration+=@values[start.wday].total