Skip to content

Commit d12ae36

Browse files
committed
ENH: convert all datetime-like objects to Timestamp
1 parent ea7be22 commit d12ae36

File tree

4 files changed

+33
-37
lines changed

4 files changed

+33
-37
lines changed

pandas/computation/expr.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,6 @@ def f(cls):
379379
return f
380380

381381

382-
_date_kinds = frozenset(['datetime64', 'timestamp', 'datetime'])
383-
384382
@disallow(_unsupported_nodes)
385383
@add_ops(_op_classes)
386384
class BaseExprVisitor(ast.NodeVisitor):
@@ -496,7 +494,7 @@ def _possibly_evaluate_binop(self, op, op_class, lhs, rhs,
496494
res = op(lhs, rhs)
497495

498496
if (res.op in _cmp_ops_syms and
499-
lhs.kind in _date_kinds or rhs.kind in _date_kinds and
497+
lhs.is_datetime or rhs.is_datetime and
500498
self.engine != 'pytables'):
501499
# all date ops must be done in python bc numexpr doesn't work well
502500
# with NaT

pandas/computation/ops.py

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import operator as op
66
from functools import partial
77
from itertools import product, islice, chain
8+
from datetime import datetime
89

910
import numpy as np
1011

@@ -161,21 +162,16 @@ def raw(self):
161162
self.type))
162163

163164
@property
164-
def kind(self):
165-
t = self.type
165+
def is_datetime(self):
166166
try:
167-
res = t.__name__
167+
t = self.type.type
168168
except AttributeError:
169-
res = t.type.__name__
170-
return res.lower()
169+
t = self.type
170+
171+
return issubclass(t, (datetime, np.datetime64))
171172

172173
@property
173174
def value(self):
174-
kind = self.kind
175-
if kind == 'timestamp':
176-
return self._value.asm8
177-
elif kind == 'datetime':
178-
return np.datetime64(self._value)
179175
return self._value
180176

181177
@value.setter
@@ -246,14 +242,13 @@ def isscalar(self):
246242
return all(operand.isscalar for operand in self.operands)
247243

248244
@property
249-
def kind(self):
250-
t = self.return_type
251-
245+
def is_datetime(self):
252246
try:
253-
res = t.__name__
247+
t = self.return_type.type
254248
except AttributeError:
255-
res = t.type.__name__
256-
return res.lower()
249+
t = self.return_type
250+
251+
return issubclass(t, (datetime, np.datetime64))
257252

258253

259254
def _in(x, y):
@@ -431,24 +426,20 @@ def stringify(value):
431426

432427
lhs, rhs = self.lhs, self.rhs
433428

434-
if (is_term(lhs) and lhs.kind.startswith('datetime') and is_term(rhs)
435-
and rhs.isscalar):
429+
if is_term(lhs) and lhs.is_datetime and is_term(rhs) and rhs.isscalar:
436430
v = rhs.value
437431
if isinstance(v, (int, float)):
438432
v = stringify(v)
439-
v = _ensure_decoded(v)
440-
v = pd.Timestamp(v)
433+
v = pd.Timestamp(_ensure_decoded(v))
441434
if v.tz is not None:
442435
v = v.tz_convert('UTC')
443436
self.rhs.update(v)
444437

445-
if (is_term(rhs) and rhs.kind.startswith('datetime') and
446-
is_term(lhs) and lhs.isscalar):
438+
if is_term(rhs) and rhs.is_datetime and is_term(lhs) and lhs.isscalar:
447439
v = lhs.value
448440
if isinstance(v, (int, float)):
449441
v = stringify(v)
450-
v = _ensure_decoded(v)
451-
v = pd.Timestamp(v)
442+
v = pd.Timestamp(_ensure_decoded(v))
452443
if v.tz is not None:
453444
v = v.tz_convert('UTC')
454445
self.lhs.update(v)

pandas/core/frame.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1910,8 +1910,10 @@ def _get_index_resolvers(self, axis):
19101910
key = '{prefix}level_{i}'.format(prefix=prefix, i=i)
19111911
level = i
19121912

1913-
d[key] = Series(axis_index.get_level_values(level).values,
1914-
index=axis_index, name=level)
1913+
level_values = axis_index.get_level_values(level)
1914+
s = level_values.to_series()
1915+
s.index = axis_index
1916+
d[key] = s
19151917

19161918
# put the index/columns itself in the dict
19171919
if isinstance(axis_index, MultiIndex):

pandas/tests/test_frame.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11432,23 +11432,28 @@ def check_query_multiindex_get_index_resolvers(self, parser, engine):
1143211432
resolvers = df._get_index_resolvers('index')
1143311433
resolvers.update(df._get_index_resolvers('columns'))
1143411434

11435+
def to_series(mi, level):
11436+
level_values = mi.get_level_values(level)
11437+
s = level_values.to_series()
11438+
s.index = mi
11439+
return s
11440+
11441+
col_series = df.columns.to_series()
1143511442
expected = {'index': df.index,
11436-
'columns': Series(df.columns, index=df.columns,
11437-
name=df.columns.name),
11438-
'spam': Series(df.index.get_level_values('spam'),
11439-
name='spam', index=df.index),
11440-
'eggs': Series(df.index.get_level_values('eggs'),
11441-
name='eggs', index=df.index),
11442-
'C0': Series(df.columns, index=df.columns,
11443-
name=df.columns.name)}
11443+
'columns': col_series,
11444+
'spam': to_series(df.index, 'spam'),
11445+
'eggs': to_series(df.index, 'eggs'),
11446+
'C0': col_series}
1144411447
for k, v in resolvers.items():
1144511448
if isinstance(v, Index):
1144611449
assert v.is_(expected[k])
1144711450
elif isinstance(v, Series):
11451+
print(k)
1144811452
tm.assert_series_equal(v, expected[k])
1144911453
else:
1145011454
raise AssertionError("object must be a Series or Index")
1145111455

11456+
1145211457
class TestDataFrameQueryNumExprPandas(unittest.TestCase):
1145311458
@classmethod
1145411459
def setUpClass(cls):

0 commit comments

Comments
 (0)