demingfactor-ri_cal 0.9.0

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 (167) hide show
  1. checksums.yaml +7 -0
  2. data/History.txt +402 -0
  3. data/Manifest.txt +161 -0
  4. data/README.txt +410 -0
  5. data/Rakefile +69 -0
  6. data/VERSION +1 -0
  7. data/bin/ri_cal +8 -0
  8. data/component_attributes/alarm.yml +10 -0
  9. data/component_attributes/calendar.yml +4 -0
  10. data/component_attributes/component_property_defs.yml +180 -0
  11. data/component_attributes/event.yml +45 -0
  12. data/component_attributes/freebusy.yml +16 -0
  13. data/component_attributes/journal.yml +35 -0
  14. data/component_attributes/timezone.yml +3 -0
  15. data/component_attributes/timezone_period.yml +11 -0
  16. data/component_attributes/todo.yml +46 -0
  17. data/copyrights.txt +1 -0
  18. data/docs/draft-ietf-calsify-2446bis-08.txt +7280 -0
  19. data/docs/draft-ietf-calsify-rfc2445bis-09.txt +10416 -0
  20. data/docs/incrementers.txt +7 -0
  21. data/docs/rfc2445.pdf +0 -0
  22. data/lib/ri_cal/component/alarm.rb +19 -0
  23. data/lib/ri_cal/component/calendar.rb +257 -0
  24. data/lib/ri_cal/component/event.rb +58 -0
  25. data/lib/ri_cal/component/freebusy.rb +16 -0
  26. data/lib/ri_cal/component/journal.rb +27 -0
  27. data/lib/ri_cal/component/non_standard.rb +33 -0
  28. data/lib/ri_cal/component/t_z_info_timezone.rb +153 -0
  29. data/lib/ri_cal/component/timezone/daylight_period.rb +25 -0
  30. data/lib/ri_cal/component/timezone/standard_period.rb +23 -0
  31. data/lib/ri_cal/component/timezone/timezone_period.rb +76 -0
  32. data/lib/ri_cal/component/timezone.rb +197 -0
  33. data/lib/ri_cal/component/todo.rb +42 -0
  34. data/lib/ri_cal/component.rb +256 -0
  35. data/lib/ri_cal/core_extensions/array/conversions.rb +15 -0
  36. data/lib/ri_cal/core_extensions/array.rb +7 -0
  37. data/lib/ri_cal/core_extensions/date/conversions.rb +56 -0
  38. data/lib/ri_cal/core_extensions/date.rb +13 -0
  39. data/lib/ri_cal/core_extensions/date_time/conversions.rb +50 -0
  40. data/lib/ri_cal/core_extensions/date_time.rb +15 -0
  41. data/lib/ri_cal/core_extensions/object/conversions.rb +20 -0
  42. data/lib/ri_cal/core_extensions/object.rb +8 -0
  43. data/lib/ri_cal/core_extensions/string/conversions.rb +57 -0
  44. data/lib/ri_cal/core_extensions/string.rb +8 -0
  45. data/lib/ri_cal/core_extensions/time/calculations.rb +153 -0
  46. data/lib/ri_cal/core_extensions/time/conversions.rb +42 -0
  47. data/lib/ri_cal/core_extensions/time/tzid_access.rb +50 -0
  48. data/lib/ri_cal/core_extensions/time/week_day_predicates.rb +55 -0
  49. data/lib/ri_cal/core_extensions/time.rb +14 -0
  50. data/lib/ri_cal/core_extensions.rb +11 -0
  51. data/lib/ri_cal/fast_date_time.rb +234 -0
  52. data/lib/ri_cal/floating_timezone.rb +32 -0
  53. data/lib/ri_cal/invalid_property_value.rb +8 -0
  54. data/lib/ri_cal/invalid_timezone_identifier.rb +20 -0
  55. data/lib/ri_cal/occurrence_enumerator.rb +265 -0
  56. data/lib/ri_cal/occurrence_period.rb +17 -0
  57. data/lib/ri_cal/parser.rb +148 -0
  58. data/lib/ri_cal/properties/alarm.rb +390 -0
  59. data/lib/ri_cal/properties/calendar.rb +164 -0
  60. data/lib/ri_cal/properties/event.rb +1523 -0
  61. data/lib/ri_cal/properties/freebusy.rb +593 -0
  62. data/lib/ri_cal/properties/journal.rb +1237 -0
  63. data/lib/ri_cal/properties/timezone.rb +150 -0
  64. data/lib/ri_cal/properties/timezone_period.rb +416 -0
  65. data/lib/ri_cal/properties/todo.rb +1559 -0
  66. data/lib/ri_cal/properties.rb +12 -0
  67. data/lib/ri_cal/property_value/array.rb +27 -0
  68. data/lib/ri_cal/property_value/cal_address.rb +11 -0
  69. data/lib/ri_cal/property_value/date.rb +184 -0
  70. data/lib/ri_cal/property_value/date_time/additive_methods.rb +44 -0
  71. data/lib/ri_cal/property_value/date_time/time_machine.rb +159 -0
  72. data/lib/ri_cal/property_value/date_time/timezone_support.rb +100 -0
  73. data/lib/ri_cal/property_value/date_time.rb +359 -0
  74. data/lib/ri_cal/property_value/duration.rb +110 -0
  75. data/lib/ri_cal/property_value/geo.rb +11 -0
  76. data/lib/ri_cal/property_value/integer.rb +12 -0
  77. data/lib/ri_cal/property_value/occurrence_list.rb +144 -0
  78. data/lib/ri_cal/property_value/period.rb +86 -0
  79. data/lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb +100 -0
  80. data/lib/ri_cal/property_value/recurrence_rule/enumerator.rb +79 -0
  81. data/lib/ri_cal/property_value/recurrence_rule/initialization_methods.rb +148 -0
  82. data/lib/ri_cal/property_value/recurrence_rule/negative_setpos_enumerator.rb +53 -0
  83. data/lib/ri_cal/property_value/recurrence_rule/numbered_span.rb +31 -0
  84. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_day_incrementer.rb +86 -0
  85. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_hour_incrementer.rb +31 -0
  86. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_minute_incrementer.rb +32 -0
  87. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_month_incrementer.rb +52 -0
  88. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_monthday_incrementer.rb +31 -0
  89. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_numbered_day_incrementer.rb +38 -0
  90. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_second_incrementer.rb +32 -0
  91. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_weekno_incrementer.rb +69 -0
  92. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/by_yearday_incrementer.rb +31 -0
  93. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/daily_incrementer.rb +28 -0
  94. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/frequency_incrementer.rb +80 -0
  95. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/hourly_incrementer.rb +23 -0
  96. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/list_incrementer.rb +106 -0
  97. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/minutely_incrementer.rb +23 -0
  98. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/monthly_incrementer.rb +33 -0
  99. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/null_sub_cycle_incrementer.rb +43 -0
  100. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/secondly_incrementer.rb +28 -0
  101. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/weekly_incrementer.rb +37 -0
  102. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer/yearly_incrementer.rb +57 -0
  103. data/lib/ri_cal/property_value/recurrence_rule/occurrence_incrementer.rb +135 -0
  104. data/lib/ri_cal/property_value/recurrence_rule/recurring_day.rb +131 -0
  105. data/lib/ri_cal/property_value/recurrence_rule/recurring_month_day.rb +64 -0
  106. data/lib/ri_cal/property_value/recurrence_rule/recurring_numbered_week.rb +33 -0
  107. data/lib/ri_cal/property_value/recurrence_rule/recurring_year_day.rb +53 -0
  108. data/lib/ri_cal/property_value/recurrence_rule/time_manipulation.rb +42 -0
  109. data/lib/ri_cal/property_value/recurrence_rule/validations.rb +125 -0
  110. data/lib/ri_cal/property_value/recurrence_rule.rb +154 -0
  111. data/lib/ri_cal/property_value/text.rb +44 -0
  112. data/lib/ri_cal/property_value/uri.rb +11 -0
  113. data/lib/ri_cal/property_value/utc_offset.rb +33 -0
  114. data/lib/ri_cal/property_value/zulu_date_time.rb +34 -0
  115. data/lib/ri_cal/property_value.rb +159 -0
  116. data/lib/ri_cal/required_timezones.rb +55 -0
  117. data/lib/ri_cal.rb +187 -0
  118. data/parked_specs/ri_cal/claudio_a_bug_spec.rb +100 -0
  119. data/performance/empty_propval/subject.rb +43 -0
  120. data/performance/paris_eastern/subject.rb +90 -0
  121. data/performance/penultimate_weekday/subject.rb +15 -0
  122. data/performance/psm_big_enum/ical.ics +3171 -0
  123. data/performance/psm_big_enum/subject.rb +16 -0
  124. data/performance/utah_cycling/subject.rb +55 -0
  125. data/ri_cal.gemspec +244 -0
  126. data/script/benchmark_subject +23 -0
  127. data/script/console +10 -0
  128. data/script/destroy +14 -0
  129. data/script/generate +14 -0
  130. data/script/profile_subject +29 -0
  131. data/script/txt2html +71 -0
  132. data/spec/ri_cal/bugreports_spec.rb +276 -0
  133. data/spec/ri_cal/component/alarm_spec.rb +12 -0
  134. data/spec/ri_cal/component/calendar_spec.rb +88 -0
  135. data/spec/ri_cal/component/event_spec.rb +735 -0
  136. data/spec/ri_cal/component/freebusy_spec.rb +12 -0
  137. data/spec/ri_cal/component/journal_spec.rb +37 -0
  138. data/spec/ri_cal/component/t_z_info_timezone_spec.rb +60 -0
  139. data/spec/ri_cal/component/timezone_spec.rb +236 -0
  140. data/spec/ri_cal/component/todo_spec.rb +112 -0
  141. data/spec/ri_cal/component_spec.rb +224 -0
  142. data/spec/ri_cal/core_extensions/string/conversions_spec.rb +78 -0
  143. data/spec/ri_cal/core_extensions/time/calculations_spec.rb +188 -0
  144. data/spec/ri_cal/core_extensions/time/week_day_predicates_spec.rb +45 -0
  145. data/spec/ri_cal/fast_date_time_spec.rb +77 -0
  146. data/spec/ri_cal/inf_loop_spec.rb +78 -0
  147. data/spec/ri_cal/occurrence_enumerator_spec.rb +611 -0
  148. data/spec/ri_cal/parser_spec.rb +337 -0
  149. data/spec/ri_cal/property_value/date_spec.rb +53 -0
  150. data/spec/ri_cal/property_value/date_time_spec.rb +383 -0
  151. data/spec/ri_cal/property_value/duration_spec.rb +126 -0
  152. data/spec/ri_cal/property_value/occurrence_list_spec.rb +72 -0
  153. data/spec/ri_cal/property_value/period_spec.rb +63 -0
  154. data/spec/ri_cal/property_value/recurrence_rule/recurring_year_day_spec.rb +21 -0
  155. data/spec/ri_cal/property_value/recurrence_rule_spec.rb +1814 -0
  156. data/spec/ri_cal/property_value/text_spec.rb +25 -0
  157. data/spec/ri_cal/property_value/utc_offset_spec.rb +48 -0
  158. data/spec/ri_cal/property_value_spec.rb +125 -0
  159. data/spec/ri_cal/required_timezones_spec.rb +67 -0
  160. data/spec/ri_cal_spec.rb +53 -0
  161. data/spec/spec.opts +4 -0
  162. data/spec/spec_helper.rb +50 -0
  163. data/tasks/gem_loader/load_active_support.rb +3 -0
  164. data/tasks/gem_loader/load_tzinfo_gem.rb +2 -0
  165. data/tasks/ri_cal.rake +412 -0
  166. data/tasks/spec.rake +102 -0
  167. metadata +246 -0
@@ -0,0 +1,12 @@
1
+ module RiCal
2
+ module Properties #:nodoc:
3
+ autoload :Alarm, "ri_cal/properties/alarm.rb"
4
+ autoload :Calendar, "ri_cal/properties/calendar.rb"
5
+ autoload :Event, "ri_cal/properties/event.rb"
6
+ autoload :Freebusy, "ri_cal/properties/freebusy.rb"
7
+ autoload :Journal, "ri_cal/properties/journal.rb"
8
+ autoload :Timezone, "ri_cal/properties/timezone.rb"
9
+ autoload :TimezonePeriod, "ri_cal/properties/timezone_period.rb"
10
+ autoload :Todo, "ri_cal/properties/todo.rb"
11
+ end
12
+ end
@@ -0,0 +1,27 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
4
+ #
5
+ class Array < PropertyValue # :nodoc:
6
+
7
+ def value=(val)
8
+ case val
9
+ when String
10
+ @value = val.split(",")
11
+ else
12
+ @value = val
13
+ end
14
+ end
15
+
16
+ def value
17
+ @value.join(",")
18
+ end
19
+
20
+ def self.convert(timezone_finder, ruby_object) # :nodoc:
21
+ self.new(timezone_finder, :value => ruby_object)
22
+ end
23
+
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,11 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
4
+ #
5
+ # RiCal::PropertyValue::CalAddress represents an icalendar CalAddress property value
6
+ # which is defined in
7
+ # RFC 2445 section 4.3.3 p 34
8
+ class CalAddress < PropertyValue
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,184 @@
1
+ require 'date'
2
+ module RiCal
3
+ class PropertyValue
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ # RiCal::PropertyValue::CalAddress represents an icalendar Date property value
7
+ # which is defined in
8
+ # RFC 2445 section 4.3.4 p 34
9
+ class Date < PropertyValue
10
+
11
+ def self.valid_string?(string) #:nodoc:
12
+ string =~ /^\d{8}$/
13
+ end
14
+
15
+ # Returns the value of the reciever as an RFC 2445 iCalendar string
16
+ def value
17
+ if @date_time_value
18
+ @date_time_value.ical_date_str
19
+ else
20
+ nil
21
+ end
22
+ end
23
+
24
+ def to_ri_cal_zulu_date_time
25
+ self.to_ri_cal_date_time_value.to_ri_cal_zulu_date_time
26
+ end
27
+
28
+ # Set the value of the property to val
29
+ #
30
+ # val may be either:
31
+ #
32
+ # * A string which can be parsed as a DateTime
33
+ # * A Time instance
34
+ # * A Date instance
35
+ # * A DateTime instance
36
+ def value=(val)
37
+ case val
38
+ when nil
39
+ @date_time_value = nil
40
+ when String
41
+ @date_time_value = FastDateTime.from_date_time(::DateTime.parse(::DateTime.parse(val).strftime("%Y%m%d")))
42
+ when ::Time, ::Date, ::DateTime
43
+ @date_time_value = FastDateTime.from_date_time(::DateTime.parse(val.strftime("%Y%m%d")))
44
+ when FastDateTime
45
+ @date_time_value = val
46
+ end
47
+ end
48
+
49
+ # Nop to allow occurrence list to try to set it
50
+ def tzid=(val)#:nodoc:
51
+ end
52
+
53
+ def tzid #:nodoc:
54
+ nil
55
+ end
56
+
57
+ def visible_params #:nodoc:
58
+ {"VALUE" => "DATE"}.merge(params)
59
+ end
60
+
61
+ # Returns the year (including the century)
62
+ def year
63
+ @date_time_value.year
64
+ end
65
+
66
+ # Returns the month of the year (1..12)
67
+ def month
68
+ @date_time_value.month
69
+ end
70
+
71
+ # Returns the day of the month
72
+ def day
73
+ @date_time_value.day
74
+ end
75
+
76
+ # Returns the ruby representation a ::Date
77
+ def ruby_value
78
+ @date_time_value.date
79
+ end
80
+
81
+ alias_method :to_ri_cal_ruby_value, :ruby_value
82
+
83
+ # Return an instance of RiCal::PropertyValue::DateTime representing the start of this date
84
+ def to_ri_cal_date_time_value
85
+ PropertyValue::DateTime.new(timezone_finder, :value => @date_time_value)
86
+ end
87
+
88
+ # Return this date property
89
+ def to_ri_cal_date_value(timezone_finder = nil)
90
+ self
91
+ end
92
+
93
+ # Return the "Natural' property value for the date_property, in this case the date property itself."
94
+ def to_ri_cal_date_or_date_time_value
95
+ self
96
+ end
97
+
98
+ def for_parent(parent) #:nodoc:
99
+ if timezone_finder.nil?
100
+ @timezone_finder = parent
101
+ self
102
+ elsif parent == timezone_finder
103
+ self
104
+ else
105
+ Date.new(parent, :value => @date_time_value)
106
+ end
107
+ end
108
+
109
+ def advance(options) #:nodoc:
110
+ PropertyValue::Date.new(timezone_finder, :value => @date_time_value.advance(options), :params =>(params ? params.dup : nil) )
111
+ end
112
+
113
+ def change(options) #:nodoc:
114
+ PropertyValue::Date.new(timezone_finder,:value => @date_time_value.change(options), :params => (params ? params.dup : nil) )
115
+ end
116
+
117
+ def add_date_times_to(required_timezones) #:nodoc:
118
+ # Do nothing since dates don't have a timezone
119
+ end
120
+
121
+ # Return the difference between the receiver and other
122
+ #
123
+ # The parameter other should be either a RiCal::PropertyValue::Duration or a RiCal::PropertyValue::DateTime
124
+ #
125
+ # If other is a Duration, the result will be a DateTime, if it is a DateTime the result will be a Duration
126
+ def -(other)
127
+ other.subtract_from_date_time_value(to_ri_cal_date_time_value)
128
+ end
129
+
130
+ def subtract_from_date_time_value(date_time)
131
+ to_ri_cal_date_time_value.subtract_from_date_time_value(date_time)
132
+ end
133
+
134
+ # Return the sum of the receiver and duration
135
+ #
136
+ # The parameter other duration should be a RiCal::PropertyValue::Duration
137
+ #
138
+ # The result will be an RiCal::PropertyValue::DateTime
139
+ def +(duration)
140
+ duration.add_to_date_time_value(to_ri_cal_date_time_value)
141
+ end
142
+
143
+ # Delegate unknown messages to the wrappered Date instance.
144
+ # TODO: Is this really necessary?
145
+ def method_missing(selector, *args) #:nodoc:
146
+ @date_time_value.send(selector, *args)
147
+ end
148
+
149
+ # TODO: consider if this should be a period rather than a hash
150
+ def occurrence_period(default_duration) #:nodoc:
151
+ date_time = self.to_ri_cal_date_time_value
152
+ RiCal::OccurrencePeriod.new(date_time, date_time.advance(:hours => 24, :seconds => -1))
153
+ end
154
+
155
+ def start_of_day?
156
+ true
157
+ end
158
+
159
+ def to_floating_date_time_property
160
+ PropertyValue::DateTime.new(timezone_finder, :value => @date_time_value.ical_str)
161
+ end
162
+
163
+ def to_zulu_occurrence_range_start_time
164
+ to_floating_date_time_property.to_zulu_occurrence_range_start_time
165
+ end
166
+
167
+ def to_zulu_occurrence_range_finish_time
168
+ to_ri_cal_date_time_value.end_of_day.to_zulu_occurrence_range_finish_time
169
+ end
170
+
171
+ def to_finish_time
172
+ to_ri_cal_date_time_value.end_of_day.to_datetime
173
+ end
174
+
175
+ def for_occurrence(occurrence)
176
+ if occurrence.start_of_day?
177
+ occurrence.to_ri_cal_date_value(timezone_finder)
178
+ else
179
+ occurrence.for_parent(timezone_finder)
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,44 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class DateTime
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ # Methods for DateTime which support adding or subtracting another DateTime or Duration
7
+ module AdditiveMethods
8
+ # if end_time is nil => nil
9
+ # otherwise convert end_time to a DateTime and compute the difference
10
+ def duration_until(end_time) # :nodoc:
11
+ end_time && RiCal::PropertyValue::Duration.from_datetimes(timezone_finder, to_datetime, end_time.to_datetime)
12
+ end
13
+
14
+ # Double-dispatch method for subtraction.
15
+ def subtract_from_date_time_value(dtvalue) #:nodoc:
16
+ RiCal::PropertyValue::Duration.from_datetimes(timezone_finder, to_datetime,dtvalue.to_datetime)
17
+ end
18
+
19
+ # Double-dispatch method for addition.
20
+ def add_to_date_time_value(date_time_value) #:nodoc:
21
+ raise ArgumentError.new("Cannot add #{date_time_value} to #{self}")
22
+ end
23
+
24
+ # Return the difference between the receiver and other
25
+ #
26
+ # The parameter other should be either a RiCal::PropertyValue::Duration or a RiCal::PropertyValue::DateTime
27
+ #
28
+ # If other is a Duration, the result will be a DateTime, if it is a DateTime the result will be a Duration
29
+ def -(other)
30
+ other.subtract_from_date_time_value(self)
31
+ end
32
+
33
+ # Return the sum of the receiver and duration
34
+ #
35
+ # The parameter other duration should be a RiCal::PropertyValue::Duration
36
+ #
37
+ # The result will be an RiCal::PropertyValue::DateTime
38
+ def +(duration)
39
+ duration.add_to_date_time_value(self)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,159 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class DateTime
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ # Methods for DateTime which support getting values at different point in time.
7
+ module TimeMachine
8
+
9
+ def advance(options) # :nodoc:
10
+ PropertyValue::DateTime.new(timezone_finder,
11
+ :value => @date_time_value.advance(options),
12
+ :tzid => @tzid,
13
+ :params =>(params ? params.dup : nil)
14
+ )
15
+ end
16
+
17
+ def change(options) # :nodoc:
18
+ PropertyValue::DateTime.new(timezone_finder,
19
+ :value => @date_time_value.change(options),
20
+ :tzid => @tzid,
21
+ :params => (params ? params.dup : nil)
22
+ )
23
+ end
24
+
25
+ def change_sec(new_sec) #:nodoc:
26
+ change(:sec => new_sec)
27
+ end
28
+
29
+ def change_min(new_min) #:nodoc:
30
+ change(:min => new_min)
31
+ end
32
+
33
+ def change_hour(new_hour) #:nodoc:
34
+ change(:hour => new_hour)
35
+ end
36
+
37
+ def change_day(new_day) #:nodoc:
38
+ change(:day => new_day)
39
+ end
40
+
41
+ def change_month(new_month) #:nodoc:
42
+ change(:month => new_month)
43
+ end
44
+
45
+ def change_year(new_year) #:nodoc:
46
+ change(:year => new_year)
47
+ end
48
+
49
+ # Return a DATE-TIME property representing the receiver on a different day (if necessary) so that
50
+ # the result is within the 7 days starting with date
51
+ def in_week_starting?(date)
52
+ wkst_jd = date.jd
53
+ @date_time_value.jd.between?(wkst_jd, wkst_jd + 6)
54
+ end
55
+
56
+ # Return a DATE-TIME property representing the receiver on a different day (if necessary) so that
57
+ # the result is the first day of the ISO week starting on the wkst day containing the receiver.
58
+ def at_start_of_week_with_wkst(wkst)
59
+ date = @date_time_value.start_of_week_with_wkst(wkst)
60
+ change(:year => date.year, :month => date.month, :day => date.day)
61
+ end
62
+ # Return a DATE_TIME value representing the first second of the minute containing the receiver
63
+ def start_of_minute
64
+ change(:sec => 0)
65
+ end
66
+
67
+ # Return a DATE_TIME value representing the last second of the minute containing the receiver
68
+ def end_of_minute
69
+ change(:sec => 59)
70
+ end
71
+
72
+ # Return a DATE_TIME value representing the first second of the hour containing the receiver
73
+ def start_of_hour
74
+ change(:min => 0, :sec => 0)
75
+ end
76
+
77
+ # Return a DATE_TIME value representing the last second of the hour containing the receiver
78
+ def end_of_hour
79
+ change(:min => 59, :sec => 59)
80
+ end
81
+
82
+ # Return a DATE_TIME value representing the first second of the day containing the receiver
83
+ def start_of_day
84
+ change(:hour => 0, :min => 0, :sec => 0)
85
+ end
86
+
87
+ # Return a DATE_TIME value representing the last second of the day containing the receiver
88
+ def end_of_day
89
+ change(:hour => 23, :min => 59, :sec => 59)
90
+ end
91
+
92
+ # Return a Ruby Date representing the first day of the ISO week starting with wkst containing the receiver
93
+ def start_of_week_with_wkst(wkst)
94
+ @date_time_value.start_of_week_with_wkst(wkst)
95
+ end
96
+
97
+ # Return a DATE_TIME value representing the last second of the ISO week starting with wkst containing the receiver
98
+ def end_of_week_with_wkst(wkst)
99
+ date = at_start_of_week_with_wkst(wkst).advance(:days => 6).end_of_day
100
+ end
101
+
102
+ # Return a DATE_TIME value representing the first second of the month containing the receiver
103
+ def start_of_month
104
+ change(:day => 1, :hour => 0, :min => 0, :sec => 0)
105
+ end
106
+
107
+ # Return a DATE_TIME value representing the last second of the month containing the receiver
108
+ def end_of_month
109
+ change(:day => days_in_month, :hour => 23, :min => 59, :sec => 59)
110
+ end
111
+
112
+ # Return a DATE_TIME value representing the first second of the month containing the receiver
113
+ def start_of_year
114
+ change(:month => 1, :day => 1, :hour => 0, :min => 0, :sec => 0)
115
+ end
116
+
117
+ # Return a DATE_TIME value representing the last second of the month containing the receiver
118
+ def end_of_year
119
+ change(:month => 12, :day => 31, :hour => 23, :min => 59, :sec => 59)
120
+ end
121
+
122
+ # Return a DATE_TIME value representing the same time on the first day of the ISO year with weeks
123
+ # starting on wkst containing the receiver
124
+ def at_start_of_iso_year(wkst)
125
+ start_of_year = @date_time_value.iso_year_start(wkst)
126
+ change(:year => start_of_year.year, :month => start_of_year.month, :day => start_of_year.day)
127
+ end
128
+
129
+ # Return a DATE_TIME value representing the same time on the last day of the ISO year with weeks
130
+ # starting on wkst containing the receiver
131
+ def at_end_of_iso_year(wkst)
132
+ num_weeks = @date_time_value.iso_weeks_in_year(wkst)
133
+ at_start_of_iso_year(wkst).advance(:weeks => (num_weeks - 1), :days => 6)
134
+ end
135
+
136
+ # Return a DATE_TIME value representing the same time on the first day of the ISO year with weeks
137
+ # starting on wkst after the ISO year containing the receiver
138
+ def at_start_of_next_iso_year(wkst)
139
+ num_weeks = @date_time_value.iso_weeks_in_year(wkst)
140
+ at_start_of_iso_year(wkst).advance(:weeks => num_weeks)
141
+ end
142
+
143
+ # Return a DATE_TIME value representing the last second of the last day of the ISO year with weeks
144
+ # starting on wkst containing the receiver
145
+ def end_of_iso_year(wkst)
146
+ at_end_of_iso_year(wkst).end_of_day
147
+ end
148
+
149
+ # Return a DATE-TIME representing the same time, on the same day of the month in month.
150
+ # If the month of the receiver has more days than the target month the last day of the target month
151
+ # will be used.
152
+ def in_month(month)
153
+ first = change(:day => 1, :month => month)
154
+ first.change(:day => [first.days_in_month, day].min)
155
+ end
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,100 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ class DateTime
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ # Time zone related methods for DateTime
7
+ module TimezoneSupport
8
+ # Return the timezone id of the receiver, or nil if it is a floating time
9
+ def tzid
10
+ @tzid == :floating ? nil : @tzid
11
+ end
12
+
13
+ def tzid=(timezone_id) #:nodoc:
14
+ timezone_id = default_tzid if timezone_id == :default
15
+ @tzid = timezone_id
16
+ reset_cached_values
17
+ end
18
+
19
+ def reset_cached_values #:nodoc:
20
+ @timezone = @utc = @rational_tz_offset = nil
21
+ end
22
+
23
+ def find_timezone #:nodoc:
24
+ if @tzid == :floating
25
+ FloatingTimezone
26
+ else
27
+ timezone_finder.find_timezone(@tzid)
28
+ end
29
+ end
30
+
31
+ def timezone #:nodoc:
32
+ @timezone ||= find_timezone
33
+ end
34
+
35
+ # Determine if the receiver has a local time zone, i.e. it is not a floating time or a UTC time
36
+ def has_local_timezone?
37
+ tzid && tzid.upcase != "UTC"
38
+ end
39
+
40
+ # Return the receiver if it has a floating time zone already,
41
+ # otherwise return a DATETIME property with the same time as the receiver but with a floating time zone
42
+ def with_floating_timezone
43
+ if @tzid == nil
44
+ self
45
+ else
46
+ @date_time_value.with_floating_timezone.to_ri_cal_date_time_value
47
+ end
48
+ end
49
+
50
+ # Returns a instance that represents the time in UTC.
51
+ def utc
52
+ if has_local_timezone?
53
+ @utc ||= timezone.local_to_utc(self)
54
+ else # Already local or a floating time
55
+ self
56
+ end
57
+ end
58
+
59
+ def rational_tz_offset #:nodoc:
60
+ if has_local_timezone?
61
+ @rational_tz_offset ||= timezone.rational_utc_offset(@date_time_value.to_datetime)
62
+ else
63
+ @rational_tz_offset ||= RiCal.RationalOffset[0]
64
+ end
65
+ end
66
+
67
+ # Predicate indicating whether or not the instance represents a ZULU time
68
+ def utc?
69
+ tzid == "UTC"
70
+ end
71
+
72
+ # Predicate indicating whether or not the instance represents a floating time
73
+ def floating?
74
+ tzid.nil?
75
+ end
76
+
77
+ def has_valid_tzinfo_tzid? #:nodoc:
78
+ if tzid && tzid != :floating
79
+ TZInfo::Timezone.get(tzid) rescue false
80
+ else
81
+ false
82
+ end
83
+ end
84
+
85
+ # Returns the simultaneous time in the specified zone.
86
+ def in_time_zone(new_zone)
87
+ new_zone = timezone_finder.find_timezone(new_zone)
88
+ return self if tzid == new_zone.identifier
89
+ if has_local_timezone?
90
+ new_zone.utc_to_local(utc)
91
+ elsif utc?
92
+ new_zone.utc_to_local(self)
93
+ else # Floating time
94
+ DateTime.new(timezone_finder, :value => @date_time_value, :tzid => new_zone.identifier)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end