icalendar 2.10.1 → 2.12.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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +5 -3
- data/CHANGELOG.md +231 -0
- data/README.md +1 -1
- data/icalendar.gemspec +4 -1
- data/lib/icalendar/downcased_hash.rb +39 -6
- data/lib/icalendar/offset/active_support_exact.rb +23 -0
- data/lib/icalendar/offset/active_support_partial.rb +27 -0
- data/lib/icalendar/offset/null.rb +17 -0
- data/lib/icalendar/offset/time_zone_store.rb +29 -0
- data/lib/icalendar/offset/windows_to_iana.rb +144 -0
- data/lib/icalendar/offset.rb +44 -0
- data/lib/icalendar/parser.rb +14 -8
- data/lib/icalendar/value.rb +11 -2
- data/lib/icalendar/values/boolean.rb +3 -3
- data/lib/icalendar/values/date.rb +3 -4
- data/lib/icalendar/values/date_time.rb +3 -3
- data/lib/icalendar/values/duration.rb +3 -3
- data/lib/icalendar/values/float.rb +3 -3
- data/lib/icalendar/values/helpers/array.rb +7 -6
- data/lib/icalendar/values/helpers/time_with_zone.rb +18 -42
- data/lib/icalendar/values/integer.rb +3 -3
- data/lib/icalendar/values/period.rb +3 -3
- data/lib/icalendar/values/recur.rb +3 -3
- data/lib/icalendar/values/text.rb +2 -2
- data/lib/icalendar/values/time.rb +4 -4
- data/lib/icalendar/values/uri.rb +4 -3
- data/lib/icalendar/values/utc_offset.rb +2 -2
- data/lib/icalendar/version.rb +1 -1
- data/spec/fixtures/single_event_bad_location.ics +23 -0
- data/spec/fixtures/two_time_events.ics +1 -1
- data/spec/fixtures/tz_store_param_bug.ics +30 -0
- data/spec/parser_spec.rb +24 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/values/date_spec.rb +24 -0
- data/spec/values/date_time_spec.rb +22 -7
- data/spec/values/uri_spec.rb +43 -0
- metadata +61 -7
- data/History.txt +0 -200
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ad06e861392ab70f0e800ac4f2a6b81f019aaf3548a35e513f02bcc975968b86
|
|
4
|
+
data.tar.gz: 16562bdeae817fc8afd4e0b6de7090a42c0b095cb56640d5b9183cfb3a07bb74
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 927cd1536b413039b75f4c2a100ca169bb17897c10754b4806762d341aaa4b7800fc93e7bc81566681a678a853fefc0d54fad5fdd0316c10f0245f91864d2faf
|
|
7
|
+
data.tar.gz: 5d9c09347062a5dd73ad23cd75905c5508b8a72ce0447241ee282fa6bbcc7d259e4a26309fc90af718f14f14b18ca78403bc849898b42147c5368ae6edb21d13
|
data/.github/workflows/main.yml
CHANGED
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
## Unreleased
|
|
2
|
+
|
|
3
|
+
## 2.12.2 - 2026-03-21
|
|
4
|
+
- Fix a potential property injection issue through escaping control characters in URI values - Wes Ring
|
|
5
|
+
|
|
6
|
+
## 2.12.1 - 2025-10-19
|
|
7
|
+
- Fix a problem with invalid ics generation for calendars with custom properties that include a `tzid` parameter.
|
|
8
|
+
|
|
9
|
+
## 2.12.0 - 2025-09-26
|
|
10
|
+
- Support timezone lookup by Windows names - Ronak Gothi
|
|
11
|
+
|
|
12
|
+
## 2.11.2 - 2025-06-21
|
|
13
|
+
- Deal with more bad value parameter values by falling back to the property default type
|
|
14
|
+
|
|
15
|
+
## 2.11.1 - 2025-06-06
|
|
16
|
+
- Gracefully deal with malformed ics files that use spaces in the value parameter instead of hyphens
|
|
17
|
+
|
|
18
|
+
## 2.11.0 - 2025-04-12
|
|
19
|
+
- Require gems for ruby 3.4 that used to be in stdlib - Go Sueyoshi
|
|
20
|
+
- Refactor how timezone offsets are calculated - Pat Allan
|
|
21
|
+
- 'tzid' param is always returned as an array when accessing `ical_params` directly, rather than matching whatever the input parsed. ICS output remains unchanged
|
|
22
|
+
|
|
23
|
+
## 2.10.3 - 2024-09-21
|
|
24
|
+
- Override Icalendar::Value.== so that value objects can be compared to each other.
|
|
25
|
+
- Correctly load activesupport before activesupport/time
|
|
26
|
+
- Load ostruct to address deprecation warning - aki77
|
|
27
|
+
|
|
28
|
+
## 2.10.2 - 2024-07-21
|
|
29
|
+
- Raise Icalendar::Parser::ParseError on bad .ics file input instead of RuntimeError - Micah Geisel
|
|
30
|
+
- Remove Ruby 3.0 from the test matrix - still should work for now with ice_cube < 0.17.0
|
|
31
|
+
- Add Ruby 3.3 to the test matrix
|
|
32
|
+
- Move from old History.txt file to modern CHANGELOG.md - Guillaume Briday
|
|
33
|
+
|
|
34
|
+
## 2.10.1 - 2023-12-01
|
|
35
|
+
- Parsing now handles VTIMEZONE blocks defined after their TZID is used in events and other components
|
|
36
|
+
|
|
37
|
+
## 2.10.0 - 2023-11-01
|
|
38
|
+
- Add changelog metadata to gemspec - Juri Hahn
|
|
39
|
+
- Attempt to rescue timezone info when given a nonstandard tzid with no VTIMEZONE
|
|
40
|
+
- Move Values classes that shouldn't be directly used into Helpers module
|
|
41
|
+
|
|
42
|
+
## 2.9.0 - 2023-08-11
|
|
43
|
+
- Always include the VALUE of Event URLs for improved compatibility - Sean Kelley
|
|
44
|
+
- Improved parse performance - Thomas Cannon
|
|
45
|
+
- Add helper methods for other Calendar method verbs
|
|
46
|
+
- bugfix: Require stringio before use in Parser - vwyu
|
|
47
|
+
|
|
48
|
+
## 2.8.0 - 2022-07-10
|
|
49
|
+
- Fix compatibility with ActiveSupport 7 - Pat Allan
|
|
50
|
+
- Set default action of "DISPLAY" on alarms - Rikson
|
|
51
|
+
- Add license information to gemspec - Robert Reiz
|
|
52
|
+
- Support RFC7986 properties - Daniele Frisanco
|
|
53
|
+
|
|
54
|
+
## 2.7.1 - 2021-03-14
|
|
55
|
+
- Recover from bad line-wrapping code that splits in the middle of Unicode code points
|
|
56
|
+
- Add a verbose option to the Parser to quiet some of the chattier log entries
|
|
57
|
+
|
|
58
|
+
## 2.7.0 - 2020-09-12
|
|
59
|
+
- Handle custom component names, with and without X- prefix
|
|
60
|
+
- Fix Component lookup to avoid namespace collisions
|
|
61
|
+
|
|
62
|
+
## 2.6.1 - 2019-12-07
|
|
63
|
+
- Improve performance when generating large ICS files - Alex Balhatchet
|
|
64
|
+
|
|
65
|
+
## 2.6.0 - 2019-11-26
|
|
66
|
+
- Improve performance for calculating timezone offsets - Justin Howard
|
|
67
|
+
- Make it possible to de/serialize with Marshal - Pawel Niewiadomski
|
|
68
|
+
- Avoid FrozenError when running with frozen_string_literal
|
|
69
|
+
- Update minimum Ruby version to supported versions
|
|
70
|
+
|
|
71
|
+
## 2.5.3 - 2019-03-04
|
|
72
|
+
- Improve parsing performance - nehresma
|
|
73
|
+
- Support tzinfo 2.0 - Misty De Meo
|
|
74
|
+
|
|
75
|
+
## 2.5.2 - 2018-12-08
|
|
76
|
+
- Remove usage of the global TimezoneStore instance, in favor of a local variable in the parser
|
|
77
|
+
- Deprecate TimezoneStore class methods
|
|
78
|
+
|
|
79
|
+
## 2.5.1 - 2018-10-30
|
|
80
|
+
- Fix usage without ActiveSupport installed.
|
|
81
|
+
|
|
82
|
+
## 2.5.0 - 2018-09-10
|
|
83
|
+
- Set timezone information from VTIMEZONE components in cases that ActiveSupport can't figure it out (or isn't installed)
|
|
84
|
+
- Prevent rewinding the Parser IO input during parsing - Niels Laukens
|
|
85
|
+
- Update tested/supported ruby versions & documentation updates.
|
|
86
|
+
|
|
87
|
+
## 2.4.1 - 2016-09-03
|
|
88
|
+
- Fix parsing multiple calendars or components in same file - Patrick Schnetger
|
|
89
|
+
- Fix multi-byte folding bug - Niels Laukens
|
|
90
|
+
- Fix typos across the code - Martin Edenhofer & yuuji.yaginuma
|
|
91
|
+
|
|
92
|
+
## 2.4.0 - 2016-07-04
|
|
93
|
+
- Enable parsing individual ICalendar components - Patrick Schnetger
|
|
94
|
+
- many bug fixes. Thanks to Quan Sun, Garry Shutler, Ryan Bigg, Patrick Schnetger and others
|
|
95
|
+
- README/documentation updates. Thanks to JonMidhir and Hendrik Sollich
|
|
96
|
+
|
|
97
|
+
## 2.3.0 - 2015-04-26
|
|
98
|
+
- fix value parameter for properties with multiple values
|
|
99
|
+
- fix error when assigning Icalendar::Values::Array to a component
|
|
100
|
+
- Fall back to Icalendar::Values::Date if Icalendar::Values::DateTime is not given a properly formatted value
|
|
101
|
+
- Downcase the keys in ical_params to ensure we aren't assigning both tzid and TZID
|
|
102
|
+
|
|
103
|
+
## 2.2.2 - 2014-12-27
|
|
104
|
+
- add a `has_#{component}?` method for testing if component exists - John Hope
|
|
105
|
+
- add documentation & tests for organizer attribute - Ben Walding
|
|
106
|
+
|
|
107
|
+
## 2.2.1 - 2014-12-03
|
|
108
|
+
- Prevent crashes when using ActiveSupport::TimeWithZone in multi-property DateTime fields - Danny (tdg5)
|
|
109
|
+
- Ensure TimeWithZone is loaded before using, not just ActiveSupport - Jeremy Evans
|
|
110
|
+
- Improve error message on unparseable DateTimes - Garry Shutler
|
|
111
|
+
|
|
112
|
+
## 2.2.0 - 2014-09-23
|
|
113
|
+
- Default to non-strict parsing
|
|
114
|
+
- Enable sorting events by dtstart - Mark Rickert
|
|
115
|
+
- Better tolerate malformed lines in parser - Garry Shutler
|
|
116
|
+
- Deduplicate timezone code - Jan Vlnas
|
|
117
|
+
- Eliminate warnings - rochefort
|
|
118
|
+
|
|
119
|
+
## 2.1.2 - 2014-09-10
|
|
120
|
+
- Fix timezone abbreviation generation - Jan Vlnas
|
|
121
|
+
- Fix timezone repeat rules for end of month
|
|
122
|
+
|
|
123
|
+
## 2.1.1 - 2014-07-23
|
|
124
|
+
- Quiet TimeWithZone support logging
|
|
125
|
+
- Use SecureRandom.uuid - antoinelyset
|
|
126
|
+
|
|
127
|
+
## 2.1.0 - 2014-06-17
|
|
128
|
+
- Enable parsing all custom properties, not just X- prefixed ones
|
|
129
|
+
Requires non-strict parsing
|
|
130
|
+
- Fixed bugs when using non-MRI ruby interpreters
|
|
131
|
+
- Fix bug copying OpenStruct-backed value types
|
|
132
|
+
|
|
133
|
+
## 2.0.1 - 2014-04-27
|
|
134
|
+
- Re-add support for ruby 1.9.2
|
|
135
|
+
|
|
136
|
+
## 2.0.0 - 2014-04-22
|
|
137
|
+
- Add Icalendar.logger class & logging in Parser
|
|
138
|
+
- Support tzinfo ~> 0.3 and ~> 1.1
|
|
139
|
+
|
|
140
|
+
## 2.0.0.beta.2 - 2014-04-11
|
|
141
|
+
- Add uid & acknowledged fields from valarm extensions
|
|
142
|
+
- Swallow NoMethodError on non-strict parsers
|
|
143
|
+
- Expose a parse_property method on Icalendar::Parser
|
|
144
|
+
|
|
145
|
+
## 2.0.0.beta.1 - 2014-03-30
|
|
146
|
+
- Rewrite for easier development going forward.
|
|
147
|
+
|
|
148
|
+
## 1.5.2 - 2014-02-22
|
|
149
|
+
- Output timezone components first
|
|
150
|
+
- Fix undefined local variable or method 'e' - Jason Stirk
|
|
151
|
+
|
|
152
|
+
## 1.5.1 - 2014-02-27
|
|
153
|
+
- Check for dtend existence before setting timezone - Jonas Grau
|
|
154
|
+
- Clean up and refactor components - Kasper Timm Hansen
|
|
155
|
+
|
|
156
|
+
## 1.5.0 - 2013-12-06
|
|
157
|
+
- Support for custom x- properties - Jake Craige
|
|
158
|
+
|
|
159
|
+
## 1.4.5 - 2013-11-14
|
|
160
|
+
- Fix Geo accessor methods - bouzuya
|
|
161
|
+
- Add ical_multiline_property :related_to for Alarm
|
|
162
|
+
- Allow using multi setters to append single values
|
|
163
|
+
|
|
164
|
+
## 1.4.4 - 2013-11-05
|
|
165
|
+
- Allow user to handle TZInfo::AmbiguousTime error - David Bradford
|
|
166
|
+
- Better handling of multiple exdate and rdate values
|
|
167
|
+
|
|
168
|
+
## 1.4.3 - 2013-09-18
|
|
169
|
+
- Fix concatenation of multiple BYWEEK or BYMONTH recurrence rules
|
|
170
|
+
|
|
171
|
+
## 1.4.2 - 2013-09-11
|
|
172
|
+
- Double Quote parameter values that contain forbidden characters
|
|
173
|
+
- Update Component#respond_to? to match Ruby 2.0 - Keith Marcum
|
|
174
|
+
|
|
175
|
+
## 1.4.1 - 2013-06-25
|
|
176
|
+
- Don't escape semicolon in GEO property - temirov
|
|
177
|
+
- Allow access to various parts of RRule class
|
|
178
|
+
|
|
179
|
+
## 1.4.0 - 2013-05-21
|
|
180
|
+
- Implement ACKNOWLEDGED property for VALARM - tsuzuki08
|
|
181
|
+
- Output VERSION property as first line after BEGIN:VCALENDAR
|
|
182
|
+
- Check for unbounded timezone transitions in tzinfo
|
|
183
|
+
|
|
184
|
+
## 1.3.0 - 2013-03-31
|
|
185
|
+
- Lenient parsing mode ignores unknown properties - David Grandinetti
|
|
186
|
+
- VTIMEZONE positive offsets properly have "+" prepended (Fixed issue
|
|
187
|
+
#18) - Benjamin Jorgensen (sorry for misspelling your last name)
|
|
188
|
+
|
|
189
|
+
## 1.2.4 - 2013-03-26
|
|
190
|
+
- Proxy component values now frozen in Ruby 2.0 (Fixed issue #17)
|
|
191
|
+
- Clean up gemspec for cleaner installing via bundler/git
|
|
192
|
+
|
|
193
|
+
## 1.2.3 - 2013-03-09
|
|
194
|
+
- Call `super` from Component#method_missing
|
|
195
|
+
- Clean up warnings in test suite
|
|
196
|
+
- Add Gemfile for installing development dependencies
|
|
197
|
+
|
|
198
|
+
## 1.2.2 - 2013-02-16
|
|
199
|
+
- added TZURL property to Timezone component - spacepixels
|
|
200
|
+
- correct days in RRule ("[TU,WE]" -> "TU,WE") - Christoph Finkensiep
|
|
201
|
+
|
|
202
|
+
## 1.2.1 - 2012-11-12
|
|
203
|
+
- Adds uid property to alarms to support iCloud - Jeroen Jacobs
|
|
204
|
+
- Fix up testing docs - Eric Carty-Fickes
|
|
205
|
+
- Fix parsing property params that have : in them - Sean Dague
|
|
206
|
+
- Clean up warnings in test suite - Sean Dague
|
|
207
|
+
|
|
208
|
+
## 1.2.0 - 2012-08-30
|
|
209
|
+
* Fix calendar handling for dates < 1000 - Ryan Ahearn
|
|
210
|
+
* Updated license to GPL/BSD/Ruby at users option
|
|
211
|
+
|
|
212
|
+
## 1.1.6 - 2011-03-10
|
|
213
|
+
* Fix todo handling (thanks to Frank Schwarz)
|
|
214
|
+
* clean up a number of warnings during test runs
|
|
215
|
+
|
|
216
|
+
## 1.1.5 - 2010-06-21
|
|
217
|
+
* Fix for windows line endings (thanks to Rowan Collins)
|
|
218
|
+
|
|
219
|
+
## 1.1.4 - 2010-04-23
|
|
220
|
+
* Fix for RRULE escaping
|
|
221
|
+
* Fix tests so they run under 1.8.7 in multiple environments
|
|
222
|
+
* Readme fix
|
|
223
|
+
|
|
224
|
+
## 1.1.3 - 2010-03-15
|
|
225
|
+
* Revert component sorting behavior that I was trying to make
|
|
226
|
+
the tests run more consistantly on different platforms.
|
|
227
|
+
* Added new test for multiple events in a calendar which caught that break.
|
|
228
|
+
|
|
229
|
+
## 1.1.2 - 2010-03-10
|
|
230
|
+
|
|
231
|
+
* Convert project to newgem to make for easier publishing
|
data/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
iCalendar -- Internet calendaring, Ruby style
|
|
2
2
|
===
|
|
3
3
|
|
|
4
|
-
[](https://github.com/icalendar/icalendar/actions/workflows/main.yml)
|
|
5
5
|
[](https://codeclimate.com/github/icalendar/icalendar)
|
|
6
6
|
|
|
7
7
|
<http://github.com/icalendar/icalendar>
|
data/icalendar.gemspec
CHANGED
|
@@ -21,7 +21,7 @@ ActiveSupport is required for TimeWithZone support, but not required for general
|
|
|
21
21
|
EOM
|
|
22
22
|
|
|
23
23
|
s.metadata = {
|
|
24
|
-
'changelog_uri' => 'https://github.com/icalendar/icalendar/blob/main/
|
|
24
|
+
'changelog_uri' => 'https://github.com/icalendar/icalendar/blob/main/CHANGELOG.md'
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
s.files = `git ls-files`.split "\n"
|
|
@@ -31,7 +31,10 @@ ActiveSupport is required for TimeWithZone support, but not required for general
|
|
|
31
31
|
|
|
32
32
|
s.required_ruby_version = '>= 2.4.0'
|
|
33
33
|
|
|
34
|
+
s.add_dependency 'base64'
|
|
34
35
|
s.add_dependency 'ice_cube', '~> 0.16'
|
|
36
|
+
s.add_dependency 'logger'
|
|
37
|
+
s.add_dependency 'ostruct'
|
|
35
38
|
|
|
36
39
|
s.add_development_dependency 'rake', '~> 13.0'
|
|
37
40
|
s.add_development_dependency 'bundler', '~> 2.0'
|
|
@@ -3,32 +3,65 @@
|
|
|
3
3
|
require 'delegate'
|
|
4
4
|
|
|
5
5
|
module Icalendar
|
|
6
|
-
class DowncasedHash
|
|
6
|
+
class DowncasedHash
|
|
7
7
|
|
|
8
8
|
def initialize(base)
|
|
9
|
-
|
|
9
|
+
@obj = Hash.new
|
|
10
10
|
base.each do |key, value|
|
|
11
11
|
self[key] = value
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def []=(key, value)
|
|
16
|
-
|
|
16
|
+
obj[key.to_s.downcase] = value
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def [](key)
|
|
20
|
-
|
|
20
|
+
obj[key.to_s.downcase]
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def has_key?(key)
|
|
24
|
-
|
|
24
|
+
obj.has_key? key.to_s.downcase
|
|
25
25
|
end
|
|
26
26
|
alias_method :include?, :has_key?
|
|
27
27
|
alias_method :member?, :has_key?
|
|
28
28
|
|
|
29
29
|
def delete(key, &block)
|
|
30
|
-
|
|
30
|
+
obj.delete key.to_s.downcase, &block
|
|
31
31
|
end
|
|
32
|
+
|
|
33
|
+
def merge(*other_hashes)
|
|
34
|
+
Icalendar::DowncasedHash.new(obj).merge!(*other_hashes)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def merge!(*other_hashes)
|
|
38
|
+
other_hashes.each do |hash|
|
|
39
|
+
hash.each do |key, value|
|
|
40
|
+
self[key] = value
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
self
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def empty?
|
|
47
|
+
obj.empty?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def each(&block)
|
|
51
|
+
obj.each &block
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def map(&block)
|
|
55
|
+
obj.map &block
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def ==(other)
|
|
59
|
+
obj == Icalendar::DowncasedHash(other).obj
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
protected
|
|
63
|
+
|
|
64
|
+
attr_reader :obj
|
|
32
65
|
end
|
|
33
66
|
|
|
34
67
|
def self.DowncasedHash(base)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Icalendar
|
|
4
|
+
class Offset
|
|
5
|
+
class ActiveSupportExact < Icalendar::Offset
|
|
6
|
+
def valid?
|
|
7
|
+
support_classes_defined? && tz
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def normalized_value
|
|
11
|
+
Icalendar.logger.debug("Plan a - parsing #{value}/#{tzid} as ActiveSupport::TimeWithZone")
|
|
12
|
+
# plan a - use ActiveSupport::TimeWithZone
|
|
13
|
+
Icalendar::Values::Helpers::ActiveSupportTimeWithZoneAdapter.new(nil, tz, value)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def tz
|
|
19
|
+
@tz ||= ActiveSupport::TimeZone[tzid]
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Icalendar
|
|
4
|
+
class Offset
|
|
5
|
+
class ActiveSupportPartial < Offset
|
|
6
|
+
def valid?
|
|
7
|
+
support_classes_defined? && tz
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def normalized_value
|
|
11
|
+
# plan c - try to find an ActiveSupport::TimeWithZone based on the first word of the tzid
|
|
12
|
+
Icalendar.logger.debug("Plan c - parsing #{value}/#{tz.tzinfo.name} as ActiveSupport::TimeWithZone")
|
|
13
|
+
Icalendar::Values::Helpers::ActiveSupportTimeWithZoneAdapter.new(nil, tz, value)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def normalized_tzid
|
|
17
|
+
[tz.tzinfo.name]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def tz
|
|
23
|
+
@tz ||= ActiveSupport::TimeZone[tzid.split.first]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Icalendar
|
|
4
|
+
class Offset
|
|
5
|
+
class Null < Offset
|
|
6
|
+
def valid?
|
|
7
|
+
true
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def normalized_value
|
|
11
|
+
# plan d - just ignore the tzid
|
|
12
|
+
Icalendar.logger.info("Ignoring timezone #{tzid} for time #{value}")
|
|
13
|
+
nil
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Icalendar
|
|
4
|
+
class Offset
|
|
5
|
+
class TimeZoneStore < Offset
|
|
6
|
+
def valid?
|
|
7
|
+
timezone_store && tz_info
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def normalized_value
|
|
11
|
+
# plan b - use definition from provided `VTIMEZONE`
|
|
12
|
+
offset = tz_info.offset_for_local(value).to_s
|
|
13
|
+
|
|
14
|
+
Icalendar.logger.debug("Plan b - parsing #{value} with offset: #{offset}")
|
|
15
|
+
if value.respond_to?(:change)
|
|
16
|
+
value.change offset: offset
|
|
17
|
+
else
|
|
18
|
+
::Time.new value.year, value.month, value.day, value.hour, value.min, value.sec, offset
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def tz_info
|
|
25
|
+
@tz_info ||= timezone_store.retrieve(tzid)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This module contains mappings from Windows timezone identifiers to Olson timezone identifiers.
|
|
4
|
+
#
|
|
5
|
+
# The data is taken from the unicode consortium [0], the proposal and rationale
|
|
6
|
+
# for this mapping is also available at the unicode consortium [1].
|
|
7
|
+
#
|
|
8
|
+
# [0] https://www.unicode.org/cldr/cldr-aux/charts/29/supplemental/zone_tzid.html
|
|
9
|
+
# [1] https://cldr.unicode.org/development/development-process/design-proposals/extended-windows-olson-zid-mapping
|
|
10
|
+
|
|
11
|
+
module Icalendar
|
|
12
|
+
class Offset
|
|
13
|
+
class WindowsToIana < Offset
|
|
14
|
+
WINDOWS_TO_IANA = {
|
|
15
|
+
'AUS Central Standard Time' => 'Australia/Darwin',
|
|
16
|
+
'AUS Eastern Standard Time' => 'Australia/Sydney',
|
|
17
|
+
'Afghanistan Standard Time' => 'Asia/Kabul',
|
|
18
|
+
'Alaskan Standard Time' => 'America/Anchorage',
|
|
19
|
+
'Arab Standard Time' => 'Asia/Riyadh',
|
|
20
|
+
'Arabian Standard Time' => 'Asia/Dubai',
|
|
21
|
+
'Arabic Standard Time' => 'Asia/Baghdad',
|
|
22
|
+
'Argentina Standard Time' => 'America/Argentina/Buenos_Aires',
|
|
23
|
+
'Atlantic Standard Time' => 'America/Halifax',
|
|
24
|
+
'Azerbaijan Standard Time' => 'Asia/Baku',
|
|
25
|
+
'Azores Standard Time' => 'Atlantic/Azores',
|
|
26
|
+
'Bahia Standard Time' => 'America/Bahia',
|
|
27
|
+
'Bangladesh Standard Time' => 'Asia/Dhaka',
|
|
28
|
+
'Belarus Standard Time' => 'Europe/Minsk',
|
|
29
|
+
'Canada Central Standard Time' => 'America/Regina',
|
|
30
|
+
'Cape Verde Standard Time' => 'Atlantic/Cape_Verde',
|
|
31
|
+
'Caucasus Standard Time' => 'Asia/Yerevan',
|
|
32
|
+
'Cen. Australia Standard Time' => 'Australia/Adelaide',
|
|
33
|
+
'Central America Standard Time' => 'America/Guatemala',
|
|
34
|
+
'Central Asia Standard Time' => 'Asia/Almaty',
|
|
35
|
+
'Central Brazilian Standard Time' => 'America/Cuiaba',
|
|
36
|
+
'Central Europe Standard Time' => 'Europe/Budapest',
|
|
37
|
+
'Central European Standard Time' => 'Europe/Warsaw',
|
|
38
|
+
'Central Pacific Standard Time' => 'Pacific/Guadalcanal',
|
|
39
|
+
'Central Standard Time' => 'America/Chicago',
|
|
40
|
+
'Central Standard Time (Mexico)' => 'America/Mexico_City',
|
|
41
|
+
'China Standard Time' => 'Asia/Shanghai',
|
|
42
|
+
'Dateline Standard Time' => 'Etc/GMT+12',
|
|
43
|
+
'E. Africa Standard Time' => 'Africa/Nairobi',
|
|
44
|
+
'E. Australia Standard Time' => 'Australia/Brisbane',
|
|
45
|
+
'E. Europe Standard Time' => 'Europe/Chisinau',
|
|
46
|
+
'E. South America Standard Time' => 'America/Sao_Paulo',
|
|
47
|
+
'Eastern Standard Time' => 'America/New_York',
|
|
48
|
+
'Eastern Standard Time (Mexico)' => 'America/Cancun',
|
|
49
|
+
'Egypt Standard Time' => 'Africa/Cairo',
|
|
50
|
+
'Ekaterinburg Standard Time' => 'Asia/Yekaterinburg',
|
|
51
|
+
'FLE Standard Time' => 'Europe/Kyiv',
|
|
52
|
+
'Fiji Standard Time' => 'Pacific/Fiji',
|
|
53
|
+
'GMT Standard Time' => 'Europe/London',
|
|
54
|
+
'GTB Standard Time' => 'Europe/Bucharest',
|
|
55
|
+
'Georgian Standard Time' => 'Asia/Tbilisi',
|
|
56
|
+
'Greenland Standard Time' => 'America/Nuuk',
|
|
57
|
+
'Greenwich Standard Time' => 'Atlantic/Reykjavik',
|
|
58
|
+
'Hawaiian Standard Time' => 'Pacific/Honolulu',
|
|
59
|
+
'India Standard Time' => 'Asia/Kolkata',
|
|
60
|
+
'Iran Standard Time' => 'Asia/Tehran',
|
|
61
|
+
'Israel Standard Time' => 'Asia/Jerusalem',
|
|
62
|
+
'Jordan Standard Time' => 'Asia/Amman',
|
|
63
|
+
'Kaliningrad Standard Time' => 'Europe/Kaliningrad',
|
|
64
|
+
'Korea Standard Time' => 'Asia/Seoul',
|
|
65
|
+
'Libya Standard Time' => 'Africa/Tripoli',
|
|
66
|
+
'Line Islands Standard Time' => 'Pacific/Kiritimati',
|
|
67
|
+
'Magadan Standard Time' => 'Asia/Magadan',
|
|
68
|
+
'Mauritius Standard Time' => 'Indian/Mauritius',
|
|
69
|
+
'Middle East Standard Time' => 'Asia/Beirut',
|
|
70
|
+
'Montevideo Standard Time' => 'America/Montevideo',
|
|
71
|
+
'Morocco Standard Time' => 'Africa/Casablanca',
|
|
72
|
+
'Mountain Standard Time' => 'America/Denver',
|
|
73
|
+
'Mountain Standard Time (Mexico)' => 'America/Chihuahua',
|
|
74
|
+
'Myanmar Standard Time' => 'Asia/Yangon',
|
|
75
|
+
'N. Central Asia Standard Time' => 'Asia/Novosibirsk',
|
|
76
|
+
'Namibia Standard Time' => 'Africa/Windhoek',
|
|
77
|
+
'Nepal Standard Time' => 'Asia/Kathmandu',
|
|
78
|
+
'New Zealand Standard Time' => 'Pacific/Auckland',
|
|
79
|
+
'Newfoundland Standard Time' => 'America/St_Johns',
|
|
80
|
+
'North Asia East Standard Time' => 'Asia/Irkutsk',
|
|
81
|
+
'North Asia Standard Time' => 'Asia/Krasnoyarsk',
|
|
82
|
+
'North Korea Standard Time' => 'Asia/Pyongyang',
|
|
83
|
+
'Pacific SA Standard Time' => 'America/Santiago',
|
|
84
|
+
'Pacific Standard Time' => 'America/Los_Angeles',
|
|
85
|
+
'Pakistan Standard Time' => 'Asia/Karachi',
|
|
86
|
+
'Paraguay Standard Time' => 'America/Asuncion',
|
|
87
|
+
'Romance Standard Time' => 'Europe/Paris',
|
|
88
|
+
'Russia Time Zone 10' => 'Asia/Srednekolymsk',
|
|
89
|
+
'Russia Time Zone 11' => 'Asia/Kamchatka',
|
|
90
|
+
'Russia Time Zone 3' => 'Europe/Samara',
|
|
91
|
+
'Russian Standard Time' => 'Europe/Moscow',
|
|
92
|
+
'SA Eastern Standard Time' => 'America/Cayenne',
|
|
93
|
+
'SA Pacific Standard Time' => 'America/Bogota',
|
|
94
|
+
'SA Western Standard Time' => 'America/La_Paz',
|
|
95
|
+
'SE Asia Standard Time' => 'Asia/Bangkok',
|
|
96
|
+
'Samoa Standard Time' => 'Pacific/Apia',
|
|
97
|
+
'Singapore Standard Time' => 'Asia/Singapore',
|
|
98
|
+
'South Africa Standard Time' => 'Africa/Johannesburg',
|
|
99
|
+
'Sri Lanka Standard Time' => 'Asia/Colombo',
|
|
100
|
+
'Syria Standard Time' => 'Asia/Damascus',
|
|
101
|
+
'Taipei Standard Time' => 'Asia/Taipei',
|
|
102
|
+
'Tasmania Standard Time' => 'Australia/Hobart',
|
|
103
|
+
'Tokyo Standard Time' => 'Asia/Tokyo',
|
|
104
|
+
'Tonga Standard Time' => 'Pacific/Tongatapu',
|
|
105
|
+
'Turkey Standard Time' => 'Europe/Istanbul',
|
|
106
|
+
'US Eastern Standard Time' => 'America/Indiana/Indianapolis',
|
|
107
|
+
'US Mountain Standard Time' => 'America/Phoenix',
|
|
108
|
+
'UTC' => 'Etc/GMT',
|
|
109
|
+
'UTC+12' => 'Etc/GMT-12',
|
|
110
|
+
'UTC-02' => 'Etc/GMT+2',
|
|
111
|
+
'UTC-11' => 'Etc/GMT+11',
|
|
112
|
+
'Ulaanbaatar Standard Time' => 'Asia/Ulaanbaatar',
|
|
113
|
+
'Venezuela Standard Time' => 'America/Caracas',
|
|
114
|
+
'Vladivostok Standard Time' => 'Asia/Vladivostok',
|
|
115
|
+
'W. Australia Standard Time' => 'Australia/Perth',
|
|
116
|
+
'W. Central Africa Standard Time' => 'Africa/Lagos',
|
|
117
|
+
'W. Europe Standard Time' => 'Europe/Berlin',
|
|
118
|
+
'West Asia Standard Time' => 'Asia/Tashkent',
|
|
119
|
+
'West Pacific Standard Time' => 'Pacific/Port_Moresby',
|
|
120
|
+
'Yakutsk Standard Time' => 'Asia/Yakutsk'
|
|
121
|
+
}.freeze
|
|
122
|
+
|
|
123
|
+
def valid?
|
|
124
|
+
support_classes_defined? && tz
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def normalized_value
|
|
128
|
+
Icalendar.logger.debug("Plan a - parsing #{value}/#{tzid} as ActiveSupport::TimeWithZone")
|
|
129
|
+
# plan a - use ActiveSupport::TimeWithZone
|
|
130
|
+
Icalendar::Values::Helpers::ActiveSupportTimeWithZoneAdapter.new(nil, tz, value)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def normalized_tzid
|
|
134
|
+
[WINDOWS_TO_IANA[tzid]].compact
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
private
|
|
138
|
+
|
|
139
|
+
def tz
|
|
140
|
+
@tz ||= ActiveSupport::TimeZone[normalized_tzid.first || '']
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Icalendar
|
|
4
|
+
class Offset
|
|
5
|
+
def self.build(value, params, timezone_store)
|
|
6
|
+
return nil if params.nil? || params['tzid'].nil?
|
|
7
|
+
|
|
8
|
+
tzid = Array(params['tzid']).first
|
|
9
|
+
|
|
10
|
+
[
|
|
11
|
+
Icalendar::Offset::ActiveSupportExact,
|
|
12
|
+
Icalendar::Offset::TimeZoneStore,
|
|
13
|
+
Icalendar::Offset::WindowsToIana,
|
|
14
|
+
Icalendar::Offset::ActiveSupportPartial,
|
|
15
|
+
Icalendar::Offset::Null
|
|
16
|
+
].lazy.map { |klass| klass.new(tzid, value, timezone_store) }.detect(&:valid?)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def initialize(tzid, value, timezone_store)
|
|
20
|
+
@tzid = tzid
|
|
21
|
+
@value = value
|
|
22
|
+
@timezone_store = timezone_store
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def normalized_tzid
|
|
26
|
+
Array(tzid)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
attr_reader :tzid, :value, :timezone_store
|
|
32
|
+
|
|
33
|
+
def support_classes_defined?
|
|
34
|
+
defined?(ActiveSupport::TimeZone) &&
|
|
35
|
+
defined?(Icalendar::Values::Helpers::ActiveSupportTimeWithZoneAdapter)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
require_relative 'offset/active_support_exact'
|
|
41
|
+
require_relative 'offset/active_support_partial'
|
|
42
|
+
require_relative 'offset/null'
|
|
43
|
+
require_relative 'offset/time_zone_store'
|
|
44
|
+
require_relative 'offset/windows_to_iana'
|