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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a4c654b36ffe5a09f521ad3c012686f12e582ba5d380242c646334f47153360
4
- data.tar.gz: 184399a11e6e8a39b18ceeef59de8a9b9f7cd581f0c7169cce5c7dca63575e3b
3
+ metadata.gz: 7b9f7e30ef6614ad4175a9d282d1b03b57f140f98a2962b4e0268aa015f8f942
4
+ data.tar.gz: 7ebabfddd0f3d8e8e05e1ef82d2389007c1419c727c5404d2ec2c1c09565a8bb
5
5
  SHA512:
6
- metadata.gz: 61837b5d19193d80d72f37edff89290fc2e5ffa0c6b9ee500036de58b0fbd9aacb5e0e9bc9f1a0a4e1ce7a3ad494ed0147e87bf697b54523d8b799e9eaa275fa
7
- data.tar.gz: 00d54cc0ab4b7fc6acf616a537b426d110ddbe65dda1d6ab8ec938ba2df64e87def99023916c6193ab25d1885a2a60e8a1706617ed5a6e0adb5cb34671dae1ec
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
- # s.add_development_dependency 'tzinfo', '~> 2.0'
42
- # s.add_development_dependency 'tzinfo-data', '~> 1.2020'
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
@@ -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-info'] = timezone_store.retrieve param_value
214
+ params['x-tz-store'] = timezone_store
215
215
  end
216
216
  end
217
217
  end
@@ -108,15 +108,17 @@ module Icalendar
108
108
 
109
109
  def standard_for(local)
110
110
  possible = standards.map do |std|
111
- [std.previous_occurrence(local.to_time), std]
112
- end
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
- [day.previous_occurrence(local.to_time), day]
119
- end
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
@@ -10,7 +10,7 @@ module Icalendar
10
10
 
11
11
  def initialize(value, params = {})
12
12
  params.delete 'tzid'
13
- params.delete 'x-tz-info'
13
+ params.delete 'x-tz-store'
14
14
  if value.is_a? String
15
15
  begin
16
16
  parsed_date = ::Date.strptime(value, FORMAT)
@@ -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
- x_tz_info = params.delete 'x-tz-info'
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
- offset_value = unless params['tzid'].nil?
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 params_ical
55
- ical_params.delete 'tzid' if tz_utc
56
- super
80
+ def set_offset?
81
+ !!@offset_value
57
82
  end
58
83
  end
59
84
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Icalendar
4
4
 
5
- VERSION = '2.10.0'
5
+ VERSION = '2.10.1'
6
6
 
7
7
  end
@@ -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.0
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-01 00:00:00.000000000 Z
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: '6.0'
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: '6.0'
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: '1.2'
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: '1.2'
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.4.10
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