tzinfo 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of tzinfo might be problematic. Click here for more details.

Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.yardopts +6 -0
  5. data/{CHANGES → CHANGES.md} +121 -50
  6. data/{README → README.md} +48 -34
  7. data/Rakefile +45 -22
  8. data/lib/tzinfo.rb +7 -2
  9. data/lib/tzinfo/country.rb +23 -1
  10. data/lib/tzinfo/country_index_definition.rb +6 -1
  11. data/lib/tzinfo/country_timezone.rb +9 -1
  12. data/lib/tzinfo/data_source.rb +26 -5
  13. data/lib/tzinfo/data_timezone.rb +30 -2
  14. data/lib/tzinfo/data_timezone_info.rb +26 -0
  15. data/lib/tzinfo/info_timezone.rb +3 -1
  16. data/lib/tzinfo/linked_timezone.rb +30 -1
  17. data/lib/tzinfo/offset_rationals.rb +5 -3
  18. data/lib/tzinfo/ruby_core_support.rb +2 -0
  19. data/lib/tzinfo/ruby_country_info.rb +14 -0
  20. data/lib/tzinfo/ruby_data_source.rb +5 -0
  21. data/lib/tzinfo/time_or_datetime.rb +16 -1
  22. data/lib/tzinfo/timezone.rb +107 -5
  23. data/lib/tzinfo/timezone_definition.rb +5 -1
  24. data/lib/tzinfo/timezone_index_definition.rb +7 -1
  25. data/lib/tzinfo/{timezone_offset_info.rb → timezone_offset.rb} +12 -10
  26. data/lib/tzinfo/timezone_period.rb +19 -15
  27. data/lib/tzinfo/timezone_proxy.rb +5 -1
  28. data/lib/tzinfo/timezone_transition.rb +136 -0
  29. data/lib/tzinfo/{timezone_transition_info.rb → timezone_transition_definition.rb} +21 -57
  30. data/lib/tzinfo/transition_data_timezone_info.rb +81 -8
  31. data/lib/tzinfo/zoneinfo_country_info.rb +7 -0
  32. data/lib/tzinfo/zoneinfo_data_source.rb +104 -57
  33. data/lib/tzinfo/zoneinfo_timezone_info.rb +18 -10
  34. data/test/tc_country.rb +39 -1
  35. data/test/tc_data_timezone.rb +28 -5
  36. data/test/tc_linked_timezone.rb +24 -3
  37. data/test/tc_ruby_data_source.rb +22 -2
  38. data/test/tc_time_or_datetime.rb +3 -3
  39. data/test/tc_timezone.rb +364 -117
  40. data/test/tc_timezone_london.rb +25 -0
  41. data/test/tc_timezone_melbourne.rb +24 -0
  42. data/test/tc_timezone_new_york.rb +24 -0
  43. data/test/{tc_timezone_offset_info.rb → tc_timezone_offset.rb} +27 -27
  44. data/test/tc_timezone_period.rb +113 -90
  45. data/test/tc_timezone_transition.rb +374 -0
  46. data/test/tc_timezone_transition_definition.rb +306 -0
  47. data/test/tc_transition_data_timezone_info.rb +143 -43
  48. data/test/tc_zoneinfo_data_source.rb +69 -5
  49. data/test/tc_zoneinfo_timezone_info.rb +63 -20
  50. data/test/test_utils.rb +27 -7
  51. data/tzinfo.gemspec +21 -0
  52. metadata +61 -38
  53. metadata.gz.sig +3 -0
  54. data/test/tc_timezone_transition_info.rb +0 -471
  55. data/test/zoneinfo/UTC +0 -0
  56. data/test/zoneinfo/localtime +0 -0
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2006-2012 Philip Ross
2
+ # Copyright (c) 2006-2013 Philip Ross
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@
22
22
 
23
23
  module TZInfo
24
24
  # Represents an offset defined in a Timezone data file.
25
- class TimezoneOffsetInfo #:nodoc:
25
+ class TimezoneOffset
26
26
  # The base offset of the timezone from UTC in seconds.
27
27
  attr_reader :utc_offset
28
28
 
@@ -39,8 +39,8 @@ module TZInfo
39
39
  # symbol.
40
40
  attr_reader :abbreviation
41
41
 
42
- # Constructs a new TimezoneOffsetInfo. utc_offset and std_offset are
43
- # specified in seconds.
42
+ # Constructs a new TimezoneOffset. utc_offset and std_offset are specified
43
+ # in seconds.
44
44
  def initialize(utc_offset, std_offset, abbreviation)
45
45
  @utc_offset = utc_offset
46
46
  @std_offset = std_offset
@@ -54,14 +54,16 @@ module TZInfo
54
54
  @std_offset != 0
55
55
  end
56
56
 
57
- # Converts a UTC DateTime to local time based on the offset of this period.
57
+ # Converts a UTC Time, DateTime or integer timestamp to local time, based on
58
+ # the offset of this period.
58
59
  def to_local(utc)
59
60
  TimeOrDateTime.wrap(utc) {|wrapped|
60
61
  wrapped + @utc_total_offset
61
62
  }
62
63
  end
63
64
 
64
- # Converts a local DateTime to UTC based on the offset of this period.
65
+ # Converts a local Time, DateTime or integer timestamp to UTC, based on the
66
+ # offset of this period.
65
67
  def to_utc(local)
66
68
  TimeOrDateTime.wrap(local) {|wrapped|
67
69
  wrapped - @utc_total_offset
@@ -69,19 +71,19 @@ module TZInfo
69
71
  end
70
72
 
71
73
  # Returns true if and only if toi has the same utc_offset, std_offset
72
- # and abbreviation as this TimezoneOffsetInfo.
74
+ # and abbreviation as this TimezoneOffset.
73
75
  def ==(toi)
74
- toi.kind_of?(TimezoneOffsetInfo) &&
76
+ toi.kind_of?(TimezoneOffset) &&
75
77
  utc_offset == toi.utc_offset && std_offset == toi.std_offset && abbreviation == toi.abbreviation
76
78
  end
77
79
 
78
80
  # Returns true if and only if toi has the same utc_offset, std_offset
79
- # and abbreviation as this TimezoneOffsetInfo.
81
+ # and abbreviation as this TimezoneOffset.
80
82
  def eql?(toi)
81
83
  self == toi
82
84
  end
83
85
 
84
- # Returns a hash of this TimezoneOffsetInfo.
86
+ # Returns a hash of this TimezoneOffset.
85
87
  def hash
86
88
  utc_offset.hash ^ std_offset.hash ^ abbreviation.hash
87
89
  end
@@ -26,21 +26,20 @@ module TZInfo
26
26
  # All the methods that take times accept instances of Time or DateTime as well
27
27
  # as Integer timestamps.
28
28
  class TimezonePeriod
29
- # The TimezoneTransitionInfo that defines the start of this TimezonePeriod
29
+ # The TimezoneTransition that defines the start of this TimezonePeriod
30
30
  # (may be nil if unbounded).
31
- attr_reader :start_transition #:nodoc:
32
- protected :start_transition
31
+ attr_reader :start_transition
33
32
 
34
- # The TimezoneTransitionInfo that defines the end of this TimezonePeriod
33
+ # The TimezoneTransition that defines the end of this TimezonePeriod
35
34
  # (may be nil if unbounded).
36
- attr_reader :end_transition #:nodoc:
37
- protected :end_transition
35
+ attr_reader :end_transition
38
36
 
39
- # The TimezoneOffsetInfo for this period.
40
- attr_reader :offset #:nodoc:
41
- protected :offset
37
+ # The TimezoneOffset for this period.
38
+ attr_reader :offset
42
39
 
43
40
  # Initializes a new TimezonePeriod.
41
+ #
42
+ # TimezonePeriod instances should not normally be constructed manually.
44
43
  def initialize(start_transition, end_transition, offset = nil)
45
44
  @start_transition = start_transition
46
45
  @end_transition = end_transition
@@ -88,6 +87,11 @@ module TZInfo
88
87
 
89
88
  # Total offset from UTC (days). Result is a Rational.
90
89
  def utc_total_offset_rational
90
+ # Thread-safey: It is possible that the value of
91
+ # @utc_total_offset_rational may be calculated multiple times in
92
+ # concurrently executing threads. It is not worth the overhead of locking
93
+ # to ensure that @zone_identifiers is only calculated once.
94
+
91
95
  unless @utc_total_offset_rational
92
96
  @utc_total_offset_rational = OffsetRationals.rational_for_offset(utc_total_offset)
93
97
  end
@@ -117,25 +121,25 @@ module TZInfo
117
121
  # The start time of the period in local time as a DateTime. May be nil if
118
122
  # unbounded.
119
123
  def local_start
120
- @start_transition ? @start_transition.local_start.to_datetime : nil
124
+ @start_transition ? @start_transition.local_start_at.to_datetime : nil
121
125
  end
122
126
 
123
127
  # The start time of the period in local time as a Time. May be nil if
124
128
  # unbounded.
125
129
  def local_start_time
126
- @start_transition ? @start_transition.local_start.to_time : nil
130
+ @start_transition ? @start_transition.local_start_at.to_time : nil
127
131
  end
128
132
 
129
133
  # The end time of the period in local time as a DateTime. May be nil if
130
134
  # unbounded.
131
135
  def local_end
132
- @end_transition ? @end_transition.local_end.to_datetime : nil
136
+ @end_transition ? @end_transition.local_end_at.to_datetime : nil
133
137
  end
134
138
 
135
139
  # The end time of the period in local time as a Time. May be nil if
136
140
  # unbounded.
137
141
  def local_end_time
138
- @end_transition ? @end_transition.local_end.to_time : nil
142
+ @end_transition ? @end_transition.local_end_at.to_time : nil
139
143
  end
140
144
 
141
145
  # true if daylight savings is in effect for this period; otherwise false.
@@ -168,13 +172,13 @@ module TZInfo
168
172
  # true if the given local DateTime is after the start of the period
169
173
  # (inclusive); otherwise false.
170
174
  def local_after_start?(local)
171
- !@start_transition || @start_transition.local_start <= local
175
+ !@start_transition || @start_transition.local_start_at <= local
172
176
  end
173
177
 
174
178
  # true if the given local DateTime is before the end of the period
175
179
  # (exclusive); otherwise false.
176
180
  def local_before_end?(local)
177
- !@end_transition || @end_transition.local_end > local
181
+ !@end_transition || @end_transition.local_end_at > local
178
182
  end
179
183
 
180
184
  # Converts a UTC DateTime to local time based on the offset of this period.
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2005-2010 Philip Ross
2
+ # Copyright (c) 2005-2013 Philip Ross
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -77,6 +77,10 @@ module TZInfo
77
77
  end
78
78
 
79
79
  def real_timezone
80
+ # Thread-safey: It is possible that the value of @real_timezone may be
81
+ # calculated multiple times in concurrently executing threads. It is not
82
+ # worth the overhead of locking to ensure that @real_timezone is only
83
+ # calculated once.
80
84
  @real_timezone ||= Timezone.get(@identifier)
81
85
  end
82
86
  end
@@ -0,0 +1,136 @@
1
+ #--
2
+ # Copyright (c) 2006-2013 Philip Ross
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #++
22
+
23
+ module TZInfo
24
+ # Represents a transition from one timezone offset to another at a particular
25
+ # date and time.
26
+ class TimezoneTransition
27
+ # The offset this transition changes to (a TimezoneOffset instance).
28
+ attr_reader :offset
29
+
30
+ # The offset this transition changes from (a TimezoneOffset instance).
31
+ attr_reader :previous_offset
32
+
33
+ # Initializes a new TimezoneTransition.
34
+ #
35
+ # TimezoneTransition instances should not normally be constructed manually.
36
+ def initialize(offset, previous_offset)
37
+ @offset = offset
38
+ @previous_offset = previous_offset
39
+ @local_end_at = nil
40
+ @local_start_at = nil
41
+ end
42
+
43
+ # A TimeOrDateTime instance representing the UTC time when this transition
44
+ # occurs.
45
+ def at
46
+ raise NotImplementedError, 'Subclasses must override at'
47
+ end
48
+
49
+ # The UTC time when this transition occurs, returned as a DateTime instance.
50
+ def datetime
51
+ at.to_datetime
52
+ end
53
+
54
+ # The UTC time when this transition occurs, returned as a Time instance.
55
+ def time
56
+ at.to_time
57
+ end
58
+
59
+ # A TimeOrDateTime instance representing the local time when this transition
60
+ # causes the previous observance to end (calculated from at using
61
+ # previous_offset).
62
+ def local_end_at
63
+ # Thread-safey: It is possible that the value of @local_end_at may be
64
+ # calculated multiple times in concurrently executing threads. It is not
65
+ # worth the overhead of locking to ensure that @local_end_at is only
66
+ # calculated once.
67
+
68
+ @local_end_at = at.add_with_convert(@previous_offset.utc_total_offset) unless @local_end_at
69
+ @local_end_at
70
+ end
71
+
72
+ # The local time when this transition causes the previous observance to end,
73
+ # returned as a DateTime instance.
74
+ def local_end
75
+ local_end_at.to_datetime
76
+ end
77
+
78
+ # The local time when this transition causes the previous observance to end,
79
+ # returned as a Time instance.
80
+ def local_end_time
81
+ local_end_at.to_time
82
+ end
83
+
84
+ # A TimeOrDateTime instance representing the local time when this transition
85
+ # causes the next observance to start (calculated from at using offset).
86
+ def local_start_at
87
+ # Thread-safey: It is possible that the value of @local_start_at may be
88
+ # calculated multiple times in concurrently executing threads. It is not
89
+ # worth the overhead of locking to ensure that @local_start_at is only
90
+ # calculated once.
91
+
92
+ @local_start_at = at.add_with_convert(@offset.utc_total_offset) unless @local_start_at
93
+ @local_start_at
94
+ end
95
+
96
+ # The local time when this transition causes the next observance to start,
97
+ # returned as a DateTime instance.
98
+ def local_start
99
+ local_start_at.to_datetime
100
+ end
101
+
102
+ # The local time when this transition causes the next observance to start,
103
+ # returned as a Time instance.
104
+ def local_start_time
105
+ local_start_at.to_time
106
+ end
107
+
108
+ # Returns true if this TimezoneTransition is equal to the given
109
+ # TimezoneTransition. Two TimezoneTransition instances are
110
+ # considered to be equal by == if offset, previous_offset and at are all
111
+ # equal.
112
+ def ==(tti)
113
+ tti.kind_of?(TimezoneTransition) &&
114
+ offset == tti.offset && previous_offset == tti.previous_offset && at == tti.at
115
+ end
116
+
117
+ # Returns true if this TimezoneTransition is equal to the given
118
+ # TimezoneTransition. Two TimezoneTransition instances are
119
+ # considered to be equal by eql? if offset, previous_offset and at are all
120
+ # equal and the type used to define at in both instances is the same.
121
+ def eql?(tti)
122
+ tti.kind_of?(TimezoneTransition) &&
123
+ offset == tti.offset && previous_offset == tti.previous_offset && at.eql?(tti.at)
124
+ end
125
+
126
+ # Returns a hash of this TimezoneTransition instance.
127
+ def hash
128
+ @offset.hash ^ @previous_offset.hash ^ at.hash
129
+ end
130
+
131
+ # Returns internal object state as a programmer-readable string.
132
+ def inspect
133
+ "#<#{self.class}: #{at.inspect},#{@offset.inspect}>"
134
+ end
135
+ end
136
+ end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2006-2013 Philip Ross
2
+ # Copyright (c) 2013 Philip Ross
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  # of this software and associated documentation files (the "Software"), to deal
@@ -20,18 +20,12 @@
20
20
  # THE SOFTWARE.
21
21
  #++
22
22
 
23
- require 'date'
24
-
25
23
  module TZInfo
26
- # Represents an transition from one timezone offset to another at a particular
27
- # date and time.
28
- class TimezoneTransitionInfo #:nodoc:
29
- # The offset this transition changes to (a TimezoneOffsetInfo instance).
30
- attr_reader :offset
31
-
32
- # The offset this transition changes from (a TimezoneOffsetInfo instance).
33
- attr_reader :previous_offset
34
-
24
+ # A TimezoneTransition defined by as integer timestamp, as a rational to
25
+ # create a DateTime or as both.
26
+ #
27
+ # @private
28
+ class TimezoneTransitionDefinition < TimezoneTransition #:nodoc:
35
29
  # The numerator of the DateTime if the transition time is defined as a
36
30
  # DateTime, otherwise the transition time as a timestamp.
37
31
  attr_reader :numerator_or_time
@@ -42,11 +36,11 @@ module TZInfo
42
36
  attr_reader :denominator
43
37
  protected :denominator
44
38
 
45
- # Creates a new TimezoneTransitionInfo with the given offset,
46
- # previous_offset (both TimezoneOffsetInfo instances) and UTC time.
39
+ # Creates a new TimezoneTransitionDefinition with the given offset,
40
+ # previous_offset (both TimezoneOffset instances) and UTC time.
47
41
  #
48
42
  # The time can be specified as a timestamp, as a rational to create a
49
- # DateTime or as both.
43
+ # DateTime, or as both.
50
44
  #
51
45
  # If both a timestamp and rational are given, then the rational will only
52
46
  # be used if the timestamp falls outside of the range of Time on the
@@ -54,13 +48,12 @@ module TZInfo
54
48
  #
55
49
  # DateTimes are created from the rational as follows:
56
50
  #
57
- # RubyCoreSupport.datetime_new!(RubyCoreSupport.rational_new!(numerator_or_time, denominator), 0, Date::ITALY)
51
+ # RubyCoreSupport.datetime_new!(RubyCoreSupport.rational_new!(numerator, denominator), 0, Date::ITALY)
58
52
  #
59
53
  # For performance reasons, the numerator and denominator must be specified
60
54
  # in their lowest form.
61
55
  def initialize(offset, previous_offset, numerator_or_timestamp, denominator_or_numerator = nil, denominator = nil)
62
- @offset = offset
63
- @previous_offset = previous_offset
56
+ super(offset, previous_offset)
64
57
 
65
58
  if denominator
66
59
  numerator = denominator_or_numerator
@@ -90,13 +83,15 @@ module TZInfo
90
83
  end
91
84
 
92
85
  @at = nil
93
- @local_end = nil
94
- @local_start = nil
95
86
  end
96
87
 
97
88
  # A TimeOrDateTime instance representing the UTC time when this transition
98
89
  # occurs.
99
90
  def at
91
+ # Thread-safey: It is possible that the value of @at may be calculated
92
+ # multiple times in concurrently executing threads. It is not worth the
93
+ # overhead of locking to ensure that @at is only calculated once.
94
+
100
95
  unless @at
101
96
  unless @denominator
102
97
  @at = TimeOrDateTime.new(@numerator_or_time)
@@ -110,50 +105,19 @@ module TZInfo
110
105
  @at
111
106
  end
112
107
 
113
- # A TimeOrDateTime instance representing the local time when this transition
114
- # causes the previous observance to end (calculated from at using
115
- # previous_offset).
116
- def local_end
117
- @local_end = at.add_with_convert(@previous_offset.utc_total_offset) unless @local_end
118
- @local_end
119
- end
120
-
121
- # A TimeOrDateTime instance representing the local time when this transition
122
- # causes the next observance to start (calculated from at using offset).
123
- def local_start
124
- @local_start = at.add_with_convert(@offset.utc_total_offset) unless @local_start
125
- @local_start
126
- end
127
-
128
- # Returns true if this TimezoneTransitionInfo is equal to the given
129
- # TimezoneTransitionInfo. Two TimezoneTransitionInfo instances are
130
- # considered to be equal by == if offset, previous_offset and at are all
131
- # equal.
132
- def ==(tti)
133
- tti.kind_of?(TimezoneTransitionInfo) &&
134
- offset == tti.offset && previous_offset == tti.previous_offset && at == tti.at
135
- end
136
-
137
- # Returns true if this TimezoneTransitionInfo is equal to the given
138
- # TimezoneTransitionInfo. Two TimezoneTransitionInfo instances are
139
- # considered to be equal by eql? if offset, previous_offset,
140
- # numerator_or_time and denominator are all equal. This is stronger than ==,
141
- # which just requires the at times to be equal regardless of how they were
142
- # originally specified.
108
+ # Returns true if this TimezoneTransitionDefinition is equal to the given
109
+ # TimezoneTransitionDefinition. Two TimezoneTransitionDefinition instances
110
+ # are considered to be equal by eql? if offset, previous_offset,
111
+ # numerator_or_time and denominator are all equal.
143
112
  def eql?(tti)
144
- tti.kind_of?(TimezoneTransitionInfo) &&
113
+ tti.kind_of?(TimezoneTransitionDefinition) &&
145
114
  offset == tti.offset && previous_offset == tti.previous_offset &&
146
115
  numerator_or_time == tti.numerator_or_time && denominator == tti.denominator
147
116
  end
148
117
 
149
- # Returns a hash of this TimezoneTransitionInfo instance.
118
+ # Returns a hash of this TimezoneTransitionDefinition instance.
150
119
  def hash
151
120
  @offset.hash ^ @previous_offset.hash ^ @numerator_or_time.hash ^ @denominator.hash
152
121
  end
153
-
154
- # Returns internal object state as a programmer-readable string.
155
- def inspect
156
- "#<#{self.class}: #{at.inspect},#{@offset.inspect}>"
157
- end
158
122
  end
159
123
  end
@@ -27,7 +27,9 @@ module TZInfo
27
27
  end
28
28
 
29
29
  # Represents a data timezone defined by a set of offsets and a set
30
- # of transitions
30
+ # of transitions.
31
+ #
32
+ # @private
31
33
  class TransitionDataTimezoneInfo < DataTimezoneInfo #:nodoc:
32
34
 
33
35
  # Constructs a new TransitionDataTimezoneInfo with its identifier.
@@ -52,7 +54,7 @@ module TZInfo
52
54
  def offset(id, utc_offset, std_offset, abbreviation)
53
55
  raise ArgumentError, 'Offset already defined' if @offsets.has_key?(id)
54
56
 
55
- offset = TimezoneOffsetInfo.new(utc_offset, std_offset, abbreviation)
57
+ offset = TimezoneOffset.new(utc_offset, std_offset, abbreviation)
56
58
  @offsets[id] = offset
57
59
  @previous_offset = offset unless @previous_offset
58
60
  end
@@ -62,7 +64,7 @@ module TZInfo
62
64
  # offset_id refers to an id defined with offset. ArgumentError will be
63
65
  # raised if the offset_id cannot be found. numerator_or_time and
64
66
  # denomiator specify the time the transition occurs as. See
65
- # TimezoneTransitionInfo for more detail about specifying times.
67
+ # TimezoneTransition for more detail about specifying times.
66
68
  def transition(year, month, offset_id, numerator_or_timestamp, denominator_or_numerator = nil, denominator = nil)
67
69
  offset = @offsets[offset_id]
68
70
  raise ArgumentError, 'Offset not found' unless offset
@@ -87,7 +89,7 @@ module TZInfo
87
89
  @start_month = month
88
90
  end
89
91
 
90
- @transitions << TimezoneTransitionInfo.new(offset, @previous_offset,
92
+ @transitions << TimezoneTransitionDefinition.new(offset, @previous_offset,
91
93
  numerator_or_timestamp, denominator_or_numerator, denominator)
92
94
  @last_year = year
93
95
  @last_month = month
@@ -148,9 +150,9 @@ module TZInfo
148
150
  result = []
149
151
 
150
152
  start_index = transition_after_start(index - 1)
151
- if start_index && @transitions[start_index].local_end > local
153
+ if start_index && @transitions[start_index].local_end_at > local
152
154
  if start_index > 0
153
- if @transitions[start_index - 1].local_start <= local
155
+ if @transitions[start_index - 1].local_start_at <= local
154
156
  result << TimezonePeriod.new(@transitions[start_index - 1], @transitions[start_index])
155
157
  end
156
158
  else
@@ -164,9 +166,9 @@ module TZInfo
164
166
  start_index = end_index unless start_index
165
167
 
166
168
  start_index.upto(transition_before_end(index + 1)) do |i|
167
- if @transitions[i].local_start <= local
169
+ if @transitions[i].local_start_at <= local
168
170
  if i + 1 < @transitions.length
169
- if @transitions[i + 1].local_end > local
171
+ if @transitions[i + 1].local_end_at > local
170
172
  result << TimezonePeriod.new(@transitions[i], @transitions[i + 1])
171
173
  end
172
174
  else
@@ -183,6 +185,77 @@ module TZInfo
183
185
  end
184
186
  end
185
187
 
188
+ # Returns an Array of TimezoneTransition instances representing the times
189
+ # where the UTC offset of the timezone changes.
190
+ #
191
+ # Transitions are returned up to a given date and time up to a given date
192
+ # and time, specified in UTC (utc_to).
193
+ #
194
+ # A from date and time may also be supplied using the utc_from parameter
195
+ # (also specified in UTC). If utc_from is not nil, only transitions from
196
+ # that date and time onwards will be returned.
197
+ #
198
+ # Comparisons with utc_to are exclusive. Comparisons with utc_from are
199
+ # inclusive. If a transition falls precisely on utc_to, it will be excluded.
200
+ # If a transition falls on utc_from, it will be included.
201
+ #
202
+ # Transitions returned are ordered by when they occur, from earliest to
203
+ # latest.
204
+ #
205
+ # utc_to and utc_from can be specified using either DateTime, Time or
206
+ # integer timestamps (Time.to_i).
207
+ #
208
+ # If utc_from is specified and utc_to is not greater than utc_from, then
209
+ # transitions_up_to raises an ArgumentError exception.
210
+ def transitions_up_to(utc_to, utc_from = nil)
211
+ utc_to = TimeOrDateTime.wrap(utc_to)
212
+ utc_from = utc_from ? TimeOrDateTime.wrap(utc_from) : nil
213
+
214
+ if utc_from && utc_to <= utc_from
215
+ raise ArgumentError, 'utc_to must be greater than utc_from'
216
+ end
217
+
218
+ unless @transitions.empty?
219
+ if utc_from
220
+ from = transition_after_start(transition_index(utc_from.year, utc_from.mon))
221
+
222
+ if from
223
+ while from < @transitions.length && @transitions[from].at < utc_from
224
+ from += 1
225
+ end
226
+
227
+ if from >= @transitions.length
228
+ return []
229
+ end
230
+ else
231
+ # utc_from is later than last transition.
232
+ return []
233
+ end
234
+ else
235
+ from = 0
236
+ end
237
+
238
+ to = transition_before_end(transition_index(utc_to.year, utc_to.mon))
239
+
240
+ if to
241
+ while to >= 0 && @transitions[to].at >= utc_to
242
+ to -= 1
243
+ end
244
+
245
+ if to < 0
246
+ return []
247
+ end
248
+ else
249
+ # utc_to is earlier than first transition.
250
+ return []
251
+ end
252
+
253
+ @transitions[from..to]
254
+ else
255
+ []
256
+ end
257
+ end
258
+
186
259
  private
187
260
  # Returns the index into the @transitions_index array for a given year
188
261
  # and month.