Skip to content

Commit c8b6198

Browse files
committed
Fixes behavior for some short timezones.
1 parent 7bbb51b commit c8b6198

File tree

3 files changed

+82
-11
lines changed

3 files changed

+82
-11
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Change Log
22

3+
## [Unreleased]
4+
5+
### Fixed
6+
7+
- Fixed behavior of some short timezones (like EST, MST or HST).
8+
9+
310
## [1.2.2] - 2017-06-15
411

512
### Fixed

pendulum/tz/timezone.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def _normalize(self, dt, dst_rule=None):
187187

188188
if dt < begin.time:
189189
tr = begin
190-
elif not dt < end.time:
190+
elif dt >= end.time:
191191
tr = end
192192
else:
193193
idx = self._find_transition_index(dt)
@@ -202,7 +202,7 @@ def _normalize(self, dt, dst_rule=None):
202202

203203
tzinfo_index = tr._tzinfo_index
204204
if tr is begin:
205-
if not tr.pre_time < dt:
205+
if tr.pre_time >= dt:
206206
# Before first transition, so use the default offset.
207207
offset = self._tzinfos[self._default_tzinfo_index].offset
208208
unix_time = (dt - datetime(1970, 1, 1)).total_seconds() - offset
@@ -212,16 +212,21 @@ def _normalize(self, dt, dst_rule=None):
212212
fold
213213
)
214214
else:
215-
# tr.pre_time < dt < tr.time
216-
# Skipped time
217-
if dst_rule == self.TRANSITION_ERROR:
218-
raise NonExistingTime(dt)
219-
elif dst_rule == self.PRE_TRANSITION:
220-
# We do not apply the transition
221-
(unix_time,
222-
tzinfo_index) = self._get_previous_transition_time(tr, dt, skipped=True)
215+
if begin is end:
216+
# We only have one transition
217+
offset = self._tzinfos[tzinfo_index].offset
218+
unix_time = (dt - datetime(1970, 1, 1)).total_seconds() - offset
223219
else:
224-
unix_time = tr.unix_time - (tr.pre_time - dt).total_seconds()
220+
# tr.pre_time < dt < tr.time
221+
# Skipped time
222+
if dst_rule == self.TRANSITION_ERROR:
223+
raise NonExistingTime(dt)
224+
elif dst_rule == self.PRE_TRANSITION:
225+
# We do not apply the transition
226+
(unix_time,
227+
tzinfo_index) = self._get_previous_transition_time(tr, dt, skipped=True)
228+
else:
229+
unix_time = tr.unix_time - (tr.time - dt).total_seconds()
225230
elif tr is end:
226231
if tr.pre_time < dt:
227232
# After the last transition.

tests/tz_tests/test_timezone.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,65 @@ def test_short_timezones(self):
168168
tz = pendulum.timezone('EET')
169169
self.assertTrue(len(tz.transitions) > 0)
170170

171+
def test_short_timezones_should_not_modify_time(self):
172+
tz = pendulum.timezone('EST')
173+
dt = tz.datetime(2017, 6, 15, 14, 0, 0)
174+
175+
assert dt.year == 2017
176+
assert dt.month == 6
177+
assert dt.day == 15
178+
assert dt.hour == 14
179+
assert dt.minute == 0
180+
assert dt.second == 0
181+
182+
tz = pendulum.timezone('HST')
183+
dt = tz.datetime(2017, 6, 15, 14, 0, 0)
184+
185+
assert dt.year == 2017
186+
assert dt.month == 6
187+
assert dt.day == 15
188+
assert dt.hour == 14
189+
assert dt.minute == 0
190+
assert dt.second == 0
191+
192+
def test_after_last_transition(self):
193+
tz = pendulum.timezone('Europe/Paris')
194+
dt = tz.datetime(2135, 6, 15, 14, 0, 0)
195+
196+
assert dt.year == 2135
197+
assert dt.month == 6
198+
assert dt.day == 15
199+
assert dt.hour == 14
200+
assert dt.minute == 0
201+
assert dt.second == 0
202+
assert dt.microsecond == 0
203+
204+
def test_on_last_transition(self):
205+
tz = pendulum.timezone('Europe/Paris')
206+
dt = datetime(2037, 10, 25, 3, 0, 0)
207+
dt = tz.convert(dt, dst_rule=tz.POST_TRANSITION)
208+
209+
assert dt.year == 2037
210+
assert dt.month == 10
211+
assert dt.day == 25
212+
assert dt.hour == 3
213+
assert dt.minute == 0
214+
assert dt.second == 0
215+
assert dt.microsecond == 0
216+
assert dt.utcoffset().total_seconds() == 3600
217+
218+
dt = datetime(2037, 10, 25, 3, 0, 0)
219+
dt = tz.convert(dt, dst_rule=tz.PRE_TRANSITION)
220+
221+
assert dt.year == 2037
222+
assert dt.month == 10
223+
assert dt.day == 25
224+
assert dt.hour == 3
225+
assert dt.minute == 0
226+
assert dt.second == 0
227+
assert dt.microsecond == 0
228+
assert dt.utcoffset().total_seconds() == 7200
229+
171230
def test_convert_fold_attribute_is_honored(self):
172231
self.skip_if_not_36()
173232

0 commit comments

Comments
 (0)