Skip to content

BUG: Bug in localizing an ambiguous timezone when a boolean is passed #14405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v0.19.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Bug Fixes




- Bug in localizing an ambiguous timezone when a boolean is passed (:issue:`14402`)



Expand Down
57 changes: 48 additions & 9 deletions pandas/tseries/tests/test_timezones.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
from pytz import NonExistentTimeError

import pandas.util.testing as tm
from pandas.util.testing import assert_frame_equal, set_timezone
from pandas.util.testing import (assert_frame_equal, assert_series_equal,
set_timezone)
from pandas.compat import lrange, zip

try:
Expand Down Expand Up @@ -535,6 +536,44 @@ def test_ambiguous_nat(self):
# right is datetime64[ns, tzfile('/usr/share/zoneinfo/US/Eastern')]
self.assert_numpy_array_equal(di_test.values, localized.values)

def test_ambiguous_bool(self):
# make sure that we are correctly accepting bool values as ambiguous

# gh-14402
t = Timestamp('2015-11-01 01:00:03')
expected0 = Timestamp('2015-11-01 01:00:03-0500', tz='US/Central')
expected1 = Timestamp('2015-11-01 01:00:03-0600', tz='US/Central')

def f():
t.tz_localize('US/Central')
self.assertRaises(pytz.AmbiguousTimeError, f)

result = t.tz_localize('US/Central', ambiguous=True)
self.assertEqual(result, expected0)

result = t.tz_localize('US/Central', ambiguous=False)
self.assertEqual(result, expected1)

s = Series([t])
expected0 = Series([expected0])
expected1 = Series([expected1])

def f():
s.dt.tz_localize('US/Central')
self.assertRaises(pytz.AmbiguousTimeError, f)

result = s.dt.tz_localize('US/Central', ambiguous=True)
assert_series_equal(result, expected0)

result = s.dt.tz_localize('US/Central', ambiguous=[True])
assert_series_equal(result, expected0)

result = s.dt.tz_localize('US/Central', ambiguous=False)
assert_series_equal(result, expected1)

result = s.dt.tz_localize('US/Central', ambiguous=[False])
assert_series_equal(result, expected1)

def test_nonexistent_raise_coerce(self):
# See issue 13057
from pytz.exceptions import NonExistentTimeError
Expand Down Expand Up @@ -629,14 +668,14 @@ def test_localized_at_time_between_time(self):
result = ts_local.at_time(time(10, 0))
expected = ts.at_time(time(10, 0)).tz_localize(self.tzstr(
'US/Eastern'))
tm.assert_series_equal(result, expected)
assert_series_equal(result, expected)
self.assertTrue(self.cmptz(result.index.tz, self.tz('US/Eastern')))

t1, t2 = time(10, 0), time(11, 0)
result = ts_local.between_time(t1, t2)
expected = ts.between_time(t1,
t2).tz_localize(self.tzstr('US/Eastern'))
tm.assert_series_equal(result, expected)
assert_series_equal(result, expected)
self.assertTrue(self.cmptz(result.index.tz, self.tz('US/Eastern')))

def test_string_index_alias_tz_aware(self):
Expand Down Expand Up @@ -723,7 +762,7 @@ def test_frame_no_datetime64_dtype(self):
result = df.get_dtype_counts().sort_index()
expected = Series({'datetime64[ns]': 2,
str(tz_expected): 2}).sort_index()
tm.assert_series_equal(result, expected)
assert_series_equal(result, expected)

def test_hongkong_tz_convert(self):
# #1673
Expand Down Expand Up @@ -1324,7 +1363,7 @@ def test_append_aware(self):
exp_index = DatetimeIndex(['2011-01-01 01:00', '2011-01-01 02:00'],
tz='US/Eastern')
exp = Series([1, 2], index=exp_index)
self.assert_series_equal(ts_result, exp)
assert_series_equal(ts_result, exp)
self.assertEqual(ts_result.index.tz, rng1.tz)

rng1 = date_range('1/1/2011 01:00', periods=1, freq='H', tz='UTC')
Expand All @@ -1336,7 +1375,7 @@ def test_append_aware(self):
exp_index = DatetimeIndex(['2011-01-01 01:00', '2011-01-01 02:00'],
tz='UTC')
exp = Series([1, 2], index=exp_index)
self.assert_series_equal(ts_result, exp)
assert_series_equal(ts_result, exp)
utc = rng1.tz
self.assertEqual(utc, ts_result.index.tz)

Expand All @@ -1352,7 +1391,7 @@ def test_append_aware(self):
exp_index = Index([Timestamp('1/1/2011 01:00', tz='US/Eastern'),
Timestamp('1/1/2011 02:00', tz='US/Central')])
exp = Series([1, 2], index=exp_index)
self.assert_series_equal(ts_result, exp)
assert_series_equal(ts_result, exp)

def test_append_dst(self):
rng1 = date_range('1/1/2016 01:00', periods=3, freq='H',
Expand All @@ -1368,7 +1407,7 @@ def test_append_dst(self):
'2016-08-01 02:00', '2016-08-01 03:00'],
tz='US/Eastern')
exp = Series([1, 2, 3, 10, 11, 12], index=exp_index)
tm.assert_series_equal(ts_result, exp)
assert_series_equal(ts_result, exp)
self.assertEqual(ts_result.index.tz, rng1.tz)

def test_append_aware_naive(self):
Expand Down Expand Up @@ -1429,7 +1468,7 @@ def test_arith_utc_convert(self):
expected = uts1 + uts2

self.assertEqual(result.index.tz, pytz.UTC)
tm.assert_series_equal(result, expected)
assert_series_equal(result, expected)

def test_intersection(self):
rng = date_range('1/1/2011', periods=100, freq='H', tz='utc')
Expand Down
10 changes: 9 additions & 1 deletion pandas/tslib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4155,6 +4155,7 @@ def tz_localize_to_utc(ndarray[int64_t] vals, object tz, object ambiguous=None,
"""
cdef:
ndarray[int64_t] trans, deltas, idx_shifted
ndarray ambiguous_array
Py_ssize_t i, idx, pos, ntrans, n = len(vals)
int64_t *tdata
int64_t v, left, right
Expand Down Expand Up @@ -4190,11 +4191,18 @@ def tz_localize_to_utc(ndarray[int64_t] vals, object tz, object ambiguous=None,
infer_dst = True
elif ambiguous == 'NaT':
fill = True
elif isinstance(ambiguous, bool):
is_dst = True
if ambiguous:
ambiguous_array = np.ones(len(vals), dtype=bool)
else:
ambiguous_array = np.zeros(len(vals), dtype=bool)
elif hasattr(ambiguous, '__iter__'):
is_dst = True
if len(ambiguous) != len(vals):
raise ValueError(
"Length of ambiguous bool-array must be the same size as vals")
ambiguous_array = np.asarray(ambiguous)

trans, deltas, typ = _get_dst_info(tz)

Expand Down Expand Up @@ -4286,7 +4294,7 @@ def tz_localize_to_utc(ndarray[int64_t] vals, object tz, object ambiguous=None,
if infer_dst and dst_hours[i] != NPY_NAT:
result[i] = dst_hours[i]
elif is_dst:
if ambiguous[i]:
if ambiguous_array[i]:
result[i] = left
else:
result[i] = right
Expand Down