Skip to content

Commit

Permalink
Added Schedule#to_ical
Browse files Browse the repository at this point in the history
  • Loading branch information
John Crepezzi committed Jul 27, 2010
1 parent d214d7f commit e4620ce
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 21 deletions.
40 changes: 20 additions & 20 deletions lib/ice_cube/schedule.rb
Expand Up @@ -60,34 +60,34 @@ def self.from_yaml(str)

TIME_FORMAT = '%B %e, %Y'
SEPARATOR = ' / '
NEWLINE = "\n"

# use with caution
# incomplete and not entirely tested - no time representation in dates
# there's a lot that can happen here
def to_s
representation = ''
representation_pieces = []
inc_dates = (@rdates - @exdates).uniq
if inc_dates && !inc_dates.empty?
representation << inc_dates.sort.map { |d| d.strftime(TIME_FORMAT) }.join(SEPARATOR)
end
if @rrule_occurrence_heads && !@rrule_occurrence_heads.empty?
representation << SEPARATOR unless representation.empty?
representation << @rrule_occurrence_heads.map{ |r| r.rule.to_s }.join(SEPARATOR)
end
if @exrule_occurrence_heads && !@exrule_occurrence_heads.empty?
representation << SEPARATOR unless representation.empty?
representation << @exrule_occurrence_heads.map { |r| 'not ' << r.to_s }.join(SEPARATOR)
end
if @exdates && !@exdates.empty?
representation << SEPARATOR unless representation.empty?
representation << @exdates.uniq.sort.map { |d| 'not on ' << d.strftime(TIME_FORMAT) }.join(SEPARATOR)
end
if @end_time
representation << "until #{end_time.strftime(TIME_FORMAT)}"
end
representation
representation_pieces.concat inc_dates.sort.map { |d| d.strftime(TIME_FORMAT) } unless inc_dates.empty?
representation_pieces.concat @rrule_occurrence_heads.map{ |r| r.rule.to_s } if @rrule_occurrence_heads
representation_pieces.concat @exrule_occurrence_heads.map { |r| 'not ' << r.rule.to_s } if @exrule_occurrence_heads
representation_pieces.concat @exdates.uniq.sort.map { |d| 'not on ' << d.strftime(TIME_FORMAT) } if @exdates
representation_pieces << "until #{end_time.strftime(TIME_FORMAT)}" if @end_time
representation_pieces.join(SEPARATOR)
end

def to_ical
representation_pieces = ["DTSTART#{TimeUtil.ical_format(@start_date)}"]
representation_pieces << "DURATION:#{TimeUtil.ical_duration(@duration)}" if @duration
inc_dates = (@rdates - @exdates).uniq
representation_pieces.concat inc_dates.sort.map { |d| "RDATE#{TimeUtil.ical_format(d)}" } if inc_dates.any?
representation_pieces.concat @exdates.uniq.sort.map { |d| "EXDATE#{TimeUtil.ical_format(d)}" } if @exdates
representation_pieces.concat @rrule_occurrence_heads.map { |r| "RRULE:#{r.rule.to_ical}" } if @rrule_occurrence_heads
representation_pieces.concat @exrule_occurrence_heads.map { |r| "EXRULE:#{r.rule.to_ical}" } if @exrule_occurrence_heads
representation_pieces << "DTEND#{TimeUtil.ical_format(@end_time)}" if @end_time
representation_pieces.join(NEWLINE)
end

def occurring_at?(time)
return false if @exdates.include?(time)
return true if @rdates.include?(time)
Expand Down
18 changes: 18 additions & 0 deletions lib/ice_cube/time_util.rb
Expand Up @@ -27,5 +27,23 @@ def self.days_in_year(date)
def self.days_in_month(date)
is_leap?(date) ? LeapYearMonthDays[date.month - 1] : CommonYearMonthDays[date.month - 1]
end

def self.ical_format(time)
if time.utc?
":#{time.strftime('%Y%m%dT%H%M%SZ')}" # utc time
else
";TZID=#{time.strftime('%Z:%Y%m%dT%H%M%S')}" # local time specified
end
end

def self.ical_duration(duration)
hours = duration / 3600; duration %= 3600
minutes = duration / 60; duration %= 60
repr = ''
repr << "#{hours}H" if hours > 0
repr << "#{minutes}M" if minutes > 0
repr << "#{duration}S" if duration > 0
"PT#{repr}"
end

end
2 changes: 1 addition & 1 deletion lib/ice_cube/version.rb
@@ -1,5 +1,5 @@
module IceCube

VERSION = "0.4.2"
VERSION = '0.4.3'

end
98 changes: 98 additions & 0 deletions spec/examples/to_ical_spec.rb
Expand Up @@ -86,5 +86,103 @@
rule = Rule.daily.day_of_week(:monday => [1, -1], :tuesday => [2]).day(:wednesday)
['FREQ=DAILY;BYDAY=WE;BYDAY=1MO,-1MO,2TU', 'FREQ=DAILY;BYDAY=1MO,-1MO,2TU;BYDAY=WE'].include?(rule.to_ical).should be(true)
end

it 'should be able to serialize a base schedule to ical in local time' do
Time.zone = "Eastern Time (US & Canada)"
schedule = Schedule.new(Time.zone.local(2010, 5, 10, 9, 0, 0))
schedule.to_ical.should == "DTSTART;TZID=EDT:20100510T090000"
end

it 'should be able to serialize a base schedule to ical in UTC time' do
schedule = Schedule.new(Time.utc(2010, 5, 10, 9, 0, 0))
schedule.to_ical.should == "DTSTART:20100510T090000Z"
end

it 'should be able to serialize a schedule with one rrule' do
Time.zone = 'Pacific Time (US & Canada)'
schedule = Schedule.new(Time.zone.local(2010, 5, 10, 9, 0, 0))
schedule.add_recurrence_rule Rule.weekly
# test equality
expectation = "DTSTART;TZID=PDT:20100510T090000\n"
expectation << 'RRULE:FREQ=WEEKLY'
schedule.to_ical.should == expectation
end

it 'should be able to serialize a schedule with multiple rrules' do
Time.zone = 'Eastern Time (US & Canada)'
schedule = Schedule.new(Time.zone.local(2010, 10, 20, 4, 30, 0))
schedule.add_recurrence_rule Rule.weekly.day_of_week(:monday => [2, -1])
schedule.add_recurrence_rule Rule.hourly
expectation = "DTSTART;TZID=EDT:20101020T043000\n"
expectation << "RRULE:FREQ=WEEKLY;BYDAY=2MO,-1MO\n"
expectation << "RRULE:FREQ=HOURLY"
schedule.to_ical.should == expectation
end

it 'should be able to serialize a schedule with one exrule' do
Time.zone ='Pacific Time (US & Canada)'
schedule = Schedule.new(Time.zone.local(2010, 5, 10, 9, 0, 0))
schedule.add_exception_rule Rule.weekly
# test equality
expectation= "DTSTART;TZID=PDT:20100510T090000\n"
expectation<< 'EXRULE:FREQ=WEEKLY'
schedule.to_ical.should == expectation
end

it 'should be able to serialize a schedule with multiple exrules' do
Time.zone ='Eastern Time (US & Canada)'
schedule = Schedule.new(Time.zone.local(2010, 10, 20, 4, 30, 0))
schedule.add_exception_rule Rule.weekly.day_of_week(:monday => [2, -1])
schedule.add_exception_rule Rule.hourly
expectation = "DTSTART;TZID=EDT:20101020T043000\n"
expectation<< "EXRULE:FREQ=WEEKLY;BYDAY=2MO,-1MO\n"
expectation<< "EXRULE:FREQ=HOURLY"
schedule.to_ical.should == expectation
end

it 'should be able to serialize a schedule with an rdate' do
schedule = Schedule.new(Time.utc(2010, 5, 10, 10, 0, 0))
schedule.add_recurrence_date Time.utc(2010, 6, 20, 5, 0, 0)
# test equality
expectation = "DTSTART:20100510T100000Z\n"
expectation << "RDATE:20100620T050000Z"
schedule.to_ical.should == expectation
end

it 'should be able to serialize a schedule with an exdate' do
schedule = Schedule.new(Time.utc(2010, 5, 10, 10, 0, 0))
schedule.add_exception_date Time.utc(2010, 6, 20, 5, 0, 0)
# test equality
expectation = "DTSTART:20100510T100000Z\n"
expectation << "EXDATE:20100620T050000Z"
schedule.to_ical.should == expectation
end

it 'should be able to serialize a schedule with a duration' do
schedule = Schedule.new(Time.utc(2010, 5, 10, 10), :duration => 3600)
expectation = "DTSTART:20100510T100000Z\n"
expectation << 'DURATION:PT1H'
schedule.to_ical.should == expectation
end

it 'should be able to serialize a schedule with a duration - more odd duration' do
schedule = Schedule.new(Time.utc(2010, 5, 10, 10), :duration => 3665)
expectation = "DTSTART:20100510T100000Z\n"
expectation << 'DURATION:PT1H1M5S'
schedule.to_ical.should == expectation
end

it 'should be able to serialize a schedule with an end time' do
schedule = Schedule.new(Time.utc(2010, 5, 10, 10), :end_time => Time.utc(2010, 5, 10, 20))
expectation = "DTSTART:20100510T100000Z\n"
expectation << "DTEND:20100510T200000Z"
schedule.to_ical.should == expectation
end

it 'should not modify the duration when running to_ical' do
schedule = Schedule.new(Time.now, :duration => 3600)
schedule.to_ical
schedule.duration.should == 3600
end

end

0 comments on commit e4620ce

Please sign in to comment.