Skip to content

Commit 5a596b0

Browse files
committed
Fix an offset error for datetimes between the before last and last transition
1 parent 3a0513c commit 5a596b0

File tree

3 files changed

+47
-47
lines changed

3 files changed

+47
-47
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Fixed
66

77
- Fixed an error when comparing a Period to a timedelta in PyPy.
8+
- Fixed an offset error for datetimes between the before last and last transition.
89

910

1011
## [1.4.0] - 2018-01-22

pendulum/tz/timezone.py

Lines changed: 37 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -218,65 +218,55 @@ def _normalize(self, dt, dst_rule=None):
218218
offset = self._tzinfos[tzinfo_index].offset
219219
unix_time = (dt - datetime(1970, 1, 1)).total_seconds() - offset
220220
else:
221-
# tr.pre_time < dt < tr.time
222-
# Skipped time
223-
if dst_rule == self.TRANSITION_ERROR:
224-
raise NonExistingTime(dt)
225-
elif dst_rule == self.PRE_TRANSITION:
226-
# We do not apply the transition
227-
(unix_time,
228-
tzinfo_index) = self._get_previous_transition_time(tr, dt, skipped=True)
229-
else:
230-
unix_time = tr.unix_time - (tr.time - dt).total_seconds()
221+
unix_time, tzinfo_index = self._get_time(dt, tr, dst_rule)
231222
elif tr is end:
232223
if tr.pre_time < dt:
233224
# After the last transition.
234225
unix_time = tr.unix_time + (dt - tr.time).total_seconds()
235226
else:
236-
# tr.time <= dt <= tr.pre_time
237-
# Repeated time
238-
if dst_rule == self.TRANSITION_ERROR:
239-
raise AmbiguousTime(dt)
240-
elif dst_rule == self.PRE_TRANSITION:
241-
# We do not apply the transition
242-
(unix_time,
243-
tzinfo_index) = self._get_previous_transition_time(tr, dt)
244-
else:
245-
unix_time = tr.unix_time + (dt - tr.time).total_seconds()
227+
unix_time, tzinfo_index = self._get_time(dt, tr, dst_rule)
246228
else:
247-
if tr.pre_time <= dt < tr.time:
248-
# tr.pre_time <= dt < tr.time
249-
# Skipped time
250-
if dst_rule == self.TRANSITION_ERROR:
251-
raise NonExistingTime(dt)
252-
elif dst_rule == self.PRE_TRANSITION:
253-
# We do not apply the transition
254-
(unix_time,
255-
tzinfo_index) = self._get_previous_transition_time(tr, dt, skipped=True)
256-
else:
257-
unix_time = tr.unix_time - (tr.pre_time - dt).total_seconds()
258-
elif tr.time <= dt <= tr.pre_time:
259-
# tr.time <= dt <= tr.pre_time
260-
# Repeated time
261-
if dst_rule == self.TRANSITION_ERROR:
262-
raise AmbiguousTime(dt)
263-
elif dst_rule == self.PRE_TRANSITION:
264-
# We do not apply the transition
265-
(unix_time,
266-
tzinfo_index) = self._get_previous_transition_time(tr, dt)
267-
else:
268-
unix_time = tr.unix_time + (dt - tr.time).total_seconds()
269-
else:
270-
# In between transitions
271-
# The actual transition type is the previous transition one
272-
(unix_time,
273-
tzinfo_index) = self._get_previous_transition_time(tr, dt)
229+
unix_time, tzinfo_index = self._get_time(dt, tr, dst_rule)
274230

275231
return self._to_local_time(
276232
unix_time, dt.microsecond, tzinfo_index,
277233
fold
278234
)
279235

236+
def _get_time(self, dt, tr, dst_rule):
237+
tzinfo_index = tr._tzinfo_index
238+
239+
if tr.pre_time <= dt < tr.time:
240+
# tr.pre_time <= dt < tr.time
241+
# Skipped time
242+
if dst_rule == self.TRANSITION_ERROR:
243+
raise NonExistingTime(dt)
244+
elif dst_rule == self.PRE_TRANSITION:
245+
# We do not apply the transition
246+
(unix_time,
247+
tzinfo_index) = self._get_previous_transition_time(tr, dt,
248+
skipped=True)
249+
else:
250+
unix_time = tr.unix_time - (tr.pre_time - dt).total_seconds()
251+
elif tr.time <= dt <= tr.pre_time:
252+
# tr.time <= dt <= tr.pre_time
253+
# Repeated time
254+
if dst_rule == self.TRANSITION_ERROR:
255+
raise AmbiguousTime(dt)
256+
elif dst_rule == self.PRE_TRANSITION:
257+
# We do not apply the transition
258+
(unix_time,
259+
tzinfo_index) = self._get_previous_transition_time(tr, dt)
260+
else:
261+
unix_time = tr.unix_time + (dt - tr.time).total_seconds()
262+
else:
263+
# In between transitions
264+
# The actual transition type is the previous transition one
265+
(unix_time,
266+
tzinfo_index) = self._get_previous_transition_time(tr, dt)
267+
268+
return unix_time, tzinfo_index
269+
280270
def _convert(self, dt):
281271
"""
282272
Converts a timezone-aware datetime to local time.

tests/tz_tests/test_timezone.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,15 @@ def test_on_last_transition(self):
227227
assert dt.microsecond == 0
228228
assert dt.utcoffset().total_seconds() == 7200
229229

230+
def test_just_before_last_transition(self):
231+
tz = pendulum.timezone('Asia/Shanghai')
232+
dt = datetime(1991, 4, 20, 1, 49, 8)
233+
dt = tz.convert(dt, dst_rule=tz.POST_TRANSITION)
234+
235+
epoch = datetime(1970, 1, 1, tzinfo=timezone('UTC'))
236+
expected = (dt - epoch).total_seconds()
237+
assert expected == 672079748.0
238+
230239
def test_convert_fold_attribute_is_honored(self):
231240
self.skip_if_not_36()
232241

0 commit comments

Comments
 (0)