Subversion Repositories mildred

Rev

Blame | Compare with Previous | Last modification | View Log | RSS feed

class TimeSlot

  cattr_accessor :logger
  attr_reader :dow, :days, :months, :pblock
  attr_accessor :start, :end

  def initialize(slot={})
    slot.symbolize_keys!
    @start = to_hour_min(slot[:start])
    @end = to_hour_min(slot[:end])
    @dow = slot[:dow]
    @days = slot[:days]
    @months = slot[:months]
    @pblock = slot[:"programming block"]
    raise "invalid time slot: #{self.inspect}" unless valid?
  end

  def ==(other)
    return compare_to_time(other) == 0 if other.kind_of?(Time)
    @start == other.start &&
      @end == other.end &&
      @dow == other.dow &&
      @days == other.days &&
      @months == other.months
  end

  def <(other)
    s = Time.parse(@start) <=> Time.parse(other.start)
    e = Time.parse(@end) <=> Time.parse(other.end)
    s == -1 || (s == 0 && e == 1)
  end

  def >(other)
    s = Time.parse(@start) <=> Time.parse(other.start)
    e = Time.parse(@end) <=> Time.parse(other.end)
    s == 1 || (s == 0 && e == -1)
  end

  def <=>(other)
    return compare_to_time(other) if other.kind_of?(Time)

    if self < other
      -1
    elsif self == other
      0
    else
      1
    end
  end

  def duration(block_size=15.minutes)
    s = Time.parse(@start)
    e = Time.parse(@end)
    if s < e
      (e - s).to_i / block_size
    else
      e += 1.day
      (e - s).to_i / block_size
    end
  end
 

  def self.default
    TimeSlot.new(:start => 0, :end => 24)
  end
 
  # Take a start or end time, specified as a string, in the format "hh:mm" and
  # return an array of integers, [mm, hh].  The original format is that
  # produced by to_hour_min, while the output format is useful for blending
  # into an array to be passed to a Time.local call.
  def self.from_hour_min(hm)
    hm.split(":").collect {|x| x.to_i}.reverse
  end

  # Take a time object, and replace its hours and minutes with the string,
  # hm.  The string hm should be in the format "hh:mm", much like that
  # returned by to_hour_min.  Returns a Time object.
  def self.blend_with(hm, time)
    ar = time.to_a
    ar[1,2] = from_hour_min(hm)
    Time.local(*ar)
  end

  def compare_to_time(other)
    s = TimeSlot.blend_with(@start, other)
    e = TimeSlot.blend_with(@end, other)
    if other < s
      1
    elsif other > e
      -1
    else
      0
    end
  end

  def is_now?(time=Time.now)
    s = TimeSlot.blend_with(@start, time)
    e = TimeSlot.blend_with(@end, time)
    e += 24.hours if @end == "00:00"
    if time < s
      false
    elsif time >= e
      false
    else
      is_today?(time)
    end
  end

  def is_today?(time=Time.now)
    if @months && !@months.include?(time.month)
      false
    elsif @dow && !@dow.include?(time.wday)
      false
    elsif @days && !@days.include?(time.day)
      false
    else
      true
    end
  end

  def valid?
    return false if @start.nil?
    return false if @end.nil?
    return false if @end <= @start && Time.parse(@end).hour != 0
    true
  end

  def to_hour_min(time_str)
    begin
      /(\d{1,2})(?::(\d{2}))?/.match(time_str.to_s)
      hour = $~[1].to_i % 24
      min = $~[2].to_i
      sprintf("%02d:%02d", hour, min)
    rescue
      raise "invalid time slot: #{time_str.inspect}"
    end
  end
end