Single occurrence event with ice_cube gem using start_time and end_time

ice-cube, ruby, ruby-on-rails-3

Solution

You're misunderstanding how schedules and rules work.

Firstly, it's important to understand `start_time`. Every occurrence of the schedule is based on this, and the schedule returns times that match specific intervals from the start time. The intervals are determined by Rules.

Your example doesn't work because "5 days from now" is not a monthly interval from the schedule's start time. 28, 30, or 31 days from the start time would match, depending on the month.

start = Time.utc(2013, 05, 17, 12, 30, 00) # 2013-05-17 12:30:00 UTC
schedule = IceCube::Schedule.new(start)
schedule.add_recurrence_rule IceCube::Rule.monthly

schedule.occurs_on? start + 5.days #=> false
schedule.occurs_on? start + 31.days #=> true

Secondly, `end_time` works together with `start_time` to set the duration of each occurrence. So if your start time is 09:00, and end time is 17:00 then each occurrence will have a duration of 8 hours.

This creates a distinction between `occurs_at?(t1)` and `occurring_at?(t1)`: the first one is only true when the given time exactly matches the start of an occurrence; the second one is true for any time in the duration. `occurs_on?(d1)` matches for any time in the given date.

arrival = Time.utc(2013, 5, 1,  9, 0, 0)
departure  = Time.utc(2013, 5, 1, 17, 0, 0)
schedule = IceCube::Schedule.new(arrival, end_time: departure)
schedule.add_recurrence_rule IceCube::Rule.weekly.day(1, 2, 3, 4, 5) # M-F

schedule.occurs_at? arrival            #=> true
schedule.occurs_at? arrival + 1.second #=> false

schedule.occurring_at? arrival + 1.second   #=> true
schedule.occurring_at? departure + 1.second #=> false

For what you're doing, you could try one of two approaches:

- A single month-long occurrence

- A daily occurrence that ends after a month

This depends on how you need to display or validate times against the schedule. Here's an example of both:

arrival = Time.utc(2013, 5, 1)
departure = Time.utc(2013, 5, 31)

# single occurrence
schedule = IceCube::Schedule.new(arrival, duration: 31.days)

# daily occurrence
schedule = IceCube::Schedule.new(arrival, duration: 1.day)
schedule.add_recurrence_rule IceCube::Rule.daily.until(departure)

Problem

There must be something simple being overlooked here... I've been trying various methods for creating a basic `IceCube` schedule (https://github.com/seejohnrun/ice_cube). The overall goal is to use `IceCube` to allow "price schedules" inside a "room reservation" rails application. The first scenario would be creating a basic `schedule` with a specific `start_time` and `end_time` - occurring only once. `IceCube` can do this, correct? The schedule would begin on the `start_time` and end at the `end_time`. I would expect to be able to check if dates or times `occurs_on?` this schedule to determine if a room price should be adjusted. So in console I've tried creating a basic schedule and would expect it to be occurring `5.days` from now since the `start_time` is `Time.now` and the `end_time` is `Time.now + 30.days`. But it seems to never return true... ``` 1.8.7 :001 > schedule = IceCube::Schedule.new(Time.now, :end_time => Time.now + 30.days) => #<IceCube::Schedule:0xb619d604 @all_recurrence_rules=[], @duration=nil, @end_time=Tue Jan 08 09:13:11 -0600 2013, @all_exception_rules=[], @start_time=Sun Dec 09 09:13:11 -0600 2012> 1.8.7 :002 > schedule.occurs_on? Date.today + 5.days => false 1.8.7 :005 > schedule.occurs_at? Time.now + 5.days => false 1.8.7 :006 > schedule.occurring_at? Time.now + 5.days => false ``` Adding a recurrence rule ``` 1.8.7 :018 > schedule.rrule IceCube::Rule.monthly => [#<IceCube::MonthlyRule:0xb687a88c @validations={:base_day=>[#<IceCube::Validations::ScheduleLock::Validation:0xb6875b0c @type=:day>], :base_hour=>[#<IceCube::Validations::ScheduleLock::Validation:0xb6875abc @type=:hour>], :interval=>[#<IceCube::Validations::MonthlyInterval::Validation:0xb6875d28 @interval=1>], :base_min=>[#<IceCube::Validations::ScheduleLock::Validation:0xb6875a6c @type=:min>], :base_sec=>[#<IceCube::Validations::ScheduleLock::Validation:0xb6875a1c @type=:sec>]}, @interval=1>] ``` Then checking `Date.today` works... ``` 1.8.7 :025 > schedule.occurs_on? Date.today => true ``` But checking occurs_on? for `Date.today + 10.days` still returns false... Why? ``` 1.8.7 :026 > schedule.occurs_on? Date.today + 10.days => false ``` So what am I overlooking / doing wrong? Or what is the point of setting an `IceCube::Schedule start_time` and `end_time` - they seem to have no effect...? Does `IceCube` not work for single occurrence events with a start and end time? Another example scenario, a room owner wants room prices raised for a holiday season. So the room owner creates a price schedule that starts on Dec 1 2012 and ends Jan 7 2013. (shouldn't have to recur, but could if the owner wanted). Then when people are searching rooms, the prices would be adjusted if the requested stay `occurs_on?` a holiday price schedule Do I need to store the `start_time` and `end_time` outside of the schedule and check it manually or something? Or is there a better suited gem / tool to assist with this kind of schedule management?

Original source