Skip to content

Separate out _convert_datetime_to_tsobject #17715

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

Merged
merged 7 commits into from
Oct 2, 2017
Merged
Changes from 2 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
124 changes: 73 additions & 51 deletions pandas/_libs/tslib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ class Timestamp(_Timestamp):
# reconstruct & check bounds
ts_input = datetime(dts.year, dts.month, dts.day, dts.hour, dts.min,
dts.sec, dts.us, tzinfo=_tzinfo)
ts = convert_to_tsobject(ts_input, _tzinfo, None, 0, 0)
ts = _convert_datetime_to_tsobject(ts_input, _tzinfo)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to break with spelling convention. call convert_from_datetime_to_tsobject

value = ts.value + (dts.ps // 1000)
if value != NPY_NAT:
_check_dts_bounds(&dts)
Expand Down Expand Up @@ -1475,52 +1475,11 @@ cdef convert_to_tsobject(object ts, object tz, object unit,
obj.value = ts
pandas_datetime_to_datetimestruct(ts, PANDAS_FR_ns, &obj.dts)
elif PyDateTime_Check(ts):
if tz is not None:
# sort of a temporary hack
if ts.tzinfo is not None:
if (hasattr(tz, 'normalize') and
hasattr(ts.tzinfo, '_utcoffset')):
ts = tz.normalize(ts)
obj.value = _pydatetime_to_dts(ts, &obj.dts)
obj.tzinfo = ts.tzinfo
else: #tzoffset
try:
tz = ts.astimezone(tz).tzinfo
except:
pass
obj.value = _pydatetime_to_dts(ts, &obj.dts)
ts_offset = get_utcoffset(ts.tzinfo, ts)
obj.value -= _delta_to_nanoseconds(ts_offset)
tz_offset = get_utcoffset(tz, ts)
obj.value += _delta_to_nanoseconds(tz_offset)
pandas_datetime_to_datetimestruct(obj.value,
PANDAS_FR_ns, &obj.dts)
obj.tzinfo = tz
elif not is_utc(tz):
ts = _localize_pydatetime(ts, tz)
obj.value = _pydatetime_to_dts(ts, &obj.dts)
obj.tzinfo = ts.tzinfo
else:
# UTC
obj.value = _pydatetime_to_dts(ts, &obj.dts)
obj.tzinfo = pytz.utc
else:
obj.value = _pydatetime_to_dts(ts, &obj.dts)
obj.tzinfo = ts.tzinfo

if obj.tzinfo is not None and not is_utc(obj.tzinfo):
offset = get_utcoffset(obj.tzinfo, ts)
obj.value -= _delta_to_nanoseconds(offset)

if is_timestamp(ts):
obj.value += ts.nanosecond
obj.dts.ps = ts.nanosecond * 1000
_check_dts_bounds(&obj.dts)
return obj
return _convert_datetime_to_tsobject(ts, tz)
elif PyDate_Check(ts):
# Keep the converter same as PyDateTime's
ts = datetime.combine(ts, datetime_time())
return convert_to_tsobject(ts, tz, None, 0, 0)
return _convert_datetime_to_tsobject(ts, tz)
elif getattr(ts, '_typ', None) == 'period':
raise ValueError(
"Cannot convert Period to Timestamp "
Expand All @@ -1538,12 +1497,64 @@ cdef convert_to_tsobject(object ts, object tz, object unit,
return obj


cdef _TSObject _convert_datetime_to_tsobject(datetime ts, object tz):
cdef:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls pls always add doc-strings

_TSObject obj = _TSObject()

if tz is not None:
tz = maybe_get_tz(tz)

# sort of a temporary hack
if ts.tzinfo is not None:
if (hasattr(tz, 'normalize') and
hasattr(ts.tzinfo, '_utcoffset')):
ts = tz.normalize(ts)
obj.value = _pydatetime_to_dts(ts, &obj.dts)
obj.tzinfo = ts.tzinfo
else:
# tzoffset
try:
tz = ts.astimezone(tz).tzinfo
except:
pass
obj.value = _pydatetime_to_dts(ts, &obj.dts)
ts_offset = get_utcoffset(ts.tzinfo, ts)
obj.value -= int(ts_offset.total_seconds() * 1e9)
tz_offset = get_utcoffset(tz, ts)
obj.value += int(tz_offset.total_seconds() * 1e9)
pandas_datetime_to_datetimestruct(obj.value,
PANDAS_FR_ns, &obj.dts)
obj.tzinfo = tz
elif not is_utc(tz):
ts = _localize_pydatetime(ts, tz)
obj.value = _pydatetime_to_dts(ts, &obj.dts)
obj.tzinfo = ts.tzinfo
else:
# UTC
obj.value = _pydatetime_to_dts(ts, &obj.dts)
obj.tzinfo = pytz.utc
else:
obj.value = _pydatetime_to_dts(ts, &obj.dts)
obj.tzinfo = ts.tzinfo

if obj.tzinfo is not None and not is_utc(obj.tzinfo):
offset = get_utcoffset(obj.tzinfo, ts)
obj.value -= int(offset.total_seconds() * 1e9)

if is_timestamp(ts):
obj.value += ts.nanosecond
obj.dts.ps = ts.nanosecond * 1000

_check_dts_bounds(&obj.dts)
return obj


cpdef convert_str_to_tsobject(object ts, object tz, object unit,
dayfirst=False, yearfirst=False):
""" ts must be a string """

cdef:
_TSObject obj
_TSObject obj, obj2
int out_local = 0, out_tzoffset = 0

if tz is not None:
Expand All @@ -1558,11 +1569,12 @@ cpdef convert_str_to_tsobject(object ts, object tz, object unit,
elif ts == 'now':
# Issue 9000, we short-circuit rather than going
# into np_datetime_strings which returns utc
ts = Timestamp.now(tz)
ts = datetime.now(tz)
elif ts == 'today':
# Issue 9000, we short-circuit rather than going
# into np_datetime_strings which returns a normalized datetime
ts = Timestamp.today(tz)
ts = datetime.now(tz)
# equiv: datetime.today().replace(tzinfo=tz)
else:
try:
_string_to_dts(ts, &obj.dts, &out_local, &out_tzoffset)
Expand All @@ -1577,7 +1589,17 @@ cpdef convert_str_to_tsobject(object ts, object tz, object unit,
return obj
else:
# Keep the converter same as PyDateTime's
ts = Timestamp(obj.value, tz=obj.tzinfo)
obj2 = convert_to_tsobject(obj.value, obj.tzinfo,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just a variation on create_datatime_from_ts

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't follow.

None, 0, 0)
dtime = datetime(obj2.dts.year, obj2.dts.month,
obj2.dts.day,
obj2.dts.hour, obj2.dts.min, obj2.dts.sec,
obj2.dts.us, obj2.tzinfo)
obj2 = _convert_datetime_to_tsobject(dtime, tz)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have convert_datetime_to_tsobject take an optional ps= to facilitate this type of post-conversion.

also then you don't need a obj2 avoiding more confusion here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea.

obj2.value += obj.dts.ps / 1000
obj2.dts.ps = obj.dts.ps
return obj2

else:
ts = obj.value
if tz is not None:
Expand Down Expand Up @@ -1726,7 +1748,7 @@ def datetime_to_datetime64(ndarray[object] values):
else:
inferred_tz = get_timezone(val.tzinfo)

_ts = convert_to_tsobject(val, None, None, 0, 0)
_ts = _convert_datetime_to_tsobject(val, None)
iresult[i] = _ts.value
_check_dts_bounds(&_ts.dts)
else:
Expand Down Expand Up @@ -2046,7 +2068,7 @@ cpdef array_to_datetime(ndarray[object] values, errors='raise',
seen_datetime=1
if val.tzinfo is not None:
if utc_convert:
_ts = convert_to_tsobject(val, None, 'ns', 0, 0)
_ts = _convert_datetime_to_tsobject(val, None)
iresult[i] = _ts.value
try:
_check_dts_bounds(&_ts.dts)
Expand Down Expand Up @@ -2155,7 +2177,7 @@ cpdef array_to_datetime(ndarray[object] values, errors='raise',
raise TypeError("invalid string coercion to datetime")

try:
_ts = convert_to_tsobject(py_dt, None, None, 0, 0)
_ts = _convert_datetime_to_tsobject(py_dt, None)
iresult[i] = _ts.value
except ValueError:
if is_coerce:
Expand Down