tzinfo 1.2.5 → 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.yardopts +3 -0
  4. data/CHANGES.md +607 -377
  5. data/LICENSE +13 -13
  6. data/README.md +368 -113
  7. data/lib/tzinfo/annual_rules.rb +71 -0
  8. data/lib/tzinfo/country.rb +141 -129
  9. data/lib/tzinfo/country_timezone.rb +70 -112
  10. data/lib/tzinfo/data_source.rb +400 -144
  11. data/lib/tzinfo/data_sources/constant_offset_data_timezone_info.rb +56 -0
  12. data/lib/tzinfo/data_sources/country_info.rb +42 -0
  13. data/lib/tzinfo/data_sources/data_timezone_info.rb +91 -0
  14. data/lib/tzinfo/data_sources/linked_timezone_info.rb +33 -0
  15. data/lib/tzinfo/data_sources/posix_time_zone_parser.rb +181 -0
  16. data/lib/tzinfo/data_sources/ruby_data_source.rb +145 -0
  17. data/lib/tzinfo/data_sources/timezone_info.rb +47 -0
  18. data/lib/tzinfo/data_sources/transitions_data_timezone_info.rb +214 -0
  19. data/lib/tzinfo/data_sources/zoneinfo_data_source.rb +596 -0
  20. data/lib/tzinfo/data_sources/zoneinfo_reader.rb +486 -0
  21. data/lib/tzinfo/data_sources.rb +8 -0
  22. data/lib/tzinfo/data_timezone.rb +33 -47
  23. data/lib/tzinfo/datetime_with_offset.rb +153 -0
  24. data/lib/tzinfo/format1/country_definer.rb +17 -0
  25. data/lib/tzinfo/format1/country_index_definition.rb +64 -0
  26. data/lib/tzinfo/format1/timezone_definer.rb +64 -0
  27. data/lib/tzinfo/format1/timezone_definition.rb +39 -0
  28. data/lib/tzinfo/format1/timezone_index_definition.rb +77 -0
  29. data/lib/tzinfo/format1.rb +10 -0
  30. data/lib/tzinfo/format2/country_definer.rb +68 -0
  31. data/lib/tzinfo/format2/country_index_definer.rb +68 -0
  32. data/lib/tzinfo/format2/country_index_definition.rb +46 -0
  33. data/lib/tzinfo/format2/timezone_definer.rb +94 -0
  34. data/lib/tzinfo/format2/timezone_definition.rb +73 -0
  35. data/lib/tzinfo/format2/timezone_index_definer.rb +45 -0
  36. data/lib/tzinfo/format2/timezone_index_definition.rb +55 -0
  37. data/lib/tzinfo/format2.rb +10 -0
  38. data/lib/tzinfo/info_timezone.rb +26 -21
  39. data/lib/tzinfo/linked_timezone.rb +33 -52
  40. data/lib/tzinfo/offset_timezone_period.rb +42 -0
  41. data/lib/tzinfo/string_deduper.rb +118 -0
  42. data/lib/tzinfo/time_with_offset.rb +154 -0
  43. data/lib/tzinfo/timestamp.rb +552 -0
  44. data/lib/tzinfo/timestamp_with_offset.rb +85 -0
  45. data/lib/tzinfo/timezone.rb +989 -498
  46. data/lib/tzinfo/timezone_offset.rb +84 -74
  47. data/lib/tzinfo/timezone_period.rb +151 -217
  48. data/lib/tzinfo/timezone_proxy.rb +70 -79
  49. data/lib/tzinfo/timezone_transition.rb +77 -109
  50. data/lib/tzinfo/transition_rule.rb +455 -0
  51. data/lib/tzinfo/transitions_timezone_period.rb +63 -0
  52. data/lib/tzinfo/untaint_ext.rb +18 -0
  53. data/lib/tzinfo/version.rb +7 -0
  54. data/lib/tzinfo/with_offset.rb +61 -0
  55. data/lib/tzinfo.rb +74 -29
  56. data.tar.gz.sig +0 -0
  57. metadata +72 -122
  58. metadata.gz.sig +0 -0
  59. data/Rakefile +0 -107
  60. data/lib/tzinfo/country_index_definition.rb +0 -31
  61. data/lib/tzinfo/country_info.rb +0 -42
  62. data/lib/tzinfo/data_timezone_info.rb +0 -55
  63. data/lib/tzinfo/linked_timezone_info.rb +0 -26
  64. data/lib/tzinfo/offset_rationals.rb +0 -77
  65. data/lib/tzinfo/ruby_core_support.rb +0 -146
  66. data/lib/tzinfo/ruby_country_info.rb +0 -74
  67. data/lib/tzinfo/ruby_data_source.rb +0 -136
  68. data/lib/tzinfo/time_or_datetime.rb +0 -340
  69. data/lib/tzinfo/timezone_definition.rb +0 -36
  70. data/lib/tzinfo/timezone_index_definition.rb +0 -54
  71. data/lib/tzinfo/timezone_info.rb +0 -30
  72. data/lib/tzinfo/timezone_transition_definition.rb +0 -104
  73. data/lib/tzinfo/transition_data_timezone_info.rb +0 -274
  74. data/lib/tzinfo/zoneinfo_country_info.rb +0 -37
  75. data/lib/tzinfo/zoneinfo_data_source.rb +0 -488
  76. data/lib/tzinfo/zoneinfo_timezone_info.rb +0 -296
  77. data/test/tc_country.rb +0 -234
  78. data/test/tc_country_index_definition.rb +0 -69
  79. data/test/tc_country_info.rb +0 -16
  80. data/test/tc_country_timezone.rb +0 -173
  81. data/test/tc_data_source.rb +0 -218
  82. data/test/tc_data_timezone.rb +0 -99
  83. data/test/tc_data_timezone_info.rb +0 -18
  84. data/test/tc_info_timezone.rb +0 -34
  85. data/test/tc_linked_timezone.rb +0 -155
  86. data/test/tc_linked_timezone_info.rb +0 -23
  87. data/test/tc_offset_rationals.rb +0 -23
  88. data/test/tc_ruby_core_support.rb +0 -168
  89. data/test/tc_ruby_country_info.rb +0 -110
  90. data/test/tc_ruby_data_source.rb +0 -143
  91. data/test/tc_time_or_datetime.rb +0 -654
  92. data/test/tc_timezone.rb +0 -1350
  93. data/test/tc_timezone_definition.rb +0 -113
  94. data/test/tc_timezone_index_definition.rb +0 -73
  95. data/test/tc_timezone_info.rb +0 -11
  96. data/test/tc_timezone_london.rb +0 -143
  97. data/test/tc_timezone_melbourne.rb +0 -142
  98. data/test/tc_timezone_new_york.rb +0 -142
  99. data/test/tc_timezone_offset.rb +0 -126
  100. data/test/tc_timezone_period.rb +0 -555
  101. data/test/tc_timezone_proxy.rb +0 -136
  102. data/test/tc_timezone_transition.rb +0 -366
  103. data/test/tc_timezone_transition_definition.rb +0 -295
  104. data/test/tc_timezone_utc.rb +0 -27
  105. data/test/tc_transition_data_timezone_info.rb +0 -423
  106. data/test/tc_zoneinfo_country_info.rb +0 -78
  107. data/test/tc_zoneinfo_data_source.rb +0 -1195
  108. data/test/tc_zoneinfo_timezone_info.rb +0 -1232
  109. data/test/test_utils.rb +0 -163
  110. data/test/ts_all.rb +0 -7
  111. data/test/ts_all_ruby.rb +0 -5
  112. data/test/ts_all_zoneinfo.rb +0 -7
  113. data/test/tzinfo-data/tzinfo/data/definitions/America/Argentina/Buenos_Aires.rb +0 -89
  114. data/test/tzinfo-data/tzinfo/data/definitions/America/New_York.rb +0 -315
  115. data/test/tzinfo-data/tzinfo/data/definitions/Australia/Melbourne.rb +0 -218
  116. data/test/tzinfo-data/tzinfo/data/definitions/EST.rb +0 -19
  117. data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__m__1.rb +0 -21
  118. data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__p__1.rb +0 -21
  119. data/test/tzinfo-data/tzinfo/data/definitions/Etc/UTC.rb +0 -21
  120. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Amsterdam.rb +0 -261
  121. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Andorra.rb +0 -186
  122. data/test/tzinfo-data/tzinfo/data/definitions/Europe/London.rb +0 -321
  123. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Paris.rb +0 -265
  124. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Prague.rb +0 -220
  125. data/test/tzinfo-data/tzinfo/data/definitions/UTC.rb +0 -16
  126. data/test/tzinfo-data/tzinfo/data/indexes/countries.rb +0 -927
  127. data/test/tzinfo-data/tzinfo/data/indexes/timezones.rb +0 -596
  128. data/test/tzinfo-data/tzinfo/data/version.rb +0 -14
  129. data/test/tzinfo-data/tzinfo/data.rb +0 -8
  130. data/test/zoneinfo/America/Argentina/Buenos_Aires +0 -0
  131. data/test/zoneinfo/America/New_York +0 -0
  132. data/test/zoneinfo/Australia/Melbourne +0 -0
  133. data/test/zoneinfo/EST +0 -0
  134. data/test/zoneinfo/Etc/UTC +0 -0
  135. data/test/zoneinfo/Europe/Amsterdam +0 -0
  136. data/test/zoneinfo/Europe/Andorra +0 -0
  137. data/test/zoneinfo/Europe/London +0 -0
  138. data/test/zoneinfo/Europe/Paris +0 -0
  139. data/test/zoneinfo/Europe/Prague +0 -0
  140. data/test/zoneinfo/Factory +0 -0
  141. data/test/zoneinfo/iso3166.tab +0 -275
  142. data/test/zoneinfo/leapseconds +0 -61
  143. data/test/zoneinfo/posix/Europe/London +0 -0
  144. data/test/zoneinfo/posixrules +0 -0
  145. data/test/zoneinfo/right/Europe/London +0 -0
  146. data/test/zoneinfo/zone.tab +0 -439
  147. data/test/zoneinfo/zone1970.tab +0 -369
  148. data/tzinfo.gemspec +0 -21
@@ -0,0 +1,214 @@
1
+ # encoding: UTF-8
2
+ # frozen_string_literal: true
3
+
4
+ module TZInfo
5
+ module DataSources
6
+ # Represents a data time zone defined by a list of transitions that change
7
+ # the locally observed time.
8
+ class TransitionsDataTimezoneInfo < DataTimezoneInfo
9
+ # @return [Array<TimezoneTransition>] the transitions that define this
10
+ # time zone in order of ascending timestamp.
11
+ attr_reader :transitions
12
+
13
+ # Initializes a new {TransitionsDataTimezoneInfo}.
14
+ #
15
+ # The passed in `identifier` instance will be frozen. A reference to the
16
+ # passed in `Array` will be retained.
17
+ #
18
+ # The `transitions` `Array` must be sorted in order of ascending
19
+ # timestamp. Each transition must have a
20
+ # {TimezoneTransition#timestamp_value timestamp_value} that is greater
21
+ # than the {TimezoneTransition#timestamp_value timestamp_value} of the
22
+ # prior transition.
23
+ #
24
+ # @param identifier [String] the identifier of the time zone.
25
+ # @param transitions [Array<TimezoneTransitions>] an `Array` of
26
+ # transitions that each indicate when a change occurs in the locally
27
+ # observed time.
28
+ # @raise [ArgumentError] if `identifier` is `nil`.
29
+ # @raise [ArgumentError] if `transitions` is `nil`.
30
+ # @raise [ArgumentError] if `transitions` is an empty `Array`.
31
+ def initialize(identifier, transitions)
32
+ super(identifier)
33
+ raise ArgumentError, 'transitions must be specified' unless transitions
34
+ raise ArgumentError, 'transitions must not be an empty Array' if transitions.empty?
35
+ @transitions = transitions.freeze
36
+ end
37
+
38
+ # (see DataTimezoneInfo#period_for)
39
+ def period_for(timestamp)
40
+ raise ArgumentError, 'timestamp must be specified' unless timestamp
41
+ raise ArgumentError, 'timestamp must have a specified utc_offset' unless timestamp.utc_offset
42
+
43
+ timestamp_value = timestamp.value
44
+
45
+ index = find_minimum_transition {|t| t.timestamp_value >= timestamp_value }
46
+
47
+ if index
48
+ transition = @transitions[index]
49
+
50
+ if transition.timestamp_value == timestamp_value
51
+ # timestamp occurs within the second of the found transition, so is
52
+ # the transition that starts the period.
53
+ start_transition = transition
54
+ end_transition = @transitions[index + 1]
55
+ else
56
+ # timestamp occurs before the second of the found transition, so is
57
+ # the transition that ends the period.
58
+ start_transition = index == 0 ? nil : @transitions[index - 1]
59
+ end_transition = transition
60
+ end
61
+ else
62
+ start_transition = @transitions.last
63
+ end_transition = nil
64
+ end
65
+
66
+ TransitionsTimezonePeriod.new(start_transition, end_transition)
67
+ end
68
+
69
+ # (see DataTimezoneInfo#periods_for_local)
70
+ def periods_for_local(local_timestamp)
71
+ raise ArgumentError, 'local_timestamp must be specified' unless local_timestamp
72
+ raise ArgumentError, 'local_timestamp must have an unspecified utc_offset' if local_timestamp.utc_offset
73
+
74
+ local_timestamp_value = local_timestamp.value
75
+ latest_possible_utc_value = local_timestamp_value + 86400
76
+ earliest_possible_utc_value = local_timestamp_value - 86400
77
+
78
+ # Find the index of the first transition that occurs after a latest
79
+ # possible UTC representation of the local timestamp and then search
80
+ # backwards until an earliest possible UTC representation.
81
+
82
+ index = find_minimum_transition {|t| t.timestamp_value >= latest_possible_utc_value }
83
+
84
+ # No transitions after latest_possible_utc_value, set to max index + 1
85
+ # to search backwards including the period after the last transition
86
+ index = @transitions.length unless index
87
+
88
+ result = []
89
+
90
+ index.downto(0) do |i|
91
+ start_transition = i > 0 ? @transitions[i - 1] : nil
92
+ end_transition = @transitions[i]
93
+ offset = start_transition ? start_transition.offset : end_transition.previous_offset
94
+ utc_timestamp_value = local_timestamp_value - offset.observed_utc_offset
95
+
96
+ # It is not necessary to compare the sub-seconds because a timestamp
97
+ # is in the period if is >= the start transition (sub-seconds would
98
+ # make == become >) and if it is < the end transition (which
99
+ # sub-seconds cannot affect).
100
+ if (!start_transition || utc_timestamp_value >= start_transition.timestamp_value) && (!end_transition || utc_timestamp_value < end_transition.timestamp_value)
101
+ result << TransitionsTimezonePeriod.new(start_transition, end_transition)
102
+ elsif end_transition && end_transition.timestamp_value < earliest_possible_utc_value
103
+ break
104
+ end
105
+ end
106
+
107
+ result.reverse!
108
+ end
109
+
110
+ # (see DataTimezoneInfo#transitions_up_to)
111
+ def transitions_up_to(to_timestamp, from_timestamp = nil)
112
+ raise ArgumentError, 'to_timestamp must be specified' unless to_timestamp
113
+ raise ArgumentError, 'to_timestamp must have a specified utc_offset' unless to_timestamp.utc_offset
114
+
115
+ if from_timestamp
116
+ raise ArgumentError, 'from_timestamp must have a specified utc_offset' unless from_timestamp.utc_offset
117
+ raise ArgumentError, 'to_timestamp must be greater than from_timestamp' if to_timestamp <= from_timestamp
118
+ end
119
+
120
+ if from_timestamp
121
+ from_index = find_minimum_transition {|t| transition_on_or_after_timestamp?(t, from_timestamp) }
122
+ return [] unless from_index
123
+ else
124
+ from_index = 0
125
+ end
126
+
127
+ to_index = find_minimum_transition {|t| transition_on_or_after_timestamp?(t, to_timestamp) }
128
+
129
+ if to_index
130
+ return [] if to_index < 1
131
+ to_index -= 1
132
+ else
133
+ to_index = -1
134
+ end
135
+
136
+ @transitions[from_index..to_index]
137
+ end
138
+
139
+ private
140
+
141
+ # Array#bsearch_index was added in Ruby 2.3.0. Use bsearch_index to find
142
+ # transitions if it is available, otherwise use a Ruby implementation.
143
+ if [].respond_to?(:bsearch_index)
144
+ # Performs a binary search on {transitions} to find the index of the
145
+ # earliest transition satisfying a condition.
146
+ #
147
+ # @yield [transition] the caller will be yielded to to test the search
148
+ # condition.
149
+ # @yieldparam transition [TimezoneTransition] a {TimezoneTransition}
150
+ # instance from {transitions}.
151
+ # @yieldreturn [Boolean] `true` for the earliest transition that
152
+ # satisfies the condition and return `true` for all subsequent
153
+ # transitions. In all other cases, the result of the block must be
154
+ # `false`.
155
+ # @return [Integer] the index of the earliest transition safisfying
156
+ # the condition or `nil` if there are no such transitions.
157
+ #
158
+ # :nocov_no_array_bsearch_index:
159
+ def find_minimum_transition(&block)
160
+ @transitions.bsearch_index(&block)
161
+ end
162
+ # :nocov_no_array_bsearch_index:
163
+ else
164
+ # Performs a binary search on {transitions} to find the index of the
165
+ # earliest transition satisfying a condition.
166
+ #
167
+ # @yield [transition] the caller will be yielded to to test the search
168
+ # condition.
169
+ # @yieldparam transition [TimezoneTransition] a {TimezoneTransition}
170
+ # instance from {transitions}.
171
+ # @yieldreturn [Boolean] `true` for the earliest transition that
172
+ # satisfies the condition and return `true` for all subsequent
173
+ # transitions. In all other cases, the result of the block must be
174
+ # `false`.
175
+ # @return [Integer] the index of the earliest transition safisfying
176
+ # the condition or `nil` if there are no such transitions.
177
+ #
178
+ # :nocov_array_bsearch_index:
179
+ def find_minimum_transition
180
+ # A Ruby implementation of the find-minimum mode of Array#bsearch_index.
181
+ low = 0
182
+ high = @transitions.length
183
+ satisfied = false
184
+
185
+ while low < high do
186
+ mid = (low + high).div(2)
187
+ if yield @transitions[mid]
188
+ satisfied = true
189
+ high = mid
190
+ else
191
+ low = mid + 1
192
+ end
193
+ end
194
+
195
+ satisfied ? low : nil
196
+ end
197
+ # :nocov_array_bsearch_index:
198
+ end
199
+
200
+ # Determines if a transition occurs at or after a given {Timestamp},
201
+ # taking the {Timestamp#sub_second sub_second} into consideration.
202
+ #
203
+ # @param transition [TimezoneTransition] the transition to compare.
204
+ # @param timestamp [Timestamp] the timestamp to compare.
205
+ # @return [Boolean] `true` if `transition` occurs at or after `timestamp`,
206
+ # otherwise `false`.
207
+ def transition_on_or_after_timestamp?(transition, timestamp)
208
+ transition_timestamp_value = transition.timestamp_value
209
+ timestamp_value = timestamp.value
210
+ transition_timestamp_value > timestamp_value || transition_timestamp_value == timestamp_value && timestamp.sub_second == 0
211
+ end
212
+ end
213
+ end
214
+ end