rubyredrick-ri_cal 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. data/History.txt +3 -0
  2. data/Manifest.txt +122 -0
  3. data/README.txt +271 -0
  4. data/Rakefile +31 -0
  5. data/bin/ri_cal +8 -0
  6. data/component_attributes/alarm.yml +10 -0
  7. data/component_attributes/calendar.yml +4 -0
  8. data/component_attributes/component_property_defs.yml +180 -0
  9. data/component_attributes/event.yml +45 -0
  10. data/component_attributes/freebusy.yml +16 -0
  11. data/component_attributes/journal.yml +35 -0
  12. data/component_attributes/timezone.yml +3 -0
  13. data/component_attributes/timezone_period.yml +11 -0
  14. data/component_attributes/todo.yml +46 -0
  15. data/copyrights.txt +2 -0
  16. data/docs/draft-ietf-calsify-2446bis-08.txt +7280 -0
  17. data/docs/draft-ietf-calsify-rfc2445bis-09.txt +10416 -0
  18. data/docs/incrementers.txt +7 -0
  19. data/docs/rfc2445.pdf +0 -0
  20. data/lib/ri_cal/component/alarm.rb +22 -0
  21. data/lib/ri_cal/component/calendar.rb +199 -0
  22. data/lib/ri_cal/component/event.rb +30 -0
  23. data/lib/ri_cal/component/freebusy.rb +19 -0
  24. data/lib/ri_cal/component/journal.rb +22 -0
  25. data/lib/ri_cal/component/t_z_info_timezone.rb +124 -0
  26. data/lib/ri_cal/component/timezone/daylight_period.rb +26 -0
  27. data/lib/ri_cal/component/timezone/standard_period.rb +24 -0
  28. data/lib/ri_cal/component/timezone/timezone_period.rb +54 -0
  29. data/lib/ri_cal/component/timezone.rb +193 -0
  30. data/lib/ri_cal/component/todo.rb +26 -0
  31. data/lib/ri_cal/component.rb +224 -0
  32. data/lib/ri_cal/core_extensions/array/conversions.rb +15 -0
  33. data/lib/ri_cal/core_extensions/array.rb +7 -0
  34. data/lib/ri_cal/core_extensions/date/conversions.rb +27 -0
  35. data/lib/ri_cal/core_extensions/date.rb +13 -0
  36. data/lib/ri_cal/core_extensions/date_time/conversions.rb +27 -0
  37. data/lib/ri_cal/core_extensions/date_time.rb +13 -0
  38. data/lib/ri_cal/core_extensions/object/conversions.rb +20 -0
  39. data/lib/ri_cal/core_extensions/object.rb +8 -0
  40. data/lib/ri_cal/core_extensions/string/conversions.rb +32 -0
  41. data/lib/ri_cal/core_extensions/string.rb +8 -0
  42. data/lib/ri_cal/core_extensions/time/calculations.rb +153 -0
  43. data/lib/ri_cal/core_extensions/time/conversions.rb +27 -0
  44. data/lib/ri_cal/core_extensions/time/week_day_predicates.rb +88 -0
  45. data/lib/ri_cal/core_extensions/time.rb +11 -0
  46. data/lib/ri_cal/core_extensions.rb +6 -0
  47. data/lib/ri_cal/invalid_timezone_identifer.rb +20 -0
  48. data/lib/ri_cal/occurrence_enumerator.rb +172 -0
  49. data/lib/ri_cal/parser.rb +138 -0
  50. data/lib/ri_cal/properties/alarm.rb +390 -0
  51. data/lib/ri_cal/properties/calendar.rb +164 -0
  52. data/lib/ri_cal/properties/event.rb +1526 -0
  53. data/lib/ri_cal/properties/freebusy.rb +594 -0
  54. data/lib/ri_cal/properties/journal.rb +1240 -0
  55. data/lib/ri_cal/properties/timezone.rb +151 -0
  56. data/lib/ri_cal/properties/timezone_period.rb +416 -0
  57. data/lib/ri_cal/properties/todo.rb +1562 -0
  58. data/lib/ri_cal/property_value/array.rb +19 -0
  59. data/lib/ri_cal/property_value/cal_address.rb +12 -0
  60. data/lib/ri_cal/property_value/date.rb +119 -0
  61. data/lib/ri_cal/property_value/date_time/additive_methods.rb +43 -0
  62. data/lib/ri_cal/property_value/date_time/time_machine.rb +180 -0
  63. data/lib/ri_cal/property_value/date_time/timezone_support.rb +65 -0
  64. data/lib/ri_cal/property_value/date_time.rb +324 -0
  65. data/lib/ri_cal/property_value/duration.rb +106 -0
  66. data/lib/ri_cal/property_value/geo.rb +12 -0
  67. data/lib/ri_cal/property_value/integer.rb +13 -0
  68. data/lib/ri_cal/property_value/occurrence_list.rb +82 -0
  69. data/lib/ri_cal/property_value/period.rb +63 -0
  70. data/lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb +98 -0
  71. data/lib/ri_cal/property_value/recurrence_rule/enumerator.rb +77 -0
  72. data/lib/ri_cal/property_value/recurrence_rule/initialization_methods.rb +149 -0
  73. data/lib/ri_cal/property_value/recurrence_rule/negative_setpos_enumerator.rb +54 -0
  74. data/lib/ri_cal/property_value/recurrence_rule/numbered_span.rb +32 -0
  75. data/lib/ri_cal/property_value/recurrence_rule/occurence_incrementer.rb +794 -0
  76. data/lib/ri_cal/property_value/recurrence_rule/recurring_day.rb +132 -0
  77. data/lib/ri_cal/property_value/recurrence_rule/recurring_month_day.rb +61 -0
  78. data/lib/ri_cal/property_value/recurrence_rule/recurring_numbered_week.rb +34 -0
  79. data/lib/ri_cal/property_value/recurrence_rule/recurring_year_day.rb +50 -0
  80. data/lib/ri_cal/property_value/recurrence_rule/validations.rb +126 -0
  81. data/lib/ri_cal/property_value/recurrence_rule.rb +146 -0
  82. data/lib/ri_cal/property_value/text.rb +41 -0
  83. data/lib/ri_cal/property_value/uri.rb +12 -0
  84. data/lib/ri_cal/property_value/utc_offset.rb +34 -0
  85. data/lib/ri_cal/property_value.rb +110 -0
  86. data/lib/ri_cal/required_timezones.rb +56 -0
  87. data/lib/ri_cal/time_with_floating_timezone.rb +59 -0
  88. data/lib/ri_cal.rb +134 -0
  89. data/ri_cal.gemspec +47 -0
  90. data/sample_ical_files/from_ical_dot_app/test1.ics +38 -0
  91. data/script/console +10 -0
  92. data/script/destroy +14 -0
  93. data/script/generate +14 -0
  94. data/script/txt2html +71 -0
  95. data/spec/ri_cal/component/alarm_spec.rb +13 -0
  96. data/spec/ri_cal/component/calendar_spec.rb +55 -0
  97. data/spec/ri_cal/component/event_spec.rb +157 -0
  98. data/spec/ri_cal/component/freebusy_spec.rb +13 -0
  99. data/spec/ri_cal/component/journal_spec.rb +13 -0
  100. data/spec/ri_cal/component/t_z_info_timezone_spec.rb +37 -0
  101. data/spec/ri_cal/component/timezone_spec.rb +155 -0
  102. data/spec/ri_cal/component/todo_spec.rb +61 -0
  103. data/spec/ri_cal/component_spec.rb +212 -0
  104. data/spec/ri_cal/core_extensions/time/calculations_spec.rb +189 -0
  105. data/spec/ri_cal/core_extensions/time/week_day_predicates_spec.rb +46 -0
  106. data/spec/ri_cal/occurrence_enumerator_spec.rb +218 -0
  107. data/spec/ri_cal/parser_spec.rb +304 -0
  108. data/spec/ri_cal/property_value/date_spec.rb +22 -0
  109. data/spec/ri_cal/property_value/date_time_spec.rb +448 -0
  110. data/spec/ri_cal/property_value/duration_spec.rb +80 -0
  111. data/spec/ri_cal/property_value/period_spec.rb +50 -0
  112. data/spec/ri_cal/property_value/recurrence_rule/recurring_year_day_spec.rb +22 -0
  113. data/spec/ri_cal/property_value/recurrence_rule_spec.rb +1815 -0
  114. data/spec/ri_cal/property_value/text_spec.rb +14 -0
  115. data/spec/ri_cal/property_value/utc_offset_spec.rb +49 -0
  116. data/spec/ri_cal/property_value_spec.rb +111 -0
  117. data/spec/ri_cal/required_timezones_spec.rb +68 -0
  118. data/spec/ri_cal_spec.rb +54 -0
  119. data/spec/spec.opts +4 -0
  120. data/spec/spec_helper.rb +24 -0
  121. data/tasks/ri_cal.rake +403 -0
  122. data/tasks/spec.rake +35 -0
  123. metadata +201 -0
@@ -0,0 +1,7 @@
1
+ Seconds - Freq="SECONDLY", BYSECOND
2
+ Minutes - Freq="MINUTELY", BYMINUTE
3
+ Hours - Freq="HOURLY", BYHOUR
4
+ Days - Freq="DAILY", BYDAY, BYMONTHDAY, BYYEARDAY
5
+ Weeks - Freq="WEEKLY", BYWEEKNO
6
+ Months - Freq="MONTHLY", BYMONTH
7
+ Years - Freq="YEARLY"
data/docs/rfc2445.pdf ADDED
Binary file
@@ -0,0 +1,22 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. properties alarm.rb])
2
+
3
+ module RiCal
4
+
5
+ class Component
6
+ #- ©2009 Rick DeNatale
7
+ #- All rights reserved. Refer to the file README.txt for the license
8
+ #
9
+ # An Alarm component groups properties defining a reminder or alarm associated with an event or to-do
10
+ # TODO: The Alarm component has complex cardinality restrictions depending on the value of the action property
11
+ # i.e. audio, display, email, and proc alarms, this is currently not checked or enforced
12
+ #
13
+ # to see the property accessing methods for this class see the RiCal::Properties::Alarm module
14
+ class Alarm < Component
15
+ include RiCal::Properties::Alarm
16
+
17
+ def self.entity_name #:nodoc:
18
+ "VALARM"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,199 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. properties calendar.rb])
2
+
3
+ module RiCal
4
+ class Component
5
+ #- ©2009 Rick DeNatale
6
+ #- All rights reserved. Refer to the file README.txt for the license
7
+ #
8
+ # to see the property accessing methods for this class see the RiCal::Properties::Calendar module
9
+ class Calendar < Component
10
+ include RiCal::Properties::Calendar
11
+ attr_reader :tz_source #:nodoc:
12
+
13
+ def initialize(parent=nil, &init_block) #:nodoc:
14
+ super
15
+ @tz_source = 'TZINFO' # Until otherwise told
16
+ end
17
+
18
+ def self.entity_name #:nodoc:
19
+ "VCALENDAR"
20
+ end
21
+
22
+ def tz_info_source? #:nodoc:
23
+ @tz_source == 'TZINFO'
24
+ end
25
+
26
+ def required_timezones # :nodoc:
27
+ @required_timezones ||= RequiredTimezones.new
28
+ end
29
+
30
+ def subcomponent_class # :nodoc:
31
+ {
32
+ :event => Event,
33
+ :todo => Todo,
34
+ :journal => Journal,
35
+ :freebusy => Freebusy,
36
+ :timezone => Timezone,
37
+ }
38
+ end
39
+
40
+ def export_properties_to(export_stream) # :nodoc:
41
+ prodid_property.params["X-RICAL-TZSOURCE"] = @tz_source
42
+ export_prop_to(export_stream, "PRODID", prodid_property)
43
+ export_prop_to(export_stream, "CALSCALE", calscale_property)
44
+ export_prop_to(export_stream, "VERSION", version_property)
45
+ export_prop_to(export_stream, "METHOD", method_property)
46
+ end
47
+
48
+ def prodid_property_from_string(line) # :nodoc:
49
+ result = super
50
+ @tz_source = prodid_property.params["X-RICAL-TZSOURCE"]
51
+ result
52
+ end
53
+
54
+ # return an array of event components contained within this Calendar
55
+ def events
56
+ subcomponents["VEVENT"]
57
+ end
58
+
59
+ # add an event to the calendar
60
+ def add_subcomponent(component)
61
+ super(component)
62
+ component.add_date_times_to(required_timezones) if tz_info_source?
63
+ end
64
+
65
+ # return an array of todo components contained within this Calendar
66
+ def todos
67
+ subcomponents["VTODO"]
68
+ end
69
+
70
+ # return an array of journal components contained within this Calendar
71
+ def journals
72
+ subcomponents["VJOURNAL"]
73
+ end
74
+
75
+ # return an array of freebusy components contained within this Calendar
76
+ def freebusys
77
+ subcomponents["VFREEBUSY"]
78
+ end
79
+
80
+ class TimezoneID
81
+ attr_reader :identifier, :calendar
82
+ def initialize(identifier, calendar)
83
+ self.identifier, self.calendar = identifier, calendar
84
+ end
85
+
86
+ def tzinfo_timezone
87
+ nil
88
+ end
89
+
90
+ def resolved
91
+ calendar.find_timezone(identifier)
92
+ end
93
+
94
+ def local_to_utc(local)
95
+ resolved.local_to_utc(date_time_prop)
96
+ end
97
+ end
98
+
99
+ # return an array of timezone components contained within this calendar
100
+ def timezones
101
+ subcomponents["VTIMEZONE"]
102
+ end
103
+
104
+ class TZInfoWrapper #:nodoc:
105
+ attr_reader :tzinfo, :calendar #:nodoc:
106
+ def initialize(tzinfo, calendar) #:nodoc:
107
+ @tzinfo = tzinfo
108
+ @calendar = calendar
109
+ end
110
+
111
+ def identifier #:nodoc:
112
+ tzinfo.identifier
113
+ end
114
+
115
+ def date_time(ruby_time, tzid) #:nodoc:
116
+ RiCal::PropertyValue::DateTime.new(calendar, :value => ruby_time, :params => {'TZID' => tzid})
117
+ end
118
+
119
+ def local_to_utc(utc) #:nodoc:
120
+ date_time(tzinfo.local_to_utc(utc.to_ri_cal_ruby_value), 'UTC')
121
+ end
122
+
123
+ def utc_to_local(local) #:nodoc:
124
+ date_time(tzinfo.utc_to_local(local.to_ri_cal_ruby_value), tzinfo.identifier)
125
+ end
126
+ end
127
+
128
+ def find_timezone(identifier) #:nodoc:
129
+ if tz_info_source?
130
+ begin
131
+ TZInfoWrapper.new(TZInfo::Timezone.get(identifier), self)
132
+ rescue ::TZInfo::InvalidTimezoneIdentifier => ex
133
+ raise RiCal::InvalidTimezoneIdentifier.invalid_tzinfo_identifier(identifier)
134
+ end
135
+ else
136
+ result = timezones.find {|tz| tz.tzid == identifier}
137
+ raise RiCal::InvalidTimezoneIdentifier.not_found_in_calendar(identifier) unless result
138
+ result
139
+ end
140
+ end
141
+
142
+ def export_required_timezones(export_stream) # :nodoc:
143
+ required_timezones.export_to(export_stream)
144
+ end
145
+
146
+ class FoldingStream #:nodoc:
147
+ attr_reader :stream #:nodoc:
148
+ def initialize(stream) #:nodoc:
149
+ @stream = stream || StringIO.new
150
+ end
151
+
152
+ def string #:nodoc:
153
+ stream.string
154
+ end
155
+
156
+ def fold(string) #:nodoc:
157
+ stream.puts(string[0,73])
158
+ string = string[73..-1]
159
+ while string
160
+ stream.puts " #{string[0, 72]}"
161
+ string = string[72..-1]
162
+ end
163
+ end
164
+
165
+ def puts(*strings) #:nodoc:
166
+ strings.each do |string|
167
+ string.split("\n").each do |line|
168
+ fold(line)
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ # Export this calendar as an iCalendar file.
175
+ # if to is nil (the default) then this method will return a string,
176
+ # otherwise to should be an IO to which the iCalendar file contents will be written
177
+ def export(to=nil)
178
+ export_stream = FoldingStream.new(to)
179
+ export_stream.puts("BEGIN:VCALENDAR")
180
+ #TODO: right now I'm assuming that all timezones are internal what happens when we export
181
+ # an imported calendar.
182
+ export_properties_to(export_stream)
183
+ export_x_properties_to(export_stream)
184
+ export_required_timezones(export_stream)
185
+ export_subcomponent_to(export_stream, events)
186
+ export_subcomponent_to(export_stream, todos)
187
+ export_subcomponent_to(export_stream, journals)
188
+ export_subcomponent_to(export_stream, freebusys)
189
+ export_stream.puts("END:VCALENDAR")
190
+ if to
191
+ nil
192
+ else
193
+ export_stream.string
194
+ end
195
+ end
196
+
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,30 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. properties event.rb])
2
+
3
+ module RiCal
4
+ class Component
5
+ #- ©2009 Rick DeNatale
6
+ #- All rights reserved. Refer to the file README.txt for the license
7
+ #
8
+ # An Event (VEVENT) calendar component groups properties describing a scheduled event.
9
+ # Events may have multiple occurrences
10
+ #
11
+ # Events may also contain one or more ALARM subcomponents
12
+ #
13
+ # to see the property accessing methods for this class see the RiCal::Properties::Event module
14
+ # to see the methods for enumerating occurrences of recurring events see the RiCal::OccurrenceEnumerator module
15
+ class Event < Component
16
+ include OccurrenceEnumerator
17
+
18
+ include RiCal::Properties::Event
19
+
20
+ def subcomponent_class #:nodoc:
21
+ {:alarm => Alarm }
22
+ end
23
+
24
+ def self.entity_name #:nodoc:
25
+ "VEVENT"
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,19 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. properties freebusy.rb])
2
+
3
+ module RiCal
4
+ class Component
5
+ #- ©2009 Rick DeNatale
6
+ #- All rights reserved. Refer to the file README.txt for the license
7
+ #
8
+ # A Freebusy (VFREEBUSY) calendar component groups properties describing either a request for free/busy time,
9
+ # a response to a request for free/busy time, or a published set of busy time.
10
+ # to see the property accessing methods for this class see the RiCal::Properties::Freebusy module
11
+ class Freebusy < Component
12
+ include RiCal::Properties::Freebusy
13
+
14
+ def self.entity_name #:nodoc:
15
+ "VFREEBUSY"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+
2
+ require File.join(File.dirname(__FILE__), %w[.. properties journal.rb])
3
+
4
+ module RiCal
5
+ class Component
6
+ #- ©2009 Rick DeNatale
7
+ #- All rights reserved. Refer to the file README.txt for the license
8
+ #
9
+ # A Journal (VJOURNAL) calendar component groups properties describing a journal entry.
10
+ # Journals may have multiple occurrences
11
+ # to see the property accessing methods for this class see the RiCal::Properties::Journal module
12
+ # to see the methods for enumerating occurrences of recurring journals see the RiCal::OccurrenceEnumerator module
13
+ class Journal < Component
14
+ include RiCal::Properties::Journal
15
+ include RiCal::OccurrenceEnumerator
16
+
17
+ def self.entity_name #:nodoc:
18
+ "VJOURNAL"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,124 @@
1
+ #- ©2009 Rick DeNatale
2
+ #- All rights reserved. Refer to the file README.txt for the license
3
+ #
4
+ # A wrapper class for a Timezone implemented by the TZInfo Gem
5
+ # (or by Rails)
6
+ class RiCal::Component::TZInfoTimezone < RiCal::Component::Timezone
7
+
8
+ class Period #:nodoc: all
9
+
10
+ def initialize(which, this_period, prev_period)
11
+ @which = which
12
+ @onset = this_period.local_start.strftime("%Y%m%dT%H%M%S")
13
+ @offset_from = format_rfc2445_offset(prev_period.utc_total_offset)
14
+ @offset_to = format_rfc2445_offset(this_period.utc_total_offset)
15
+ @abbreviation = this_period.abbreviation
16
+ @rdates = []
17
+ end
18
+
19
+ def add_period(this_period)
20
+ @rdates << this_period.local_start.strftime("%Y%m%dT%H%M%S")
21
+ end
22
+
23
+
24
+ def format_rfc2445_offset(seconds) #:nodoc:
25
+ abs_seconds = seconds.abs
26
+ h = (abs_seconds/3600).floor
27
+ m = (abs_seconds - (h * 3600))/60
28
+ h *= -1 if seconds < 0
29
+ sprintf("%+03d%02d", h, m)
30
+ end
31
+
32
+ def export_to(export_stream)
33
+ export_stream.puts "BEGIN:#{@which}"
34
+ export_stream.puts "DTSTART:#{@onset}"
35
+ export_stream.puts "RDATE:#{@rdates.join(",")}"
36
+ export_stream.puts "TZOFFSETFROM:#{@offset_from}"
37
+ export_stream.puts "TZOFFSETTO:#{@offset_to}"
38
+ export_stream.puts "TZNAME:#{@abbreviation}"
39
+ export_stream.puts "END:#{@which}"
40
+ end
41
+ end
42
+
43
+ class Periods #:nodoc: all
44
+
45
+ def initialize
46
+ @dst_period = @std_period = @previous_period = nil
47
+ end
48
+
49
+ def daylight_period(this_period, previous_period)
50
+ @daylight_period ||= Period.new("DAYLIGHT", this_period, previous_period)
51
+ end
52
+
53
+ def standard_period(this_period, previous_period)
54
+ @standard_period ||= Period.new("STANDARD", this_period, previous_period)
55
+ end
56
+
57
+ def log_period(period)
58
+ @periods ||= []
59
+ @periods << period unless @periods.include?(period)
60
+ end
61
+
62
+ def add_period(this_period)
63
+ if @previous_period
64
+ if this_period.dst?
65
+ period = daylight_period(this_period, @previous_period)
66
+ else
67
+ period = standard_period(this_period, @previous_period)
68
+ end
69
+ period.add_period(this_period)
70
+ log_period(period)
71
+ end
72
+ @previous_period = this_period
73
+ end
74
+
75
+ def export_to(export_stream)
76
+ @periods.each {|period| period.export_to(export_stream)}
77
+ end
78
+ end
79
+
80
+ attr_reader :tzinfo_timezone #:nodoc:
81
+
82
+ def initialize(tzinfo_timezone) #:nodoc:
83
+ @tzinfo_timezone = tzinfo_timezone
84
+ end
85
+
86
+ # convert time from this time zone to utc time
87
+ def local_to_utc(time)
88
+ @tzinfo_timezone.local_to_utc(time.to_ri_cal_ruby_value)
89
+ end
90
+
91
+ # convert time from utc time to this time zone
92
+ def utc_to_local(time)
93
+ @tzinfo_timezone.utc_to_local(time.to_ri_cal_ruby_value)
94
+ end
95
+
96
+ # return the time zone identifier
97
+ def identifier
98
+ @tzinfo_timezone.identifier
99
+ end
100
+
101
+ def export_local_to(export_stream, local_start, local_end) #:nodoc:
102
+ export_utc_to(export_stream, local_to_utc(local_start.to_ri_cal_ruby_value), local_to_utc(local_end.to_ri_cal_ruby_value))
103
+ end
104
+
105
+ def to_rfc2445_string(utc_start, utc_end) #:nodoc:
106
+ export_stream = StringIO.new
107
+ export_utc_to(export_stream, utc_start, utc_end)
108
+ export_stream.string
109
+ end
110
+
111
+ def export_utc_to(export_stream, utc_start, utc_end) #:nodoc:
112
+ export_stream.puts "BEGIN:VTIMEZONE","TZID;X-RICAL-TZSOURCE=TZINFO:#{identifier}"
113
+ periods = Periods.new
114
+ period = tzinfo_timezone.period_for_utc(utc_start)
115
+ #start with the period before the one containing utc_start
116
+ period = tzinfo_timezone.period_for_utc(period.utc_start - 1)
117
+ while period && period.utc_start < utc_end
118
+ periods.add_period(period)
119
+ period = tzinfo_timezone.period_for_utc(period.utc_end + 1)
120
+ end
121
+ periods.export_to(export_stream)
122
+ export_stream.puts "END:VTIMEZONE\n"
123
+ end
124
+ end
@@ -0,0 +1,26 @@
1
+ module RiCal
2
+ class Component
3
+ class Timezone
4
+ #- ©2009 Rick DeNatale
5
+ #- All rights reserved. Refer to the file README.txt for the license
6
+ #
7
+ # A DaylightPeriod is a TimezonePeriod during which daylight saving time *is* in effect
8
+ class DaylightPeriod < TimezonePeriod #:nodoc: all
9
+
10
+ def self.entity_name #:nodoc:
11
+ "DAYLIGHT"
12
+ end
13
+
14
+ def dst?
15
+ true
16
+ end
17
+
18
+ def swallows_local?(local, std_candidate)
19
+ ([local.year, local.month, local.day] == [dtstart.year,dtstart.month, dtstart.day]) &&
20
+ local >= dtstart_property &&
21
+ local.advance(:seconds => (utc_total_offset - std_candidate.utc_total_offset)) < dtstart_property
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ module RiCal
2
+ class Component
3
+ class Timezone
4
+ #- ©2009 Rick DeNatale
5
+ #- All rights reserved. Refer to the file README.txt for the license
6
+ #
7
+ # A StandardPeriod is a TimezonePeriod during which daylight saving time is *not* in effect
8
+ class StandardPeriod < TimezonePeriod #:nodoc: all
9
+
10
+ def self.entity_name #:nodoc:
11
+ "STANDARD"
12
+ end
13
+
14
+ def dst?
15
+ false
16
+ end
17
+
18
+ def ambiguous_local?(time)
19
+ [time.year, time.month, time.day] == [dtstart.year, dtstart.month, dtstart.day]
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,54 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. .. properties timezone_period.rb])
2
+
3
+ module RiCal
4
+ class Component
5
+ class Timezone
6
+ #- ©2009 Rick DeNatale
7
+ #- All rights reserved. Refer to the file README.txt for the license
8
+ #
9
+ # A TimezonePeriod is a component of a timezone representing a period during which a particular offset from UTC is
10
+ # in effect.
11
+ #
12
+ # to see the property accessing methods for this class see the RiCal::Properties::TimezonePeriod module
13
+ class TimezonePeriod < Component
14
+ include Properties::TimezonePeriod
15
+
16
+ include OccurrenceEnumerator
17
+
18
+ def zone_identifier #:nodoc:
19
+ tzname.first
20
+ end
21
+
22
+ def dtend #:nodoc:
23
+ nil
24
+ end
25
+
26
+ def exdate_property #:nodoc:
27
+ nil
28
+ end
29
+
30
+ def utc_total_offset #:nodoc:
31
+ tzoffsetfrom_property.to_seconds
32
+ end
33
+
34
+ def exrule_property #:nodoc:
35
+ nil
36
+ end
37
+
38
+ def last_before_utc(utc_time) #:nodoc:
39
+ last_before_local(utc_time + tzoffsetfrom_property)
40
+ end
41
+
42
+ def last_before_local(local_time) #:nodoc:
43
+ cand_occurrence = nil
44
+ each do |occurrence|
45
+ return cand_occurrence if occurrence.dtstart_property > local_time
46
+ cand_occurrence = occurrence
47
+ end
48
+ return cand_occurrence
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+