Skip to content

Commit d8cd33b

Browse files
conquistador1492jreback
authored andcommitted
BUG: fix tz-aware datetime convert to DatetimeIndex (GH 14088)
closes pandas-dev#14088 Author: John Liekezer <[email protected]> Closes pandas-dev#14090 from conquistador1492/issue_14088 and squashes the following commits: c91425b [John Liekezer] BUG: fix tz-aware datetime convert to DatetimeIndex (GH 14088)
1 parent ff435ba commit d8cd33b

File tree

3 files changed

+94
-82
lines changed

3 files changed

+94
-82
lines changed

doc/source/whatsnew/v0.19.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1549,6 +1549,7 @@ Bug Fixes
15491549
- Bug where ``pd.read_gbq()`` could throw ``ImportError: No module named discovery`` as a result of a naming conflict with another python package called apiclient (:issue:`13454`)
15501550
- Bug in ``Index.union`` returns an incorrect result with a named empty index (:issue:`13432`)
15511551
- Bugs in ``Index.difference`` and ``DataFrame.join`` raise in Python3 when using mixed-integer indexes (:issue:`13432`, :issue:`12814`)
1552+
- Bug in subtract tz-aware ``datetime.datetime`` from tz-aware ``datetime64`` series (:issue:`14088`)
15521553
- Bug in ``.to_excel()`` when DataFrame contains a MultiIndex which contains a label with a NaN value (:issue:`13511`)
15531554
- Bug in invalid frequency offset string like "D1", "-2-3H" may not raise ``ValueError (:issue:`13930`)
15541555
- Bug in ``concat`` and ``groupby`` for hierarchical frames with ``RangeIndex`` levels (:issue:`13542`).

pandas/core/ops.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ def _convert_to_array(self, values, name=None, other=None):
453453
values = values.to_series()
454454
# datetime with tz
455455
elif (isinstance(ovalues, datetime.datetime) and
456-
hasattr(ovalues, 'tz')):
456+
hasattr(ovalues, 'tzinfo')):
457457
values = pd.DatetimeIndex(values)
458458
# datetime array with tz
459459
elif is_datetimetz(values):

pandas/tests/series/test_operators.py

+92-81
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818

1919
from pandas.compat import range, zip
2020
from pandas import compat
21-
from pandas.util.testing import assert_series_equal, assert_almost_equal
21+
from pandas.util.testing import (assert_series_equal, assert_almost_equal,
22+
assert_frame_equal)
2223
import pandas.util.testing as tm
2324

2425
from .common import TestData
@@ -45,8 +46,8 @@ def test_comparisons(self):
4546

4647
# it works!
4748
exp = Series([False, False, False])
48-
tm.assert_series_equal(s == s2, exp)
49-
tm.assert_series_equal(s2 == s, exp)
49+
assert_series_equal(s == s2, exp)
50+
assert_series_equal(s2 == s, exp)
5051

5152
def test_op_method(self):
5253
def check(series, other, check_reverse=False):
@@ -64,12 +65,12 @@ def check(series, other, check_reverse=False):
6465

6566
result = op(series, other)
6667
expected = alt(series, other)
67-
tm.assert_almost_equal(result, expected)
68+
assert_almost_equal(result, expected)
6869
if check_reverse:
6970
rop = getattr(Series, "r" + opname)
7071
result = rop(series, other)
7172
expected = alt(other, series)
72-
tm.assert_almost_equal(result, expected)
73+
assert_almost_equal(result, expected)
7374

7475
check(self.ts, self.ts * 2)
7576
check(self.ts, self.ts[::2])
@@ -149,8 +150,8 @@ def _check_op(series, other, op, pos_only=False,
149150

150151
cython_or_numpy = op(left, right)
151152
python = left.combine(right, op)
152-
tm.assert_series_equal(cython_or_numpy, python,
153-
check_dtype=check_dtype)
153+
assert_series_equal(cython_or_numpy, python,
154+
check_dtype=check_dtype)
154155

155156
def check(series, other):
156157
simple_ops = ['add', 'sub', 'mul', 'truediv', 'floordiv', 'mod']
@@ -187,7 +188,7 @@ def check_comparators(series, other, check_dtype=True):
187188
def test_operators_empty_int_corner(self):
188189
s1 = Series([], [], dtype=np.int32)
189190
s2 = Series({'x': 0.})
190-
tm.assert_series_equal(s1 * s2, Series([np.nan], index=['x']))
191+
assert_series_equal(s1 * s2, Series([np.nan], index=['x']))
191192

192193
def test_operators_timedelta64(self):
193194

@@ -668,6 +669,16 @@ def run_ops(ops, get_ser, test_ser):
668669
self.assertRaises(TypeError, lambda: td1 - dt1)
669670
self.assertRaises(TypeError, lambda: td2 - dt2)
670671

672+
def test_sub_datetime_compat(self):
673+
# GH 14088
674+
tm._skip_if_no_pytz()
675+
import pytz
676+
s = Series([datetime(2016, 8, 23, 12, tzinfo=pytz.utc), pd.NaT])
677+
dt = datetime(2016, 8, 22, 12, tzinfo=pytz.utc)
678+
exp = Series([Timedelta('1 days'), pd.NaT])
679+
assert_series_equal(s - dt, exp)
680+
assert_series_equal(s - Timestamp(dt), exp)
681+
671682
def test_sub_single_tz(self):
672683
# GH12290
673684
s1 = Series([pd.Timestamp('2016-02-10', tz='America/Sao_Paulo')])
@@ -1175,21 +1186,21 @@ def test_comparison_flex_basic(self):
11751186
left = pd.Series(np.random.randn(10))
11761187
right = pd.Series(np.random.randn(10))
11771188

1178-
tm.assert_series_equal(left.eq(right), left == right)
1179-
tm.assert_series_equal(left.ne(right), left != right)
1180-
tm.assert_series_equal(left.le(right), left < right)
1181-
tm.assert_series_equal(left.lt(right), left <= right)
1182-
tm.assert_series_equal(left.gt(right), left > right)
1183-
tm.assert_series_equal(left.ge(right), left >= right)
1189+
assert_series_equal(left.eq(right), left == right)
1190+
assert_series_equal(left.ne(right), left != right)
1191+
assert_series_equal(left.le(right), left < right)
1192+
assert_series_equal(left.lt(right), left <= right)
1193+
assert_series_equal(left.gt(right), left > right)
1194+
assert_series_equal(left.ge(right), left >= right)
11841195

11851196
# axis
11861197
for axis in [0, None, 'index']:
1187-
tm.assert_series_equal(left.eq(right, axis=axis), left == right)
1188-
tm.assert_series_equal(left.ne(right, axis=axis), left != right)
1189-
tm.assert_series_equal(left.le(right, axis=axis), left < right)
1190-
tm.assert_series_equal(left.lt(right, axis=axis), left <= right)
1191-
tm.assert_series_equal(left.gt(right, axis=axis), left > right)
1192-
tm.assert_series_equal(left.ge(right, axis=axis), left >= right)
1198+
assert_series_equal(left.eq(right, axis=axis), left == right)
1199+
assert_series_equal(left.ne(right, axis=axis), left != right)
1200+
assert_series_equal(left.le(right, axis=axis), left < right)
1201+
assert_series_equal(left.lt(right, axis=axis), left <= right)
1202+
assert_series_equal(left.gt(right, axis=axis), left > right)
1203+
assert_series_equal(left.ge(right, axis=axis), left >= right)
11931204

11941205
#
11951206
msg = 'No axis named 1 for object type'
@@ -1202,44 +1213,44 @@ def test_comparison_flex_alignment(self):
12021213
right = Series([2, 2, 2], index=list('bcd'))
12031214

12041215
exp = pd.Series([False, False, True, False], index=list('abcd'))
1205-
tm.assert_series_equal(left.eq(right), exp)
1216+
assert_series_equal(left.eq(right), exp)
12061217

12071218
exp = pd.Series([True, True, False, True], index=list('abcd'))
1208-
tm.assert_series_equal(left.ne(right), exp)
1219+
assert_series_equal(left.ne(right), exp)
12091220

12101221
exp = pd.Series([False, False, True, False], index=list('abcd'))
1211-
tm.assert_series_equal(left.le(right), exp)
1222+
assert_series_equal(left.le(right), exp)
12121223

12131224
exp = pd.Series([False, False, False, False], index=list('abcd'))
1214-
tm.assert_series_equal(left.lt(right), exp)
1225+
assert_series_equal(left.lt(right), exp)
12151226

12161227
exp = pd.Series([False, True, True, False], index=list('abcd'))
1217-
tm.assert_series_equal(left.ge(right), exp)
1228+
assert_series_equal(left.ge(right), exp)
12181229

12191230
exp = pd.Series([False, True, False, False], index=list('abcd'))
1220-
tm.assert_series_equal(left.gt(right), exp)
1231+
assert_series_equal(left.gt(right), exp)
12211232

12221233
def test_comparison_flex_alignment_fill(self):
12231234
left = Series([1, 3, 2], index=list('abc'))
12241235
right = Series([2, 2, 2], index=list('bcd'))
12251236

12261237
exp = pd.Series([False, False, True, True], index=list('abcd'))
1227-
tm.assert_series_equal(left.eq(right, fill_value=2), exp)
1238+
assert_series_equal(left.eq(right, fill_value=2), exp)
12281239

12291240
exp = pd.Series([True, True, False, False], index=list('abcd'))
1230-
tm.assert_series_equal(left.ne(right, fill_value=2), exp)
1241+
assert_series_equal(left.ne(right, fill_value=2), exp)
12311242

12321243
exp = pd.Series([False, False, True, True], index=list('abcd'))
1233-
tm.assert_series_equal(left.le(right, fill_value=0), exp)
1244+
assert_series_equal(left.le(right, fill_value=0), exp)
12341245

12351246
exp = pd.Series([False, False, False, True], index=list('abcd'))
1236-
tm.assert_series_equal(left.lt(right, fill_value=0), exp)
1247+
assert_series_equal(left.lt(right, fill_value=0), exp)
12371248

12381249
exp = pd.Series([True, True, True, False], index=list('abcd'))
1239-
tm.assert_series_equal(left.ge(right, fill_value=0), exp)
1250+
assert_series_equal(left.ge(right, fill_value=0), exp)
12401251

12411252
exp = pd.Series([True, True, False, False], index=list('abcd'))
1242-
tm.assert_series_equal(left.gt(right, fill_value=0), exp)
1253+
assert_series_equal(left.gt(right, fill_value=0), exp)
12431254

12441255
def test_operators_bitwise(self):
12451256
# GH 9016: support bitwise op for integer types
@@ -1426,27 +1437,27 @@ def test_arith_ops_df_compat(self):
14261437

14271438
exp = pd.Series([3.0, 4.0, np.nan, np.nan],
14281439
index=list('ABCD'), name='x')
1429-
tm.assert_series_equal(s1 + s2, exp)
1430-
tm.assert_series_equal(s2 + s1, exp)
1440+
assert_series_equal(s1 + s2, exp)
1441+
assert_series_equal(s2 + s1, exp)
14311442

14321443
exp = pd.DataFrame({'x': [3.0, 4.0, np.nan, np.nan]},
14331444
index=list('ABCD'))
1434-
tm.assert_frame_equal(s1.to_frame() + s2.to_frame(), exp)
1435-
tm.assert_frame_equal(s2.to_frame() + s1.to_frame(), exp)
1445+
assert_frame_equal(s1.to_frame() + s2.to_frame(), exp)
1446+
assert_frame_equal(s2.to_frame() + s1.to_frame(), exp)
14361447

14371448
# different length
14381449
s3 = pd.Series([1, 2, 3], index=list('ABC'), name='x')
14391450
s4 = pd.Series([2, 2, 2, 2], index=list('ABCD'), name='x')
14401451

14411452
exp = pd.Series([3, 4, 5, np.nan],
14421453
index=list('ABCD'), name='x')
1443-
tm.assert_series_equal(s3 + s4, exp)
1444-
tm.assert_series_equal(s4 + s3, exp)
1454+
assert_series_equal(s3 + s4, exp)
1455+
assert_series_equal(s4 + s3, exp)
14451456

14461457
exp = pd.DataFrame({'x': [3, 4, 5, np.nan]},
14471458
index=list('ABCD'))
1448-
tm.assert_frame_equal(s3.to_frame() + s4.to_frame(), exp)
1449-
tm.assert_frame_equal(s4.to_frame() + s3.to_frame(), exp)
1459+
assert_frame_equal(s3.to_frame() + s4.to_frame(), exp)
1460+
assert_frame_equal(s4.to_frame() + s3.to_frame(), exp)
14501461

14511462
def test_comp_ops_df_compat(self):
14521463
# GH 1134
@@ -1485,56 +1496,56 @@ def test_bool_ops_df_compat(self):
14851496

14861497
exp = pd.Series([True, False, False, False],
14871498
index=list('ABCD'), name='x')
1488-
tm.assert_series_equal(s1 & s2, exp)
1489-
tm.assert_series_equal(s2 & s1, exp)
1499+
assert_series_equal(s1 & s2, exp)
1500+
assert_series_equal(s2 & s1, exp)
14901501

14911502
# True | np.nan => True
14921503
exp = pd.Series([True, True, True, False],
14931504
index=list('ABCD'), name='x')
1494-
tm.assert_series_equal(s1 | s2, exp)
1505+
assert_series_equal(s1 | s2, exp)
14951506
# np.nan | True => np.nan, filled with False
14961507
exp = pd.Series([True, True, False, False],
14971508
index=list('ABCD'), name='x')
1498-
tm.assert_series_equal(s2 | s1, exp)
1509+
assert_series_equal(s2 | s1, exp)
14991510

15001511
# DataFrame doesn't fill nan with False
15011512
exp = pd.DataFrame({'x': [True, False, np.nan, np.nan]},
15021513
index=list('ABCD'))
1503-
tm.assert_frame_equal(s1.to_frame() & s2.to_frame(), exp)
1504-
tm.assert_frame_equal(s2.to_frame() & s1.to_frame(), exp)
1514+
assert_frame_equal(s1.to_frame() & s2.to_frame(), exp)
1515+
assert_frame_equal(s2.to_frame() & s1.to_frame(), exp)
15051516

15061517
exp = pd.DataFrame({'x': [True, True, np.nan, np.nan]},
15071518
index=list('ABCD'))
1508-
tm.assert_frame_equal(s1.to_frame() | s2.to_frame(), exp)
1509-
tm.assert_frame_equal(s2.to_frame() | s1.to_frame(), exp)
1519+
assert_frame_equal(s1.to_frame() | s2.to_frame(), exp)
1520+
assert_frame_equal(s2.to_frame() | s1.to_frame(), exp)
15101521

15111522
# different length
15121523
s3 = pd.Series([True, False, True], index=list('ABC'), name='x')
15131524
s4 = pd.Series([True, True, True, True], index=list('ABCD'), name='x')
15141525

15151526
exp = pd.Series([True, False, True, False],
15161527
index=list('ABCD'), name='x')
1517-
tm.assert_series_equal(s3 & s4, exp)
1518-
tm.assert_series_equal(s4 & s3, exp)
1528+
assert_series_equal(s3 & s4, exp)
1529+
assert_series_equal(s4 & s3, exp)
15191530

15201531
# np.nan | True => np.nan, filled with False
15211532
exp = pd.Series([True, True, True, False],
15221533
index=list('ABCD'), name='x')
1523-
tm.assert_series_equal(s3 | s4, exp)
1534+
assert_series_equal(s3 | s4, exp)
15241535
# True | np.nan => True
15251536
exp = pd.Series([True, True, True, True],
15261537
index=list('ABCD'), name='x')
1527-
tm.assert_series_equal(s4 | s3, exp)
1538+
assert_series_equal(s4 | s3, exp)
15281539

15291540
exp = pd.DataFrame({'x': [True, False, True, np.nan]},
15301541
index=list('ABCD'))
1531-
tm.assert_frame_equal(s3.to_frame() & s4.to_frame(), exp)
1532-
tm.assert_frame_equal(s4.to_frame() & s3.to_frame(), exp)
1542+
assert_frame_equal(s3.to_frame() & s4.to_frame(), exp)
1543+
assert_frame_equal(s4.to_frame() & s3.to_frame(), exp)
15331544

15341545
exp = pd.DataFrame({'x': [True, True, True, np.nan]},
15351546
index=list('ABCD'))
1536-
tm.assert_frame_equal(s3.to_frame() | s4.to_frame(), exp)
1537-
tm.assert_frame_equal(s4.to_frame() | s3.to_frame(), exp)
1547+
assert_frame_equal(s3.to_frame() | s4.to_frame(), exp)
1548+
assert_frame_equal(s4.to_frame() | s3.to_frame(), exp)
15381549

15391550
def test_series_frame_radd_bug(self):
15401551
# GH 353
@@ -1546,7 +1557,7 @@ def test_series_frame_radd_bug(self):
15461557
frame = DataFrame({'vals': vals})
15471558
result = 'foo_' + frame
15481559
expected = DataFrame({'vals': vals.map(lambda x: 'foo_' + x)})
1549-
tm.assert_frame_equal(result, expected)
1560+
assert_frame_equal(result, expected)
15501561

15511562
# really raise this time
15521563
with tm.assertRaises(TypeError):
@@ -1571,26 +1582,26 @@ def test_series_radd_more(self):
15711582
for dtype in [None, object]:
15721583
res = 1 + pd.Series([1, 2, 3], dtype=dtype)
15731584
exp = pd.Series([2, 3, 4], dtype=dtype)
1574-
tm.assert_series_equal(res, exp)
1585+
assert_series_equal(res, exp)
15751586
res = pd.Series([1, 2, 3], dtype=dtype) + 1
1576-
tm.assert_series_equal(res, exp)
1587+
assert_series_equal(res, exp)
15771588

15781589
res = np.nan + pd.Series([1, 2, 3], dtype=dtype)
15791590
exp = pd.Series([np.nan, np.nan, np.nan], dtype=dtype)
1580-
tm.assert_series_equal(res, exp)
1591+
assert_series_equal(res, exp)
15811592
res = pd.Series([1, 2, 3], dtype=dtype) + np.nan
1582-
tm.assert_series_equal(res, exp)
1593+
assert_series_equal(res, exp)
15831594

15841595
s = pd.Series([pd.Timedelta('1 days'), pd.Timedelta('2 days'),
15851596
pd.Timedelta('3 days')], dtype=dtype)
15861597
exp = pd.Series([pd.Timedelta('4 days'), pd.Timedelta('5 days'),
15871598
pd.Timedelta('6 days')])
1588-
tm.assert_series_equal(pd.Timedelta('3 days') + s, exp)
1589-
tm.assert_series_equal(s + pd.Timedelta('3 days'), exp)
1599+
assert_series_equal(pd.Timedelta('3 days') + s, exp)
1600+
assert_series_equal(s + pd.Timedelta('3 days'), exp)
15901601

15911602
s = pd.Series(['x', np.nan, 'x'])
1592-
tm.assert_series_equal('a' + s, pd.Series(['ax', np.nan, 'ax']))
1593-
tm.assert_series_equal(s + 'a', pd.Series(['xa', np.nan, 'xa']))
1603+
assert_series_equal('a' + s, pd.Series(['ax', np.nan, 'ax']))
1604+
assert_series_equal(s + 'a', pd.Series(['xa', np.nan, 'xa']))
15941605

15951606
def test_frame_radd_more(self):
15961607
data = [[1, 2, 3],
@@ -1608,32 +1619,32 @@ def test_frame_radd_more(self):
16081619
for dtype in [None, object]:
16091620
res = 1 + pd.DataFrame([1, 2, 3], dtype=dtype)
16101621
exp = pd.DataFrame([2, 3, 4], dtype=dtype)
1611-
tm.assert_frame_equal(res, exp)
1622+
assert_frame_equal(res, exp)
16121623
res = pd.DataFrame([1, 2, 3], dtype=dtype) + 1
1613-
tm.assert_frame_equal(res, exp)
1624+
assert_frame_equal(res, exp)
16141625

16151626
res = np.nan + pd.DataFrame([1, 2, 3], dtype=dtype)
16161627
exp = pd.DataFrame([np.nan, np.nan, np.nan], dtype=dtype)
1617-
tm.assert_frame_equal(res, exp)
1628+
assert_frame_equal(res, exp)
16181629
res = pd.DataFrame([1, 2, 3], dtype=dtype) + np.nan
1619-
tm.assert_frame_equal(res, exp)
1630+
assert_frame_equal(res, exp)
16201631

16211632
df = pd.DataFrame(['x', np.nan, 'x'])
1622-
tm.assert_frame_equal('a' + df, pd.DataFrame(['ax', np.nan, 'ax']))
1623-
tm.assert_frame_equal(df + 'a', pd.DataFrame(['xa', np.nan, 'xa']))
1633+
assert_frame_equal('a' + df, pd.DataFrame(['ax', np.nan, 'ax']))
1634+
assert_frame_equal(df + 'a', pd.DataFrame(['xa', np.nan, 'xa']))
16241635

16251636
def test_operators_frame(self):
16261637
# rpow does not work with DataFrame
16271638
df = DataFrame({'A': self.ts})
16281639

1629-
tm.assert_series_equal(self.ts + self.ts, self.ts + df['A'],
1630-
check_names=False)
1631-
tm.assert_series_equal(self.ts ** self.ts, self.ts ** df['A'],
1632-
check_names=False)
1633-
tm.assert_series_equal(self.ts < self.ts, self.ts < df['A'],
1634-
check_names=False)
1635-
tm.assert_series_equal(self.ts / self.ts, self.ts / df['A'],
1636-
check_names=False)
1640+
assert_series_equal(self.ts + self.ts, self.ts + df['A'],
1641+
check_names=False)
1642+
assert_series_equal(self.ts ** self.ts, self.ts ** df['A'],
1643+
check_names=False)
1644+
assert_series_equal(self.ts < self.ts, self.ts < df['A'],
1645+
check_names=False)
1646+
assert_series_equal(self.ts / self.ts, self.ts / df['A'],
1647+
check_names=False)
16371648

16381649
def test_operators_combine(self):
16391650
def _check_fill(meth, op, a, b, fill_value=0):
@@ -1729,12 +1740,12 @@ def test_divide_decimal(self):
17291740
s = Series([Decimal(10)])
17301741
s = s / Decimal(2)
17311742

1732-
tm.assert_series_equal(expected, s)
1743+
assert_series_equal(expected, s)
17331744

17341745
s = Series([Decimal(10)])
17351746
s = s // Decimal(2)
17361747

1737-
tm.assert_series_equal(expected, s)
1748+
assert_series_equal(expected, s)
17381749

17391750
def test_datetime64_with_index(self):
17401751

0 commit comments

Comments
 (0)