tzinfo 1.2.2 → 1.2.3

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9ebc85eb68af0647a8989ba7cb104b24100ef198
4
- data.tar.gz: a2fdbcd5b2c456658ef15e7cedea229a66259a03
3
+ metadata.gz: be3c32bd74920808d67de39efaf3a73c6e8906d9
4
+ data.tar.gz: f553215128b1b18c614252434e45d9d4e1c2dc53
5
5
  SHA512:
6
- metadata.gz: 96a612b4835747ab4a3990195c1d6ff0e8fbed4905091e0380fc0b8fb64f4635a5f2cdf1a4deb4d0e3983e64a346c8afae2b063d1f53a4a5fddda4950b1eaf11
7
- data.tar.gz: 59611995417725d20c591824e40b09df9325c39fb0161744228876effb6d263776cf12e9e209fa5380207e017fc38dd49a960c7f8582243c3982745ee1c3e37c
6
+ metadata.gz: af62bf6235210846b42517a1151a20e2e5c376005c3aa9b90515ed97c729d39e0b9fd2fd743708acfc6bb9fae55bf68a69c7408168f942d4b256feed02016d0a
7
+ data.tar.gz: b8073737407948dc494a2d9a4215044ffeae2b7ec91e9047e6fdf0b328af021e371f4e21f51d5dc798c232c80d23f2b11ee9bc9cc5d6a3c34cd806c56933c5ba
Binary file
data.tar.gz.sig CHANGED
Binary file
data/CHANGES.md CHANGED
@@ -1,3 +1,24 @@
1
+ Version 1.2.3 - 25-Mar-2017
2
+ ---------------------------
3
+
4
+ * Reduce the number of String objects allocated when loading zoneinfo files.
5
+ #54.
6
+ * Make Timezone#friendly_identifier compatible with frozen string literals.
7
+ * Improve the algorithm for deriving the utc_offset from zoneinfo files. This
8
+ now correctly handles Pacific/Apia switching from one side of the
9
+ International Date Line to the other whilst observing daylight savings time.
10
+ #66.
11
+ * Fix an UnknownTimezone exception when calling transitions_up_to or
12
+ offsets_up_to on a TimezoneProxy instance obtained from Timezone.get_proxy.
13
+ * Allow the Factory zone to be obtained from the Zoneinfo data source.
14
+ * Ignore the /usr/share/zoneinfo/timeconfig symlink included in Slackware
15
+ distributions. #64.
16
+ * Fix Timezone#strftime handling of %Z expansion when %Z is prefixed with more
17
+ than one percent. #31.
18
+ * Support expansion of %z, %:z, %::z and %:::z to the UTC offset of the time
19
+ zone in Timezone#strftime. #31 and #67.
20
+
21
+
1
22
  Version 1.2.2 - 8-Aug-2014
2
23
  --------------------------
3
24
 
@@ -92,6 +113,106 @@ Version 1.0.0 - 2-Jun-2013
92
113
  use other TimezonePeriod instance methods instead (issue #7655).
93
114
 
94
115
 
116
+ Version 0.3.53 (tzdata v2017b) - 23-Mar-2017
117
+ --------------------------------------------
118
+
119
+ * Updated to tzdata version 2017b
120
+ (https://mm.icann.org/pipermail/tz-announce/2017-March/000046.html).
121
+
122
+
123
+ Version 0.3.52 (tzdata v2016h) - 28-Oct-2016
124
+ --------------------------------------------
125
+
126
+ * Updated to tzdata version 2016h
127
+ (https://mm.icann.org/pipermail/tz-announce/2016-October/000042.html).
128
+
129
+
130
+ Version 0.3.51 (tzdata v2016f) - 5-Jul-2016
131
+ -------------------------------------------
132
+
133
+ * Updated to tzdata version 2016f
134
+ (https://mm.icann.org/pipermail/tz-announce/2016-July/000040.html).
135
+
136
+
137
+ Version 0.3.50 (tzdata v2016e) - 14-Jun-2016
138
+ --------------------------------------------
139
+
140
+ * Updated to tzdata version 2016e
141
+ (https://mm.icann.org/pipermail/tz-announce/2016-June/000039.html).
142
+
143
+
144
+ Version 0.3.49 (tzdata v2016d) - 18-Apr-2016
145
+ --------------------------------------------
146
+
147
+ * Updated to tzdata version 2016d
148
+ (https://mm.icann.org/pipermail/tz-announce/2016-April/000038.html).
149
+
150
+
151
+ Version 0.3.48 (tzdata v2016c) - 23-Mar-2016
152
+ --------------------------------------------
153
+
154
+ * Updated to tzdata version 2016c
155
+ (https://mm.icann.org/pipermail/tz-announce/2016-March/000037.html).
156
+
157
+
158
+ Version 0.3.47 (tzdata v2016b) - 15-Mar-2016
159
+ --------------------------------------------
160
+
161
+ * Updated to tzdata version 2016b
162
+ (https://mm.icann.org/pipermail/tz-announce/2016-March/000036.html).
163
+
164
+
165
+ Version 0.3.46 (tzdata v2015g) - 2-Dec-2015
166
+ -------------------------------------------
167
+
168
+ * From version 2015e, the IANA time zone database uses non-ASCII characters in
169
+ country names. Backport the encoding handling from TZInfo::Data to allow
170
+ TZInfo 0.3.x to support Ruby 1.9 (which would otherwise fail with an invalid
171
+ byte sequence error when loading the countries index). Resolves #41.
172
+
173
+
174
+ Version 0.3.45 (tzdata v2015g) - 3-Oct-2015
175
+ -------------------------------------------
176
+
177
+ * Updated to tzdata version 2015g
178
+ (http://mm.icann.org/pipermail/tz-announce/2015-October/000034.html).
179
+
180
+
181
+ Version 0.3.44 (tzdata v2015d) - 24-Apr-2015
182
+ --------------------------------------------
183
+
184
+ * Updated to tzdata version 2015d
185
+ (http://mm.icann.org/pipermail/tz-announce/2015-April/000031.html).
186
+
187
+
188
+ Version 0.3.43 (tzdata v2015a) - 31-Jan-2015
189
+ --------------------------------------------
190
+
191
+ * Updated to tzdata version 2015a
192
+ (http://mm.icann.org/pipermail/tz-announce/2015-January/000028.html).
193
+
194
+
195
+ Version 0.3.42 (tzdata v2014i) - 23-Oct-2014
196
+ --------------------------------------------
197
+
198
+ * Updated to tzdata version 2014i
199
+ (http://mm.icann.org/pipermail/tz-announce/2014-October/000026.html).
200
+
201
+
202
+ Version 0.3.41 (tzdata v2014f) - 8-Aug-2014
203
+ -------------------------------------------
204
+
205
+ * Updated to tzdata version 2014f
206
+ (http://mm.icann.org/pipermail/tz-announce/2014-August/000023.html).
207
+
208
+
209
+ Version 0.3.40 (tzdata v2014e) - 10-Jul-2014
210
+ --------------------------------------------
211
+
212
+ * Updated to tzdata version 2014e
213
+ (http://mm.icann.org/pipermail/tz-announce/2014-June/000022.html).
214
+
215
+
95
216
  Version 0.3.39 (tzdata v2014a) - 9-Mar-2014
96
217
  -------------------------------------------
97
218
 
@@ -177,7 +298,7 @@ Version 0.3.29 (tzdata v2011h) - 27-Jun-2011
177
298
 
178
299
 
179
300
  Version 0.3.28 (tzdata v2011g) - 13-Jun-2011
180
- --------------------------------------------=
301
+ ---------------------------------------------
181
302
 
182
303
  * Add support for Ruby 1.9.3 (trunk revision 31668 and later). Thanks to
183
304
  Aaron Patterson for reporting the problems running on the new version.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2005-2014 Philip Ross
1
+ Copyright (c) 2005-2017 Philip Ross
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of
4
4
  this software and associated documentation files (the "Software"), to deal in
data/Rakefile CHANGED
@@ -21,7 +21,10 @@ class TZInfoPackageTask < Gem::PackageTask
21
21
  private :orig_sh
22
22
 
23
23
  def sh(*cmd, &block)
24
- if cmd.first =~ /\A__tar_with_owner__ -?([zjcvf]+)(.*)\z/
24
+ if cmd[0] == '__tar_with_owner__' && cmd[1] =~ /\A-?[zjcvf]+\z/
25
+ opts = cmd[1]
26
+ cmd = ['tar', 'c', '--owner', '0', '--group', '0', "#{opts.start_with?('-') ? '' : '-'}#{opts.gsub('c', '')}"] + cmd.drop(2)
27
+ elsif cmd.first =~ /\A__tar_with_owner__ -?([zjcvf]+)(.*)\z/
25
28
  opts = $1
26
29
  args = $2
27
30
  cmd[0] = "tar c --owner 0 --group 0 -#{opts.gsub('c', '')}#{args}"
@@ -236,13 +236,9 @@ module TZInfo
236
236
  elsif parts.length == 1
237
237
  parts[0]
238
238
  else
239
- if skip_first_part
240
- result = ''
241
- else
242
- result = parts[0] + ' - '
243
- end
244
-
245
- parts[1, parts.length - 1].reverse_each {|part|
239
+ prefix = skip_first_part ? nil : "#{parts[0]} - "
240
+
241
+ parts = parts.drop(1).map do |part|
246
242
  part.gsub!(/_/, ' ')
247
243
 
248
244
  if part.index(/[a-z]/)
@@ -254,13 +250,11 @@ module TZInfo
254
250
  # Missing an apostrophe if two consecutive upper case characters.
255
251
  part.gsub!(/([A-Z])([A-Z])/, '\1\'\2')
256
252
  end
257
-
258
- result << part
259
- result << ', '
260
- }
261
-
262
- result.slice!(result.length - 2, 2)
263
- result
253
+
254
+ part
255
+ end
256
+
257
+ "#{prefix}#{parts.reverse.join(', ')}"
264
258
  end
265
259
  end
266
260
 
@@ -559,22 +553,60 @@ module TZInfo
559
553
 
560
554
  alias :current_time_and_period :current_period_and_time
561
555
 
562
- # Converts a time in UTC to local time and returns it as a string
563
- # according to the given format. The formatting is identical to
564
- # Time.strftime and DateTime.strftime, except %Z is replaced with the
565
- # timezone abbreviation for the specified time (for example, EST or EDT).
556
+ # Converts a time in UTC to local time and returns it as a string according
557
+ # to the given format.
558
+ #
559
+ # The formatting is identical to Time.strftime and DateTime.strftime, except
560
+ # %Z and %z are replaced with the timezone abbreviation (for example, EST or
561
+ # EDT) and offset for the specified Timezone and time.
562
+ #
563
+ # The offset can be formatted as follows:
564
+ #
565
+ # - %z - hour and minute (e.g. +0500)
566
+ # - %:z - hour and minute separated with a colon (e.g. +05:00)
567
+ # - %::z - hour minute and second separated with colons (e.g. +05:00:00)
568
+ # - %:::z - hour only (e.g. +05)
569
+ #
570
+ # Timezone#strftime currently handles the replacement of %z. From TZInfo
571
+ # version 2.0.0, %z will be passed to Time#strftime and DateTime#strftime
572
+ # instead. Some of the formatting options may cease to be available
573
+ # depending on the version of Ruby in use (for example, %:::z is only
574
+ # supported by Time#strftime from MRI version 2.0.0 onwards.)
566
575
  def strftime(format, utc = Time.now.utc)
567
576
  period = period_for_utc(utc)
568
577
  local = period.to_local(utc)
569
578
  local = Time.at(local).utc unless local.kind_of?(Time) || local.kind_of?(DateTime)
570
579
  abbreviation = period.abbreviation.to_s.gsub(/%/, '%%')
571
580
 
572
- format = format.gsub(/(.?)%Z/) do
573
- if $1 == '%'
574
- # return %%Z so the real strftime treats it as a literal %Z too
575
- '%%Z'
576
- else
581
+ format = format.gsub(/%(%*)(Z|:*z)/) do
582
+ if $1.length.odd?
583
+ # Escaped literal percent or series of percents. Pass on to strftime.
584
+ "#$1%#$2"
585
+ elsif $2 == "Z"
577
586
  "#$1#{abbreviation}"
587
+ else
588
+ m, s = period.utc_total_offset.divmod(60)
589
+ h, m = m.divmod(60)
590
+ case $2.length
591
+ when 1
592
+ "#$1#{'%+03d%02d' % [h,m]}"
593
+ when 2
594
+ "#$1#{'%+03d:%02d' % [h,m]}"
595
+ when 3
596
+ "#$1#{'%+03d:%02d:%02d' % [h,m,s]}"
597
+ when 4
598
+ "#$1#{'%+03d' % [h]}"
599
+ else # more than 3 colons - not a valid option
600
+ # Passing the invalid format string through to Time#strftime or
601
+ # DateTime#strtime would normally result in it being returned in the
602
+ # result. However, with Ruby 1.8.7 on Windows (as tested with Ruby
603
+ # 1.8.7-p374 from http://rubyinstaller.org/downloads/archives), this
604
+ # causes Time#strftime to always return an empty string (e.g.
605
+ # Time.now.strftime('a %::::z b') returns '').
606
+ #
607
+ # Escape the percent to force it to be evaluated as a literal.
608
+ "#$1%%#$2"
609
+ end
578
610
  end
579
611
  end
580
612
 
@@ -34,6 +34,8 @@ module TZInfo
34
34
 
35
35
  # Converts a UTC Time, DateTime or integer timestamp to local time, based on
36
36
  # the offset of this period.
37
+ #
38
+ # Deprecation warning: this method will be removed in TZInfo version 2.0.0.
37
39
  def to_local(utc)
38
40
  TimeOrDateTime.wrap(utc) {|wrapped|
39
41
  wrapped + @utc_total_offset
@@ -42,6 +44,8 @@ module TZInfo
42
44
 
43
45
  # Converts a local Time, DateTime or integer timestamp to UTC, based on the
44
46
  # offset of this period.
47
+ #
48
+ # Deprecation warning: this method will be removed in TZInfo version 2.0.0.
45
49
  def to_utc(local)
46
50
  TimeOrDateTime.wrap(local) {|wrapped|
47
51
  wrapped - @utc_total_offset
@@ -126,45 +126,62 @@ module TZInfo
126
126
  end
127
127
 
128
128
  # true if this period is valid for the given UTC DateTime; otherwise false.
129
+ #
130
+ # Deprecation warning: this method will be removed in TZInfo version 2.0.0.
129
131
  def valid_for_utc?(utc)
130
132
  utc_after_start?(utc) && utc_before_end?(utc)
131
133
  end
132
134
 
133
135
  # true if the given UTC DateTime is after the start of the period
134
136
  # (inclusive); otherwise false.
137
+ #
138
+ # Deprecation warning: this method will be removed in TZInfo version 2.0.0.
135
139
  def utc_after_start?(utc)
136
140
  !@start_transition || @start_transition.at <= utc
137
141
  end
138
142
 
139
143
  # true if the given UTC DateTime is before the end of the period
140
144
  # (exclusive); otherwise false.
145
+ #
146
+ # Deprecation warning: this method will be removed in TZInfo version 2.0.0.
141
147
  def utc_before_end?(utc)
142
148
  !@end_transition || @end_transition.at > utc
143
149
  end
144
150
 
145
- # true if this period is valid for the given local DateTime; otherwise false.
151
+ # true if this period is valid for the given local DateTime; otherwise
152
+ # false.
153
+ #
154
+ # Deprecation warning: this method will be removed in TZInfo version 2.0.0.
146
155
  def valid_for_local?(local)
147
156
  local_after_start?(local) && local_before_end?(local)
148
157
  end
149
158
 
150
159
  # true if the given local DateTime is after the start of the period
151
160
  # (inclusive); otherwise false.
161
+ #
162
+ # Deprecation warning: this method will be removed in TZInfo version 2.0.0.
152
163
  def local_after_start?(local)
153
164
  !@start_transition || @start_transition.local_start_at <= local
154
165
  end
155
166
 
156
167
  # true if the given local DateTime is before the end of the period
157
168
  # (exclusive); otherwise false.
169
+ #
170
+ # Deprecation warning: this method will be removed in TZInfo version 2.0.0.
158
171
  def local_before_end?(local)
159
172
  !@end_transition || @end_transition.local_end_at > local
160
173
  end
161
174
 
162
175
  # Converts a UTC DateTime to local time based on the offset of this period.
176
+ #
177
+ # Deprecation warning: this method will be removed in TZInfo version 2.0.0.
163
178
  def to_local(utc)
164
179
  @offset.to_local(utc)
165
180
  end
166
181
 
167
182
  # Converts a local DateTime to UTC based on the offset of this period.
183
+ #
184
+ # Deprecation warning: this method will be removed in TZInfo version 2.0.0.
168
185
  def to_utc(local)
169
186
  @offset.to_utc(local)
170
187
  end
@@ -38,6 +38,35 @@ module TZInfo
38
38
  real_timezone.periods_for_local(local)
39
39
  end
40
40
 
41
+ # Returns an Array of TimezoneTransition instances representing the times
42
+ # where the UTC offset of the timezone changes.
43
+ #
44
+ # Transitions are returned up to a given date and time up to a given date
45
+ # and time (to).
46
+ #
47
+ # A from date and time may also be supplied using the from parameter. If
48
+ # from is not nil, only transitions from that date and time onwards will be
49
+ # returned.
50
+ #
51
+ # Comparisons with to are exclusive. Comparisons with from are inclusive.
52
+ # If a transition falls precisely on to, it will be excluded. If a
53
+ # transition falls on from, it will be included.
54
+ #
55
+ # Transitions returned are ordered by when they occur, from earliest to
56
+ # latest.
57
+ #
58
+ # to and from can be specified using either a Time, DateTime, Time or
59
+ # Timestamp.
60
+ #
61
+ # If from is specified and to is not greater than from, then an
62
+ # ArgumentError exception is raised.
63
+ #
64
+ # ArgumentError is raised if to is nil or of either to or from are
65
+ # Timestamps with unspecified offsets.
66
+ def transitions_up_to(to, from = nil)
67
+ real_timezone.transitions_up_to(to, from)
68
+ end
69
+
41
70
  # Returns the canonical zone for this Timezone.
42
71
  def canonical_zone
43
72
  real_timezone.canonical_zone
@@ -349,9 +349,9 @@ module TZInfo
349
349
  # localtime current local timezone (may be a link).
350
350
  # posix, posixrules and right are directories containing other versions of the zoneinfo files.
351
351
  # src is a directory containing the tzdata source included on Solaris.
352
- # Factory is the compiled in default timezone.
352
+ # timeconfig is a symlink included on Slackware.
353
353
 
354
- enum_timezones(nil, ['+VERSION', 'localtime', 'posix', 'posixrules', 'right', 'src', 'Factory']) do |identifier|
354
+ enum_timezones(nil, ['+VERSION', 'localtime', 'posix', 'posixrules', 'right', 'src', 'timeconfig']) do |identifier|
355
355
  index << identifier
356
356
  end
357
357
 
@@ -432,7 +432,7 @@ module TZInfo
432
432
 
433
433
  file_is_5_column = true if column5
434
434
 
435
- zone_tab << [codes.split(','), zone_identifier, latitude, longitude, column4, column5]
435
+ zone_tab << [codes.split(','.freeze), zone_identifier, latitude, longitude, column4, column5]
436
436
  end
437
437
  end
438
438
  end
@@ -480,7 +480,7 @@ module TZInfo
480
480
  def dms_to_rational(sign, degrees, minutes, seconds = nil)
481
481
  result = degrees.to_i + Rational(minutes.to_i, 60)
482
482
  result += Rational(seconds.to_i, 3600) if seconds
483
- result = -result if sign == '-'
483
+ result = -result if sign == '-'.freeze
484
484
  result
485
485
  end
486
486
  end
@@ -56,39 +56,109 @@ module TZInfo
56
56
  result
57
57
  end
58
58
 
59
- # Zoneinfo doesn't include the offset from standard time (std_offset).
60
- # Derive the missing offsets by looking at changes in the total UTC
61
- # offset.
59
+ # Zoneinfo files don't include the offset from standard time (std_offset)
60
+ # for DST periods. Derive the base offset (utc_offset) where DST is
61
+ # observed from either the previous or next non-DST period.
62
62
  #
63
- # This will be run through forwards and then backwards by the parse
64
- # method.
65
- def derive_offsets(transitions, offsets)
66
- previous_offset = nil
63
+ # Returns the index of the offset to be used prior to the first
64
+ # transition.
65
+ def derive_offsets(transitions, offsets)
66
+ # The first non-DST offset (if there is one) is the offset observed
67
+ # before the first transition. Fallback to the first DST offset if there
68
+ # are no non-DST offsets.
69
+ first_non_dst_offset_index = offsets.index {|o| !o[:is_dst] }
70
+ first_offset_index = first_non_dst_offset_index || 0
71
+ return first_offset_index if transitions.empty?
67
72
 
68
- transitions.each do |t|
69
- offset = offsets[t[:offset]]
73
+ # Determine the utc_offset of the next non-dst offset at each transition.
74
+ utc_offset_from_next = nil
70
75
 
71
- if !offset[:std_offset] && offset[:is_dst] && previous_offset
72
- difference = offset[:utc_total_offset] - previous_offset[:utc_total_offset]
73
-
74
- if previous_offset[:is_dst]
75
- if previous_offset[:std_offset]
76
- std_offset = previous_offset[:std_offset] + difference
77
- else
78
- std_offset = nil
79
- end
80
- else
81
- std_offset = difference
76
+ transitions.reverse_each do |transition|
77
+ offset = offsets[transition[:offset]]
78
+ if offset[:is_dst]
79
+ transition[:utc_offset_from_next] = utc_offset_from_next if utc_offset_from_next
80
+ else
81
+ utc_offset_from_next = offset[:utc_total_offset]
82
+ end
83
+ end
84
+
85
+ utc_offset_from_previous = first_non_dst_offset_index ? offsets[first_non_dst_offset_index][:utc_total_offset] : nil
86
+ defined_offsets = {}
87
+
88
+ transitions.each do |transition|
89
+ offset_index = transition[:offset]
90
+ offset = offsets[offset_index]
91
+ utc_total_offset = offset[:utc_total_offset]
92
+
93
+ if offset[:is_dst]
94
+ utc_offset_from_next = transition[:utc_offset_from_next]
95
+
96
+ difference_to_previous = utc_total_offset - (utc_offset_from_previous || utc_total_offset)
97
+ difference_to_next = utc_total_offset - (utc_offset_from_next || utc_total_offset)
98
+
99
+ utc_offset = if difference_to_previous > 0 && difference_to_next > 0
100
+ difference_to_previous < difference_to_next ? utc_offset_from_previous : utc_offset_from_next
101
+ elsif difference_to_previous > 0
102
+ utc_offset_from_previous
103
+ elsif difference_to_next > 0
104
+ utc_offset_from_next
105
+ else # difference_to_previous <= 0 && difference_to_next <= 0
106
+ # DST, but the either the offset has stayed the same or decreased
107
+ # relative to both the previous and next used base utc offset, or
108
+ # there are no non-DST offsets. Assume a 1 hour offset from base.
109
+ utc_total_offset - 3600
82
110
  end
83
-
84
- if std_offset && std_offset > 0
85
- offset[:std_offset] = std_offset
86
- offset[:utc_offset] = offset[:utc_total_offset] - std_offset
111
+
112
+ if !offset[:utc_offset]
113
+ offset[:utc_offset] = utc_offset
114
+ defined_offsets[offset] = offset_index
115
+ elsif offset[:utc_offset] != utc_offset
116
+ # An earlier transition has already derived a different
117
+ # utc_offset. Define a new offset or reuse an existing identically
118
+ # defined offset.
119
+ new_offset = offset.dup
120
+ new_offset[:utc_offset] = utc_offset
121
+
122
+ offset_index = defined_offsets[new_offset]
123
+
124
+ unless offset_index
125
+ offsets << new_offset
126
+ offset_index = offsets.length - 1
127
+ defined_offsets[new_offset] = offset_index
128
+ end
129
+
130
+ transition[:offset] = offset_index
87
131
  end
132
+ else
133
+ utc_offset_from_previous = utc_total_offset
88
134
  end
89
-
90
- previous_offset = offset
91
135
  end
136
+
137
+ first_offset_index
138
+ end
139
+
140
+ # Defines an offset for the timezone based on the given index and offset
141
+ # Hash.
142
+ def define_offset(index, offset)
143
+ utc_total_offset = offset[:utc_total_offset]
144
+ utc_offset = offset[:utc_offset]
145
+
146
+ if utc_offset
147
+ # DST offset with base utc_offset derived by derive_offsets.
148
+ std_offset = utc_total_offset - utc_offset
149
+ elsif offset[:is_dst]
150
+ # DST offset unreferenced by a transition (offset in use before the
151
+ # first transition). No derived base UTC offset, so assume 1 hour
152
+ # DST.
153
+ utc_offset = utc_total_offset - 3600
154
+ std_offset = 3600
155
+ else
156
+ # Non-DST offset.
157
+ utc_offset = utc_total_offset
158
+ std_offset = 0
159
+ end
160
+
161
+ offset index, utc_offset, std_offset, offset[:abbr].untaint.to_sym
92
162
  end
93
163
 
94
164
  # Parses a zoneinfo file and intializes the DataTimezoneInfo structures.
@@ -127,27 +197,27 @@ module TZInfo
127
197
  transitions = []
128
198
 
129
199
  if using_64bit
130
- (0...timecnt).each do |i|
131
- high, low = check_read(file, 8).unpack('NN')
200
+ timecnt.times do |i|
201
+ high, low = check_read(file, 8).unpack('NN'.freeze)
132
202
  transition_time = make_signed_int64(high, low)
133
203
  transitions << {:at => transition_time}
134
204
  end
135
205
  else
136
- (0...timecnt).each do |i|
137
- transition_time = make_signed_int32(check_read(file, 4).unpack('N')[0])
206
+ timecnt.times do |i|
207
+ transition_time = make_signed_int32(check_read(file, 4).unpack('N'.freeze)[0])
138
208
  transitions << {:at => transition_time}
139
209
  end
140
210
  end
141
211
 
142
- (0...timecnt).each do |i|
143
- localtime_type = check_read(file, 1).unpack('C')[0]
212
+ timecnt.times do |i|
213
+ localtime_type = check_read(file, 1).unpack('C'.freeze)[0]
144
214
  transitions[i][:offset] = localtime_type
145
215
  end
146
216
 
147
217
  offsets = []
148
218
 
149
- (0...typecnt).each do |i|
150
- gmtoff, isdst, abbrind = check_read(file, 6).unpack('NCC')
219
+ typecnt.times do |i|
220
+ gmtoff, isdst, abbrind = check_read(file, 6).unpack('NCC'.freeze)
151
221
  gmtoff = make_signed_int32(gmtoff)
152
222
  isdst = isdst == 1
153
223
  offset = {:utc_total_offset => gmtoff, :is_dst => isdst, :abbr_index => abbrind}
@@ -179,33 +249,12 @@ module TZInfo
179
249
  end
180
250
 
181
251
  # Derive the offsets from standard time (std_offset).
182
- derive_offsets(transitions, offsets)
183
- derive_offsets(transitions.reverse, offsets)
252
+ first_offset_index = derive_offsets(transitions, offsets)
184
253
 
185
- # Assign anything left a standard offset of one hour
186
- offsets.each do |o|
187
- if !o[:std_offset] && o[:is_dst]
188
- o[:std_offset] = 3600
189
- o[:utc_offset] = o[:utc_total_offset] - 3600
190
- end
191
- end
192
-
193
- # Find the first non-dst offset. This is used as the offset for the time
194
- # before the first transition.
195
- first = nil
196
- offsets.each_with_index do |o, i|
197
- if !o[:is_dst]
198
- first = i
199
- break
200
- end
201
- end
202
-
203
- if first
204
- offset first, offsets[first][:utc_offset], offsets[first][:std_offset], offsets[first][:abbr].untaint.to_sym
205
- end
254
+ define_offset(first_offset_index, offsets[first_offset_index])
206
255
 
207
256
  offsets.each_with_index do |o, i|
208
- offset i, o[:utc_offset], o[:std_offset], o[:abbr].untaint.to_sym unless i == first
257
+ define_offset(i, o) unless i == first_offset_index
209
258
  end
210
259
 
211
260
  if !using_64bit && !RubyCoreSupport.time_supports_negative