class IceCube::Schedule

Attributes

end_time[R]

Get the end time

start_time[R]

Get the start time

Public Class Methods

dump(schedule) click to toggle source
# File lib/ice_cube/schedule.rb, line 403
def self.dump(schedule)
  return schedule if schedule.nil? || schedule == ""
  schedule.to_yaml
end
from_hash(original_hash, options = {}) { |schedule| ... } click to toggle source

Load the schedule from a hash

# File lib/ice_cube/schedule.rb, line 377
def self.from_hash(original_hash, options = {})
  HashParser.new(original_hash).to_schedule do |schedule|
    Deprecated.schedule_options(schedule, options)
    yield schedule if block_given?
  end
end
from_ical(ical, options = {}) click to toggle source

Load the schedule from ical

# File lib/ice_cube/schedule.rb, line 339
def self.from_ical(ical, options = {})
  IcalParser.schedule_from_ical(ical, options)
end
from_yaml(yaml, options = {}) { |schedule| ... } click to toggle source

Load the schedule from yaml

# File lib/ice_cube/schedule.rb, line 349
def self.from_yaml(yaml, options = {})
  YamlParser.new(yaml).to_schedule do |schedule|
    Deprecated.schedule_options(schedule, options)
    yield schedule if block_given?
  end
end
load(yaml) click to toggle source
# File lib/ice_cube/schedule.rb, line 408
def self.load(yaml)
  return yaml if yaml.nil? || yaml == ""
  from_yaml(yaml)
end
new(start_time = nil, options = {}) { |self| ... } click to toggle source

Create a new schedule

# File lib/ice_cube/schedule.rb, line 18
def initialize(start_time = nil, options = {})
  self.start_time = start_time || TimeUtil.now
  self.end_time = self.start_time + options[:duration] if options[:duration]
  self.end_time = options[:end_time] if options[:end_time]
  @all_recurrence_rules = []
  @all_exception_rules = []
  yield self if block_given?
end

Public Instance Methods

==(other)
Alias for: eql?
add_exception_rule(rule) click to toggle source

Add an exception rule to the schedule

# File lib/ice_cube/schedule.rb, line 83
def add_exception_rule(rule)
  return if rule.nil?
  @all_exception_rules << rule unless @all_exception_rules.include?(rule)
end
Also aliased as: exrule
add_exception_time(time) click to toggle source

Add an exception time to the schedule

# File lib/ice_cube/schedule.rb, line 59
def add_exception_time(time)
  return if time.nil?
  rule = SingleOccurrenceRule.new(time)
  add_exception_rule rule
  time
end
Also aliased as: extime
add_recurrence_rule(rule) click to toggle source

Add a recurrence rule to the schedule

# File lib/ice_cube/schedule.rb, line 70
def add_recurrence_rule(rule)
  return if rule.nil?
  @all_recurrence_rules << rule unless @all_recurrence_rules.include?(rule)
end
Also aliased as: rrule
add_recurrence_time(time) click to toggle source

Add a recurrence time to the schedule

# File lib/ice_cube/schedule.rb, line 48
def add_recurrence_time(time)
  return if time.nil?
  rule = SingleOccurrenceRule.new(time)
  add_recurrence_rule rule
  time
end
Also aliased as: rtime
all_occurrences() click to toggle source

All of the occurrences

# File lib/ice_cube/schedule.rb, line 154
def all_occurrences
  require_terminating_rules
  enumerate_occurrences(start_time).to_a
end
all_occurrences_enumerator() click to toggle source

Emit an enumerator based on the start time

# File lib/ice_cube/schedule.rb, line 160
def all_occurrences_enumerator
  enumerate_occurrences(start_time)
end
conflicts_with?(other_schedule, closing_time = nil) click to toggle source

Determine if this schedule conflicts with another schedule @param [IceCube::Schedule] other_schedule - The schedule to compare to @param [Time] closing_time - the last time to consider @return [Boolean] whether or not the schedules conflict at all

# File lib/ice_cube/schedule.rb, line 257
def conflicts_with?(other_schedule, closing_time = nil)
  closing_time = TimeUtil.ensure_time(closing_time)
  unless terminating? || other_schedule.terminating? || closing_time
    raise ArgumentError, "One or both schedules must be terminating to use #conflicts_with?"
  end
  # Pick the terminating schedule, and other schedule
  # No need to reverse if terminating? or there is a closing time
  terminating_schedule = self
  unless terminating? || closing_time
    terminating_schedule, other_schedule = other_schedule, terminating_schedule
  end
  # Go through each occurrence of the terminating schedule and determine
  # if the other occurs at that time
  #
  last_time = nil
  terminating_schedule.each_occurrence do |time|
    if closing_time && time > closing_time
      last_time = closing_time
      break
    end
    last_time = time
    return true if other_schedule.occurring_at?(time)
  end
  # Due to durations, we need to walk up to the end time, and verify in the
  # other direction
  if last_time
    last_time += terminating_schedule.duration
    other_schedule.each_occurrence do |time|
      break if time > last_time
      return true if terminating_schedule.occurring_at?(time)
    end
  end
  # No conflict, return false
  false
end
duration() click to toggle source
# File lib/ice_cube/schedule.rb, line 39
def duration
  end_time ? end_time - start_time : 0
end
duration=(seconds) click to toggle source
# File lib/ice_cube/schedule.rb, line 43
def duration=(seconds)
  @end_time = start_time + seconds
end
each_occurrence(&block) click to toggle source

Iterate forever

# File lib/ice_cube/schedule.rb, line 165
def each_occurrence(&block)
  enumerate_occurrences(start_time, &block).to_a
  self
end
encode_with(coder) click to toggle source

Hook for YAML.dump, enables to_yaml

# File lib/ice_cube/schedule.rb, line 344
def encode_with(coder)
  coder.represent_object nil, to_hash
end
end_time=(end_time) click to toggle source

Set end_time

# File lib/ice_cube/schedule.rb, line 34
def end_time=(end_time)
  @end_time = TimeUtil.ensure_time end_time
end
eql?(other) click to toggle source
# File lib/ice_cube/schedule.rb, line 398
def eql?(other)
  self.hash == other.hash
end
Also aliased as: ==
exception_rules() click to toggle source

Get the exception rules

# File lib/ice_cube/schedule.rb, line 102
def exception_rules
  @all_exception_rules.reject { |r| r.is_a?(SingleOccurrenceRule) }
end
Also aliased as: exrules
exception_times() click to toggle source

Get the exception times that are on the schedule

# File lib/ice_cube/schedule.rb, line 128
def exception_times
  @all_exception_rules.select { |r| r.is_a?(SingleOccurrenceRule) }.map(&:time)
end
Also aliased as: extimes
exrule(rule)
Alias for: add_exception_rule
exrules()
Alias for: exception_rules
extime(time)
Alias for: add_exception_time
extimes()
Alias for: exception_times
first(n = nil) click to toggle source

Get the first n occurrences, or the first occurrence if n is skipped

# File lib/ice_cube/schedule.rb, line 299
def first(n = nil)
  occurrences = enumerate_occurrences(start_time).take(n || 1)
  n.nil? ? occurrences.first : occurrences
end
hash() click to toggle source
# File lib/ice_cube/schedule.rb, line 390
def hash
  [
    TimeUtil.hash(start_time), duration,
    *@all_recurrence_rules.map(&:hash).sort!,
    *@all_exception_rules.map(&:hash).sort!
  ].hash
end
last(n = nil) click to toggle source

Get the final n occurrences of a terminating schedule or the final one if no n is given

# File lib/ice_cube/schedule.rb, line 306
def last(n = nil)
  require_terminating_rules
  occurrences = enumerate_occurrences(start_time).to_a
  n.nil? ? occurrences.last : occurrences[-n..-1]
end
next_occurrence(from = nil, options = {}) click to toggle source

The next occurrence after now (overridable)

# File lib/ice_cube/schedule.rb, line 177
def next_occurrence(from = nil, options = {})
  from = TimeUtil.match_zone(from, start_time) || TimeUtil.now(start_time)
  enumerate_occurrences(from + 1, nil, options).next
rescue StopIteration
  nil
end
next_occurrences(num, from = nil, options = {}) click to toggle source

The next n occurrences after now

# File lib/ice_cube/schedule.rb, line 171
def next_occurrences(num, from = nil, options = {})
  from = TimeUtil.match_zone(from, start_time) || TimeUtil.now(start_time)
  enumerate_occurrences(from + 1, nil, options).take(num)
end
occurrences(closing_time) click to toggle source

Get all of the occurrences from the start_time up until a given Time

# File lib/ice_cube/schedule.rb, line 149
def occurrences(closing_time)
  enumerate_occurrences(start_time, closing_time).to_a
end
occurrences_between(begin_time, closing_time, options = {}) click to toggle source

Occurrences between two times

# File lib/ice_cube/schedule.rb, line 213
def occurrences_between(begin_time, closing_time, options = {})
  enumerate_occurrences(begin_time, closing_time, options).to_a
end
occurring_at?(time) click to toggle source

Determine if the schedule is occurring at a given time

# File lib/ice_cube/schedule.rb, line 243
def occurring_at?(time)
  time = TimeUtil.match_zone(time, start_time) or raise ArgumentError, "Time required, got #{time.inspect}"
  if duration > 0
    return false if exception_time?(time)
    occurs_between?(time - duration + 1, time)
  else
    occurs_at?(time)
  end
end
occurring_between?(opening_time, closing_time) click to toggle source

Return a boolean indicating if an occurrence is occurring between two times, inclusive of its duration. This counts zero-length occurrences that intersect the start of the range and within the range, but not occurrences at the end of the range since none of their duration intersects the range.

# File lib/ice_cube/schedule.rb, line 230
def occurring_between?(opening_time, closing_time)
  occurs_between?(opening_time, closing_time, :spans => true)
end
occurs_at?(time) click to toggle source

Determine if the schedule occurs at a specific time

# File lib/ice_cube/schedule.rb, line 294
def occurs_at?(time)
  occurs_between?(time, time)
end
occurs_between?(begin_time, closing_time, options = {}) click to toggle source

Return a boolean indicating if an occurrence falls between two times

# File lib/ice_cube/schedule.rb, line 218
def occurs_between?(begin_time, closing_time, options = {})
  enumerate_occurrences(begin_time, closing_time, options).next
  true
rescue StopIteration
  false
end
occurs_on?(date) click to toggle source

Return a boolean indicating if an occurrence falls on a certain date

# File lib/ice_cube/schedule.rb, line 235
def occurs_on?(date)
  date = TimeUtil.ensure_date(date)
  begin_time = TimeUtil.beginning_of_date(date, start_time)
  closing_time = TimeUtil.end_of_date(date, start_time)
  occurs_between?(begin_time, closing_time)
end
previous_occurrence(from) click to toggle source

The previous occurrence from a given time

# File lib/ice_cube/schedule.rb, line 185
def previous_occurrence(from)
  from = TimeUtil.match_zone(from, start_time) or raise ArgumentError, "Time required, got #{from.inspect}"
  return nil if from <= start_time
  enumerate_occurrences(start_time, from - 1).to_a.last
end
previous_occurrences(num, from) click to toggle source

The previous n occurrences before a given time

# File lib/ice_cube/schedule.rb, line 192
def previous_occurrences(num, from)
  from = TimeUtil.match_zone(from, start_time) or raise ArgumentError, "Time required, got #{from.inspect}"
  return [] if from <= start_time
  a = enumerate_occurrences(start_time, from - 1).to_a
  a.size > num ? a[-1*num,a.size] : a
end
recurrence_rules() click to toggle source

Get the recurrence rules

# File lib/ice_cube/schedule.rb, line 96
def recurrence_rules
  @all_recurrence_rules.reject { |r| r.is_a?(SingleOccurrenceRule) }
end
Also aliased as: rrules
recurrence_times() click to toggle source

Get the recurrence times that are on the schedule

# File lib/ice_cube/schedule.rb, line 108
def recurrence_times
  @all_recurrence_rules.select { |r| r.is_a?(SingleOccurrenceRule) }.map(&:time)
end
Also aliased as: rtimes
remaining_occurrences(from = nil, options = {}) click to toggle source

The remaining occurrences (same requirements as all_occurrences)

# File lib/ice_cube/schedule.rb, line 200
def remaining_occurrences(from = nil, options = {})
  require_terminating_rules
  from ||= TimeUtil.now(@start_time)
  enumerate_occurrences(from, nil, options).to_a
end
remaining_occurrences_enumerator(from = nil, options = {}) click to toggle source

Returns an enumerator for all remaining occurrences

# File lib/ice_cube/schedule.rb, line 207
def remaining_occurrences_enumerator(from = nil, options = {})
  from ||= TimeUtil.now(@start_time)
  enumerate_occurrences(from, nil, options)
end
remove_exception_rule(rule) click to toggle source

Remove an exception rule

# File lib/ice_cube/schedule.rb, line 90
def remove_exception_rule(rule)
  res = @all_exception_rules.delete(rule)
  res.nil? ? [] : [res]
end
remove_exception_time(time) click to toggle source

Remove an exception time

# File lib/ice_cube/schedule.rb, line 136
def remove_exception_time(time)
  found = false
  @all_exception_rules.delete_if do |rule|
    found = true if rule.is_a?(SingleOccurrenceRule) && rule.time == time
  end
  time if found
end
Also aliased as: remove_extime
remove_extime(time)
remove_recurrence_rule(rule) click to toggle source

Remove a recurrence rule

# File lib/ice_cube/schedule.rb, line 77
def remove_recurrence_rule(rule)
  res = @all_recurrence_rules.delete(rule)
  res.nil? ? [] : [res]
end
remove_recurrence_time(time) click to toggle source

Remove a recurrence time

# File lib/ice_cube/schedule.rb, line 116
def remove_recurrence_time(time)
  found = false
  @all_recurrence_rules.delete_if do |rule|
    found = true if rule.is_a?(SingleOccurrenceRule) && rule.time == time
  end
  time if found
end
Also aliased as: remove_rtime
remove_rtime(time)
rrule(rule)
Alias for: add_recurrence_rule
rrules()
Alias for: recurrence_rules
rtime(time)
Alias for: add_recurrence_time
rtimes()
Alias for: recurrence_times
start_time=(start_time) click to toggle source

Set start_time

# File lib/ice_cube/schedule.rb, line 28
def start_time=(start_time)
  @start_time = TimeUtil.ensure_time start_time
end
terminating?() click to toggle source

Determine if the schedule will end @return [Boolean] true if ending, false if repeating forever

# File lib/ice_cube/schedule.rb, line 386
def terminating?
  @all_recurrence_rules.all?(&:terminating?)
end
to_h()
Alias for: to_hash
to_hash() click to toggle source

Convert the schedule to a hash

# File lib/ice_cube/schedule.rb, line 357
def to_hash
  data = {}
  data[:start_time] = TimeUtil.serialize_time(start_time)
  data[:start_date] = data[:start_time] if IceCube.compatibility <= 11
  data[:end_time] = TimeUtil.serialize_time(end_time) if end_time
  data[:rrules] = recurrence_rules.map(&:to_hash)
  if IceCube.compatibility <= 11 && exception_rules.any?
    data[:exrules] = exception_rules.map(&:to_hash)
  end
  data[:rtimes] = recurrence_times.map do |rt|
    TimeUtil.serialize_time(rt)
  end
  data[:extimes] = exception_times.map do |et|
    TimeUtil.serialize_time(et)
  end
  data
end
Also aliased as: to_h
to_ical(force_utc = false) click to toggle source

Serialize this schedule to_ical

# File lib/ice_cube/schedule.rb, line 327
def to_ical(force_utc = false)
  pieces = []
  pieces << "DTSTART#{IcalBuilder.ical_format(start_time, force_utc)}"
  pieces.concat recurrence_rules.map { |r| "RRULE:#{r.to_ical}" }
  pieces.concat exception_rules.map  { |r| "EXRULE:#{r.to_ical}" }
  pieces.concat recurrence_times_without_start_time.map { |t| "RDATE#{IcalBuilder.ical_format(t, force_utc)}" }
  pieces.concat exception_times.map  { |t| "EXDATE#{IcalBuilder.ical_format(t, force_utc)}" }
  pieces << "DTEND#{IcalBuilder.ical_format(end_time, force_utc)}" if end_time
  pieces.join("\n")
end
to_s() click to toggle source

String serialization

# File lib/ice_cube/schedule.rb, line 313
def to_s
  pieces = []
  rd = recurrence_times_with_start_time - extimes
  pieces.concat rd.sort.map { |t| IceCube::I18n.l(t, format: IceCube.to_s_time_format) }
  pieces.concat rrules.map  { |t| t.to_s }
  pieces.concat exrules.map { |t| IceCube::I18n.t('ice_cube.not', target: t.to_s) }
  pieces.concat extimes.sort.map { |t|
    target = IceCube::I18n.l(t, format: IceCube.to_s_time_format)
    IceCube::I18n.t('ice_cube.not_on', target: target)
  }
  pieces.join(IceCube::I18n.t('ice_cube.pieces_connector'))
end

Private Instance Methods

enumerate_occurrences(opening_time, closing_time = nil, options = {}) { |t0| ... } click to toggle source

Find all of the occurrences for the schedule between opening_time and closing_time Iteration is unrolled in pairs to skip duplicate times in end of DST

# File lib/ice_cube/schedule.rb, line 424
def enumerate_occurrences(opening_time, closing_time = nil, options = {})
  opening_time = TimeUtil.match_zone(opening_time, start_time)
  closing_time = TimeUtil.match_zone(closing_time, start_time)
  opening_time += TimeUtil.subsec(start_time) - TimeUtil.subsec(opening_time)
  opening_time = start_time if opening_time < start_time
  spans = options[:spans] == true && duration != 0
  Enumerator.new do |yielder|
    reset
    t1 = full_required? ? start_time : opening_time
    t1 -= duration if spans
    t1 = start_time if t1 < start_time
    loop do
      break unless (t0 = next_time(t1, closing_time))
      break if closing_time && t0 > closing_time
      if (spans ? (t0.end_time > opening_time) : (t0 >= opening_time))
        yielder << (block_given? ? yield(t0) : t0)
      end
      t1 = t0 + 1
    end
  end
end
exception_time?(time) click to toggle source

Return a boolean indicating whether or not a specific time is excluded from the schedule

# File lib/ice_cube/schedule.rb, line 472
def exception_time?(time)
  @all_exception_rules.any? do |rule|
    rule.on?(time, start_time)
  end
end
full_required?() click to toggle source

Indicate if any rule needs to be run from the start of time If we have rules with counts, we need to walk from the beginning of time

# File lib/ice_cube/schedule.rb, line 465
def full_required?
  @all_recurrence_rules.any?(&:full_required?) ||
  @all_exception_rules.any?(&:full_required?)
end
implicit_start_occurrence_rule() click to toggle source
# File lib/ice_cube/schedule.rb, line 484
def implicit_start_occurrence_rule
  SingleOccurrenceRule.new(start_time)
end
next_time(time, closing_time) click to toggle source

Get the next time after (or including) a specific time

# File lib/ice_cube/schedule.rb, line 447
def next_time(time, closing_time)
  loop do
    min_time = recurrence_rules_with_implicit_start_occurrence.reduce(nil) do |best_time, rule|
      begin
        new_time = rule.next_time(time, start_time, best_time || closing_time)
        [best_time, new_time].compact.min
      rescue StopIteration
        best_time
      end
    end
    break unless min_time
    next (time = min_time + 1) if exception_time?(min_time)
    break Occurrence.new(min_time, min_time + duration)
  end
end
recurrence_rules_with_implicit_start_occurrence() click to toggle source
# File lib/ice_cube/schedule.rb, line 500
def recurrence_rules_with_implicit_start_occurrence
  if recurrence_rules.empty?
    [implicit_start_occurrence_rule].concat @all_recurrence_rules
  else
    @all_recurrence_rules
  end
end
recurrence_times_with_start_time() click to toggle source
# File lib/ice_cube/schedule.rb, line 492
def recurrence_times_with_start_time
  if recurrence_rules.empty?
    [start_time].concat recurrence_times_without_start_time
  else
    recurrence_times
  end
end
recurrence_times_without_start_time() click to toggle source
# File lib/ice_cube/schedule.rb, line 488
def recurrence_times_without_start_time
  recurrence_times.reject { |t| t == start_time }
end
require_terminating_rules() click to toggle source
# File lib/ice_cube/schedule.rb, line 478
def require_terminating_rules
  return true if terminating?
  method_name = caller[0].split(' ').last
  raise ArgumentError, "All recurrence rules must specify .until or .count to use #{method_name}"
end
reset() click to toggle source

Reset all rules for another run

# File lib/ice_cube/schedule.rb, line 416
def reset
  @all_recurrence_rules.each(&:reset)
  @all_exception_rules.each(&:reset)
end