icalendar 2.10.0 → 2.10.1
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/History.txt +3 -0
- data/icalendar.gemspec +7 -6
- data/lib/icalendar/parser.rb +1 -1
- data/lib/icalendar/timezone.rb +6 -4
- data/lib/icalendar/values/date.rb +1 -1
- data/lib/icalendar/values/helpers/time_with_zone.rb +34 -9
- data/lib/icalendar/version.rb +1 -1
- data/spec/fixtures/reversed_timezone.ics +143 -0
- data/spec/parser_spec.rb +9 -0
- metadata +23 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b9f7e30ef6614ad4175a9d282d1b03b57f140f98a2962b4e0268aa015f8f942
|
4
|
+
data.tar.gz: 7ebabfddd0f3d8e8e05e1ef82d2389007c1419c727c5404d2ec2c1c09565a8bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d3221e4e5bd2120014ae11fe80a8e0a3b36af37b10aadd18f3bc6022e296efa47ea27d09572900bb6d6419fff64054caa6709e6b14e5182d32a188d0130b7f0
|
7
|
+
data.tar.gz: 5d7d996d53a12543de0830fdb8214e2ae39df4c19c649e81cd95ceb8d30d61f1f178b7a9a4f4e37adb591609eeac7e89d930cf5ffc24951c9cbfcb0b815c2a03
|
data/History.txt
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
=== Unreleased
|
2
2
|
|
3
|
+
=== 2.10.1 2023-12-01
|
4
|
+
* Parsing now handles VTIMEZONE blocks defined after their TZID is used in events and other components
|
5
|
+
|
3
6
|
=== 2.10.0 2023-11-01
|
4
7
|
* Add changelog metadata to gemspec - Juri Hahn
|
5
8
|
* Attempt to rescue timezone info when given a nonstandard tzid with no VTIMEZONE
|
data/icalendar.gemspec
CHANGED
@@ -38,13 +38,13 @@ ActiveSupport is required for TimeWithZone support, but not required for general
|
|
38
38
|
|
39
39
|
# test with all groups of tzinfo dependencies
|
40
40
|
# tzinfo 2.x
|
41
|
-
|
42
|
-
|
43
|
-
# tzinfo 1.x
|
44
|
-
s.add_development_dependency 'activesupport', '~> 6.0'
|
45
|
-
s.add_development_dependency 'i18n', '~> 1.8'
|
46
|
-
s.add_development_dependency 'tzinfo', '~> 1.2'
|
41
|
+
s.add_development_dependency 'activesupport', '~> 7.1'
|
42
|
+
s.add_development_dependency 'tzinfo', '~> 2.0'
|
47
43
|
s.add_development_dependency 'tzinfo-data', '~> 1.2020'
|
44
|
+
# tzinfo 1.x
|
45
|
+
# s.add_development_dependency 'activesupport', '~> 6.0'
|
46
|
+
# s.add_development_dependency 'tzinfo', '~> 1.2'
|
47
|
+
# s.add_development_dependency 'tzinfo-data', '~> 1.2020'
|
48
48
|
# tzinfo 0.x
|
49
49
|
# s.add_development_dependency 'tzinfo', '~> 0.3'
|
50
50
|
# end tzinfo
|
@@ -52,4 +52,5 @@ ActiveSupport is required for TimeWithZone support, but not required for general
|
|
52
52
|
s.add_development_dependency 'timecop', '~> 0.9'
|
53
53
|
s.add_development_dependency 'rspec', '~> 3.8'
|
54
54
|
s.add_development_dependency 'simplecov', '~> 0.16'
|
55
|
+
s.add_development_dependency 'byebug'
|
55
56
|
end
|
data/lib/icalendar/parser.rb
CHANGED
@@ -211,7 +211,7 @@ module Icalendar
|
|
211
211
|
param_value = param_value.gsub(PVALUE_GSUB_REGEX, '')
|
212
212
|
params[param_name] << param_value
|
213
213
|
if param_name == 'tzid'
|
214
|
-
params['x-tz-
|
214
|
+
params['x-tz-store'] = timezone_store
|
215
215
|
end
|
216
216
|
end
|
217
217
|
end
|
data/lib/icalendar/timezone.rb
CHANGED
@@ -108,15 +108,17 @@ module Icalendar
|
|
108
108
|
|
109
109
|
def standard_for(local)
|
110
110
|
possible = standards.map do |std|
|
111
|
-
|
112
|
-
|
111
|
+
prev = std.previous_occurrence(local.to_time)
|
112
|
+
[prev, std] unless prev.nil?
|
113
|
+
end.compact
|
113
114
|
possible.sort_by(&:first).last
|
114
115
|
end
|
115
116
|
|
116
117
|
def daylight_for(local)
|
117
118
|
possible = daylights.map do |day|
|
118
|
-
|
119
|
-
|
119
|
+
prev = day.previous_occurrence(local.to_time)
|
120
|
+
[prev, day] unless prev.nil?
|
121
|
+
end.compact
|
120
122
|
possible.sort_by(&:first).last
|
121
123
|
end
|
122
124
|
end
|
@@ -20,22 +20,45 @@ module Icalendar
|
|
20
20
|
module Values
|
21
21
|
module Helpers
|
22
22
|
module TimeWithZone
|
23
|
-
attr_reader :tz_utc
|
23
|
+
attr_reader :tz_utc, :timezone_store
|
24
24
|
|
25
25
|
def initialize(value, params = {})
|
26
26
|
params = Icalendar::DowncasedHash(params)
|
27
27
|
@tz_utc = params['tzid'] == 'UTC'
|
28
|
-
|
28
|
+
@timezone_store = params.delete 'x-tz-store'
|
29
|
+
super (offset_value(value, params) || value), params
|
30
|
+
end
|
31
|
+
|
32
|
+
def __getobj__
|
33
|
+
orig_value = super
|
34
|
+
if set_offset?
|
35
|
+
orig_value
|
36
|
+
else
|
37
|
+
offset = offset_value(orig_value, ical_params)
|
38
|
+
__setobj__(offset) unless offset.nil?
|
39
|
+
offset || orig_value
|
40
|
+
end
|
41
|
+
end
|
29
42
|
|
30
|
-
|
43
|
+
def params_ical
|
44
|
+
ical_params.delete 'tzid' if tz_utc
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def offset_value(value, params)
|
51
|
+
@offset_value = unless params.nil? || params['tzid'].nil?
|
31
52
|
tzid = params['tzid'].is_a?(::Array) ? params['tzid'].first : params['tzid']
|
32
53
|
support_classes_defined = defined?(ActiveSupport::TimeZone) && defined?(ActiveSupportTimeWithZoneAdapter)
|
33
54
|
if support_classes_defined && (tz = ActiveSupport::TimeZone[tzid])
|
55
|
+
Icalendar.logger.debug("Plan a - parsing #{value}/#{tzid} as ActiveSupport::TimeWithZone")
|
34
56
|
# plan a - use ActiveSupport::TimeWithZone
|
35
57
|
ActiveSupportTimeWithZoneAdapter.new(nil, tz, value)
|
36
|
-
elsif !x_tz_info.nil?
|
58
|
+
elsif !timezone_store.nil? && !(x_tz_info = timezone_store.retrieve(tzid)).nil?
|
37
59
|
# plan b - use definition from provided `VTIMEZONE`
|
38
60
|
offset = x_tz_info.offset_for_local(value).to_s
|
61
|
+
Icalendar.logger.debug("Plan b - parsing #{value} with offset: #{offset}")
|
39
62
|
if value.respond_to?(:change)
|
40
63
|
value.change offset: offset
|
41
64
|
else
|
@@ -43,17 +66,19 @@ module Icalendar
|
|
43
66
|
end
|
44
67
|
elsif support_classes_defined && (tz = ActiveSupport::TimeZone[tzid.split.first])
|
45
68
|
# plan c - try to find an ActiveSupport::TimeWithZone based on the first word of the tzid
|
69
|
+
Icalendar.logger.debug("Plan c - parsing #{value}/#{tz.tzinfo.name} as ActiveSupport::TimeWithZone")
|
46
70
|
params['tzid'] = [tz.tzinfo.name]
|
47
71
|
ActiveSupportTimeWithZoneAdapter.new(nil, tz, value)
|
72
|
+
else
|
73
|
+
# plan d - just ignore the tzid
|
74
|
+
Icalendar.logger.info("Ignoring timezone #{tzid} for time #{value}")
|
75
|
+
nil
|
48
76
|
end
|
49
|
-
# plan d - just ignore the tzid
|
50
77
|
end
|
51
|
-
super((offset_value || value), params)
|
52
78
|
end
|
53
79
|
|
54
|
-
def
|
55
|
-
|
56
|
-
super
|
80
|
+
def set_offset?
|
81
|
+
!!@offset_value
|
57
82
|
end
|
58
83
|
end
|
59
84
|
end
|
data/lib/icalendar/version.rb
CHANGED
@@ -0,0 +1,143 @@
|
|
1
|
+
BEGIN:VCALENDAR
|
2
|
+
VERSION:2.0
|
3
|
+
X-WR-CALNAME:My Calendar
|
4
|
+
X-APPLE-CALENDAR-COLOR:#44A703
|
5
|
+
BEGIN:VEVENT
|
6
|
+
CREATED:20231026T211915Z
|
7
|
+
DTEND;TZID=NONSTANDARDTZ:20231025T180000
|
8
|
+
DTSTAMP:20231026T211916Z
|
9
|
+
DTSTART;TZID=NONSTANDARDTZ:20231025T163000
|
10
|
+
LAST-MODIFIED:20231026T211915Z
|
11
|
+
LOCATION:Somewhere
|
12
|
+
SEQUENCE:0
|
13
|
+
SUMMARY:Summary summary summary
|
14
|
+
UID:some-unique-uid
|
15
|
+
END:VEVENT
|
16
|
+
BEGIN:VTIMEZONE
|
17
|
+
TZID:NONSTANDARDTZ
|
18
|
+
X-LIC-LOCATION:NONSTANDARDTZ
|
19
|
+
BEGIN:STANDARD
|
20
|
+
DTSTART:18831118T120702
|
21
|
+
RDATE:18831118T120702
|
22
|
+
TZNAME:PST
|
23
|
+
TZOFFSETFROM:-075258
|
24
|
+
TZOFFSETTO:-0800
|
25
|
+
END:STANDARD
|
26
|
+
BEGIN:DAYLIGHT
|
27
|
+
DTSTART:19180331T020000
|
28
|
+
RRULE:FREQ=YEARLY;UNTIL=19190330T100000Z;BYMONTH=3;BYDAY=-1SU
|
29
|
+
TZNAME:PDT
|
30
|
+
TZOFFSETFROM:-0800
|
31
|
+
TZOFFSETTO:-0700
|
32
|
+
END:DAYLIGHT
|
33
|
+
BEGIN:STANDARD
|
34
|
+
DTSTART:19181027T020000
|
35
|
+
RRULE:FREQ=YEARLY;UNTIL=19191026T090000Z;BYMONTH=10;BYDAY=-1SU
|
36
|
+
TZNAME:PST
|
37
|
+
TZOFFSETFROM:-0700
|
38
|
+
TZOFFSETTO:-0800
|
39
|
+
END:STANDARD
|
40
|
+
BEGIN:DAYLIGHT
|
41
|
+
DTSTART:19420209T020000
|
42
|
+
RDATE:19420209T020000
|
43
|
+
TZNAME:PWT
|
44
|
+
TZOFFSETFROM:-0800
|
45
|
+
TZOFFSETTO:-0700
|
46
|
+
END:DAYLIGHT
|
47
|
+
BEGIN:DAYLIGHT
|
48
|
+
DTSTART:19450814T160000
|
49
|
+
RDATE:19450814T160000
|
50
|
+
TZNAME:PPT
|
51
|
+
TZOFFSETFROM:-0700
|
52
|
+
TZOFFSETTO:-0700
|
53
|
+
END:DAYLIGHT
|
54
|
+
BEGIN:STANDARD
|
55
|
+
DTSTART:19450930T020000
|
56
|
+
RDATE:19450930T020000
|
57
|
+
RDATE:19490101T020000
|
58
|
+
TZNAME:PST
|
59
|
+
TZOFFSETFROM:-0700
|
60
|
+
TZOFFSETTO:-0800
|
61
|
+
END:STANDARD
|
62
|
+
BEGIN:STANDARD
|
63
|
+
DTSTART:19460101T000000
|
64
|
+
RDATE:19460101T000000
|
65
|
+
RDATE:19670101T000000
|
66
|
+
TZNAME:PST
|
67
|
+
TZOFFSETFROM:-0800
|
68
|
+
TZOFFSETTO:-0800
|
69
|
+
END:STANDARD
|
70
|
+
BEGIN:DAYLIGHT
|
71
|
+
DTSTART:19480314T020100
|
72
|
+
RDATE:19480314T020100
|
73
|
+
RDATE:19740106T020000
|
74
|
+
RDATE:19750223T020000
|
75
|
+
TZNAME:PDT
|
76
|
+
TZOFFSETFROM:-0800
|
77
|
+
TZOFFSETTO:-0700
|
78
|
+
END:DAYLIGHT
|
79
|
+
BEGIN:DAYLIGHT
|
80
|
+
DTSTART:19500430T010000
|
81
|
+
RRULE:FREQ=YEARLY;UNTIL=19660424T090000Z;BYMONTH=4;BYDAY=-1SU
|
82
|
+
TZNAME:PDT
|
83
|
+
TZOFFSETFROM:-0800
|
84
|
+
TZOFFSETTO:-0700
|
85
|
+
END:DAYLIGHT
|
86
|
+
BEGIN:STANDARD
|
87
|
+
DTSTART:19500924T020000
|
88
|
+
RRULE:FREQ=YEARLY;UNTIL=19610924T090000Z;BYMONTH=9;BYDAY=-1SU
|
89
|
+
TZNAME:PST
|
90
|
+
TZOFFSETFROM:-0700
|
91
|
+
TZOFFSETTO:-0800
|
92
|
+
END:STANDARD
|
93
|
+
BEGIN:STANDARD
|
94
|
+
DTSTART:19621028T020000
|
95
|
+
RRULE:FREQ=YEARLY;UNTIL=19661030T090000Z;BYMONTH=10;BYDAY=-1SU
|
96
|
+
TZNAME:PST
|
97
|
+
TZOFFSETFROM:-0700
|
98
|
+
TZOFFSETTO:-0800
|
99
|
+
END:STANDARD
|
100
|
+
BEGIN:DAYLIGHT
|
101
|
+
DTSTART:19670430T020000
|
102
|
+
RRULE:FREQ=YEARLY;UNTIL=19730429T100000Z;BYMONTH=4;BYDAY=-1SU
|
103
|
+
TZNAME:PDT
|
104
|
+
TZOFFSETFROM:-0800
|
105
|
+
TZOFFSETTO:-0700
|
106
|
+
END:DAYLIGHT
|
107
|
+
BEGIN:STANDARD
|
108
|
+
DTSTART:19671029T020000
|
109
|
+
RRULE:FREQ=YEARLY;UNTIL=20061029T090000Z;BYMONTH=10;BYDAY=-1SU
|
110
|
+
TZNAME:PST
|
111
|
+
TZOFFSETFROM:-0700
|
112
|
+
TZOFFSETTO:-0800
|
113
|
+
END:STANDARD
|
114
|
+
BEGIN:DAYLIGHT
|
115
|
+
DTSTART:19760425T020000
|
116
|
+
RRULE:FREQ=YEARLY;UNTIL=19860427T100000Z;BYMONTH=4;BYDAY=-1SU
|
117
|
+
TZNAME:PDT
|
118
|
+
TZOFFSETFROM:-0800
|
119
|
+
TZOFFSETTO:-0700
|
120
|
+
END:DAYLIGHT
|
121
|
+
BEGIN:DAYLIGHT
|
122
|
+
DTSTART:19870405T020000
|
123
|
+
RRULE:FREQ=YEARLY;UNTIL=20060402T100000Z;BYMONTH=4;BYDAY=1SU
|
124
|
+
TZNAME:PDT
|
125
|
+
TZOFFSETFROM:-0800
|
126
|
+
TZOFFSETTO:-0700
|
127
|
+
END:DAYLIGHT
|
128
|
+
BEGIN:DAYLIGHT
|
129
|
+
DTSTART:20070311T020000
|
130
|
+
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
|
131
|
+
TZNAME:PDT
|
132
|
+
TZOFFSETFROM:-0800
|
133
|
+
TZOFFSETTO:-0700
|
134
|
+
END:DAYLIGHT
|
135
|
+
BEGIN:STANDARD
|
136
|
+
DTSTART:20071104T020000
|
137
|
+
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
|
138
|
+
TZNAME:PST
|
139
|
+
TZOFFSETFROM:-0700
|
140
|
+
TZOFFSETTO:-0800
|
141
|
+
END:STANDARD
|
142
|
+
END:VTIMEZONE
|
143
|
+
END:VCALENDAR
|
data/spec/parser_spec.rb
CHANGED
@@ -5,6 +5,15 @@ describe Icalendar::Parser do
|
|
5
5
|
let(:source) { File.read File.join(File.dirname(__FILE__), 'fixtures', fn) }
|
6
6
|
|
7
7
|
describe '#parse' do
|
8
|
+
context 'reversed_timezone.ics' do
|
9
|
+
let(:fn) { 'reversed_timezone.ics' }
|
10
|
+
|
11
|
+
it 'correctly parses the event timezone' do
|
12
|
+
event = subject.parse.first.events.first
|
13
|
+
expect(event.dtstart.utc_offset).to eq -25200
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
8
17
|
context 'single_event.ics' do
|
9
18
|
let(:fn) { 'single_event.ics' }
|
10
19
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: icalendar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.10.
|
4
|
+
version: 2.10.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Ahearn
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ice_cube
|
@@ -58,42 +58,28 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '7.1'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: i18n
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - "~>"
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '1.8'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - "~>"
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '1.8'
|
68
|
+
version: '7.1'
|
83
69
|
- !ruby/object:Gem::Dependency
|
84
70
|
name: tzinfo
|
85
71
|
requirement: !ruby/object:Gem::Requirement
|
86
72
|
requirements:
|
87
73
|
- - "~>"
|
88
74
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
75
|
+
version: '2.0'
|
90
76
|
type: :development
|
91
77
|
prerelease: false
|
92
78
|
version_requirements: !ruby/object:Gem::Requirement
|
93
79
|
requirements:
|
94
80
|
- - "~>"
|
95
81
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
82
|
+
version: '2.0'
|
97
83
|
- !ruby/object:Gem::Dependency
|
98
84
|
name: tzinfo-data
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,6 +136,20 @@ dependencies:
|
|
150
136
|
- - "~>"
|
151
137
|
- !ruby/object:Gem::Version
|
152
138
|
version: '0.16'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: byebug
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
153
|
description: |
|
154
154
|
Implements the iCalendar specification (RFC-5545) in Ruby. This allows
|
155
155
|
for the generation and parsing of .ics files, which are used by a
|
@@ -216,6 +216,7 @@ files:
|
|
216
216
|
- spec/fixtures/nondefault_values.ics
|
217
217
|
- spec/fixtures/nonstandard.ics
|
218
218
|
- spec/fixtures/recurrence.ics
|
219
|
+
- spec/fixtures/reversed_timezone.ics
|
219
220
|
- spec/fixtures/single_event.ics
|
220
221
|
- spec/fixtures/single_event_bad_dtstart.ics
|
221
222
|
- spec/fixtures/single_event_bad_line.ics
|
@@ -267,7 +268,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
267
268
|
- !ruby/object:Gem::Version
|
268
269
|
version: '0'
|
269
270
|
requirements: []
|
270
|
-
rubygems_version: 3.
|
271
|
+
rubygems_version: 3.3.26
|
271
272
|
signing_key:
|
272
273
|
specification_version: 4
|
273
274
|
summary: A ruby implementation of the iCalendar specification (RFC-5545).
|
@@ -282,6 +283,7 @@ test_files:
|
|
282
283
|
- spec/fixtures/nondefault_values.ics
|
283
284
|
- spec/fixtures/nonstandard.ics
|
284
285
|
- spec/fixtures/recurrence.ics
|
286
|
+
- spec/fixtures/reversed_timezone.ics
|
285
287
|
- spec/fixtures/single_event.ics
|
286
288
|
- spec/fixtures/single_event_bad_dtstart.ics
|
287
289
|
- spec/fixtures/single_event_bad_line.ics
|