Single occurrence event with ice_cube gem using start_time and end_time

。_饼干妹妹 提交于 2019-12-03 03:59:20

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:

  1. A single month-long occurrence
  2. 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)

After some more testing I think using IceCube's SingleOccurrenceRule is the proper way to have a single occurrence of an event.

To have a schedule that occurs only on the days between the Schedule start_time and end_time I can do something like the following.

Create an IceCube::Schedule with a start and end_time:

1.8.7 :097 > schedule = IceCube::Schedule.new(Time.now, :end_time => Time.now + 30.days)
 => #<IceCube::Schedule:0xb63caabc @all_recurrence_rules=[], @duration=nil, @end_time=Wed Jan 09 00:03:36 -0600 2013, @all_exception_rules=[], @start_time=Mon Dec 10 00:03:36 -0600 2012> 

Put all the days that occur within the schedule into an array.

1.8.7 :098 > days_in_schedule = []
 => [] 
1.8.7 :099 > schedule.start_time.to_date.upto(schedule.end_time.to_date) { |d| puts d; days_in_schedule << d }

Iterate over the array and create a SingleOccurrenceRule for each day in the schedule. Then test a couple dates. Within 30 days, occurs_on? is true, outside of 30 days, occurs_on? is false. This seems correct, except it still returns false when checking if schedule.occurs_on? Date.today. WHY?!?!?

1.8.7 :100 > days_in_schedule.each { |d| schedule.rtime Time.parse(d.to_s) }
1.8.7 :109 > schedule.terminating?
 => true 
1.8.7 :110 > schedule.occurs_on? Date.today + 5.days
 => true 
1.8.7 :111 > schedule.occurs_on? Date.today + 55.days
 => false 
1.8.7 :135 > schedule.occurs_on? Date.today
 => false 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!