class Tod::Shift

Shift is a range-like class that handles wrapping around midnight. For example, the Shift of 2300 to 0200 would include 0100.

Attributes

beginning[R]
ending[R]
range[R]

Public Class Methods

new(beginning, ending, exclude_end=false) click to toggle source
# File lib/tod/shift.rb, line 8
def initialize(beginning, ending, exclude_end=false)
  raise ArgumentError, "beginning can not be nil" unless beginning
  raise ArgumentError, "ending can not be nil" unless ending
  unless [true, false].include? exclude_end
    raise ArgumentError, "exclude_end must be true or false"
  end

  @beginning = beginning
  @ending = ending
  @exclude_end = exclude_end

  normalized_ending = ending.to_i
  normalized_ending += TimeOfDay::NUM_SECONDS_IN_DAY if normalized_ending < beginning.to_i

  @range = Range.new(beginning.to_i, normalized_ending, @exclude_end)

  freeze # Shift instances are value objects
end

Public Instance Methods

==(other) click to toggle source
# File lib/tod/shift.rb, line 86
def ==(other)
  @range == other.range
end
contains?(shift) click to toggle source
# File lib/tod/shift.rb, line 72
def contains?(shift)
  self.include?(shift.beginning) && self.include?(shift.ending)
end
duration() click to toggle source

Return shift duration in seconds. if ending is lower than beginning this method will calculate the duration as the ending time is from the following day

# File lib/tod/shift.rb, line 78
def duration
  @range.last - @range.first
end
eql?(other) click to toggle source
# File lib/tod/shift.rb, line 90
def eql?(other)
  @range.eql?(other.range)
end
exclude_end?() click to toggle source
# File lib/tod/shift.rb, line 82
def exclude_end?
  @exclude_end
end
hash() click to toggle source
# File lib/tod/shift.rb, line 94
def hash
  @range.hash
end
include?(tod) click to toggle source

Returns true if the time of day is inside the shift, false otherwise.

# File lib/tod/shift.rb, line 28
def include?(tod)
  second = tod.to_i
  second += TimeOfDay::NUM_SECONDS_IN_DAY if second < @range.first
  @range.cover?(second)
end
overlaps?(other) click to toggle source

Returns true if ranges overlap, false otherwise.

# File lib/tod/shift.rb, line 35
def overlaps?(other)
  a, b = [self, other].map(&:range)
  #
  #  Although a Shift which passes through midnight is stored
  #  internally as lasting more than TimeOfDay::NUM_SECONDS_IN_DAY
  #  seconds from midnight, that's not how it is meant to be
  #  handled.  Rather, it consists of two chunks:
  #
  #    range.first => Midnight
  #    Midnight => range.last
  #
  #  The second one is *before* the first.  None of it is more than
  #  TimeOfDay::NUM_SECONDS_IN_DAY after midnight.  We thus need to shift
  #  each of our ranges to cover all overlapping possibilities.
  #
  one_day = TimeOfDay::NUM_SECONDS_IN_DAY
  ashifted =
    Range.new(a.first + one_day, a.last + one_day, a.exclude_end?)
  bshifted =
    Range.new(b.first + one_day, b.last + one_day, b.exclude_end?)
  #
  #  For exclusive ranges we need:
  #
  #  a.ending > b.beginning && b.ending > a.beginning
  #
  #  and for inclusive we need:
  #
  #  a.ending >= b.beginning && b.ending >= a.beginning
  #
  aop = a.exclude_end? ? :> : :>=
  bop = b.exclude_end? ? :> : :>=
  #
  (a.last.send(aop, b.first) && b.last.send(bop, a.first)) ||
  (ashifted.last.send(aop, b.first) && b.last.send(bop, ashifted.first)) ||
  (a.last.send(aop, bshifted.first) && bshifted.last.send(bop, a.first))
end
slide(seconds) click to toggle source

Move start and end by a number of seconds and return new shift.

# File lib/tod/shift.rb, line 99
def slide(seconds)
  self.class.new(beginning + seconds, ending + seconds, exclude_end?)
end