@@ -708,7 +708,7 @@ class Timestamp(_Timestamp):
708708 # reconstruct & check bounds
709709 ts_input = datetime(dts.year, dts.month, dts.day, dts.hour, dts.min,
710710 dts.sec, dts.us, tzinfo = _tzinfo)
711- ts = convert_to_tsobject (ts_input, _tzinfo, None , 0 , 0 )
711+ ts = convert_datetime_to_tsobject (ts_input, _tzinfo)
712712 value = ts.value + (dts.ps // 1000 )
713713 if value != NPY_NAT:
714714 _check_dts_bounds(& dts)
@@ -1455,52 +1455,11 @@ cdef convert_to_tsobject(object ts, object tz, object unit,
14551455 obj.value = ts
14561456 pandas_datetime_to_datetimestruct(ts, PANDAS_FR_ns, & obj.dts)
14571457 elif PyDateTime_Check(ts):
1458- if tz is not None :
1459- # sort of a temporary hack
1460- if ts.tzinfo is not None :
1461- if (hasattr (tz, ' normalize' ) and
1462- hasattr (ts.tzinfo, ' _utcoffset' )):
1463- ts = tz.normalize(ts)
1464- obj.value = _pydatetime_to_dts(ts, & obj.dts)
1465- obj.tzinfo = ts.tzinfo
1466- else : # tzoffset
1467- try :
1468- tz = ts.astimezone(tz).tzinfo
1469- except :
1470- pass
1471- obj.value = _pydatetime_to_dts(ts, & obj.dts)
1472- ts_offset = get_utcoffset(ts.tzinfo, ts)
1473- obj.value -= _delta_to_nanoseconds(ts_offset)
1474- tz_offset = get_utcoffset(tz, ts)
1475- obj.value += _delta_to_nanoseconds(tz_offset)
1476- pandas_datetime_to_datetimestruct(obj.value,
1477- PANDAS_FR_ns, & obj.dts)
1478- obj.tzinfo = tz
1479- elif not is_utc(tz):
1480- ts = _localize_pydatetime(ts, tz)
1481- obj.value = _pydatetime_to_dts(ts, & obj.dts)
1482- obj.tzinfo = ts.tzinfo
1483- else :
1484- # UTC
1485- obj.value = _pydatetime_to_dts(ts, & obj.dts)
1486- obj.tzinfo = pytz.utc
1487- else :
1488- obj.value = _pydatetime_to_dts(ts, & obj.dts)
1489- obj.tzinfo = ts.tzinfo
1490-
1491- if obj.tzinfo is not None and not is_utc(obj.tzinfo):
1492- offset = get_utcoffset(obj.tzinfo, ts)
1493- obj.value -= _delta_to_nanoseconds(offset)
1494-
1495- if is_timestamp(ts):
1496- obj.value += ts.nanosecond
1497- obj.dts.ps = ts.nanosecond * 1000
1498- _check_dts_bounds(& obj.dts)
1499- return obj
1458+ return convert_datetime_to_tsobject(ts, tz)
15001459 elif PyDate_Check(ts):
15011460 # Keep the converter same as PyDateTime's
15021461 ts = datetime.combine(ts, datetime_time())
1503- return convert_to_tsobject (ts, tz, None , 0 , 0 )
1462+ return convert_datetime_to_tsobject (ts, tz)
15041463 elif getattr (ts, ' _typ' , None ) == ' period' :
15051464 raise ValueError (
15061465 " Cannot convert Period to Timestamp "
@@ -1518,6 +1477,83 @@ cdef convert_to_tsobject(object ts, object tz, object unit,
15181477 return obj
15191478
15201479
1480+ cdef _TSObject convert_datetime_to_tsobject(datetime ts, object tz,
1481+ int32_t nanos = 0 ):
1482+ """
1483+ Convert a datetime (or Timestamp) input `ts`, along with optional timezone
1484+ object `tz` to a _TSObject.
1485+
1486+ The optional argument `nanos` allows for cases where datetime input
1487+ needs to be supplemented with higher-precision information.
1488+
1489+ Parameters
1490+ ----------
1491+ ts : datetime or Timestamp
1492+ Value to be converted to _TSObject
1493+ tz : tzinfo or None
1494+ timezone for the timezone-aware output
1495+ nanos : int32_t, default is 0
1496+ nanoseconds supplement the precision of the datetime input ts
1497+
1498+ Returns
1499+ -------
1500+ obj : _TSObject
1501+ """
1502+ cdef:
1503+ _TSObject obj = _TSObject()
1504+
1505+ if tz is not None :
1506+ tz = maybe_get_tz(tz)
1507+
1508+ # sort of a temporary hack
1509+ if ts.tzinfo is not None :
1510+ if (hasattr (tz, ' normalize' ) and
1511+ hasattr (ts.tzinfo, ' _utcoffset' )):
1512+ ts = tz.normalize(ts)
1513+ obj.value = _pydatetime_to_dts(ts, & obj.dts)
1514+ obj.tzinfo = ts.tzinfo
1515+ else :
1516+ # tzoffset
1517+ try :
1518+ tz = ts.astimezone(tz).tzinfo
1519+ except :
1520+ pass
1521+ obj.value = _pydatetime_to_dts(ts, & obj.dts)
1522+ ts_offset = get_utcoffset(ts.tzinfo, ts)
1523+ obj.value -= int (ts_offset.total_seconds() * 1e9 )
1524+ tz_offset = get_utcoffset(tz, ts)
1525+ obj.value += int (tz_offset.total_seconds() * 1e9 )
1526+ pandas_datetime_to_datetimestruct(obj.value,
1527+ PANDAS_FR_ns, & obj.dts)
1528+ obj.tzinfo = tz
1529+ elif not is_utc(tz):
1530+ ts = _localize_pydatetime(ts, tz)
1531+ obj.value = _pydatetime_to_dts(ts, & obj.dts)
1532+ obj.tzinfo = ts.tzinfo
1533+ else :
1534+ # UTC
1535+ obj.value = _pydatetime_to_dts(ts, & obj.dts)
1536+ obj.tzinfo = pytz.utc
1537+ else :
1538+ obj.value = _pydatetime_to_dts(ts, & obj.dts)
1539+ obj.tzinfo = ts.tzinfo
1540+
1541+ if obj.tzinfo is not None and not is_utc(obj.tzinfo):
1542+ offset = get_utcoffset(obj.tzinfo, ts)
1543+ obj.value -= int (offset.total_seconds() * 1e9 )
1544+
1545+ if is_timestamp(ts):
1546+ obj.value += ts.nanosecond
1547+ obj.dts.ps = ts.nanosecond * 1000
1548+
1549+ if nanos:
1550+ obj.value += nanos
1551+ obj.dts.ps = nanos * 1000
1552+
1553+ _check_dts_bounds(& obj.dts)
1554+ return obj
1555+
1556+
15211557cpdef convert_str_to_tsobject(object ts, object tz, object unit,
15221558 dayfirst = False , yearfirst = False ):
15231559 """ ts must be a string """
@@ -1538,11 +1574,12 @@ cpdef convert_str_to_tsobject(object ts, object tz, object unit,
15381574 elif ts == ' now' :
15391575 # Issue 9000, we short-circuit rather than going
15401576 # into np_datetime_strings which returns utc
1541- ts = Timestamp .now(tz)
1577+ ts = datetime .now(tz)
15421578 elif ts == ' today' :
15431579 # Issue 9000, we short-circuit rather than going
15441580 # into np_datetime_strings which returns a normalized datetime
1545- ts = Timestamp.today(tz)
1581+ ts = datetime.now(tz)
1582+ # equiv: datetime.today().replace(tzinfo=tz)
15461583 else :
15471584 try :
15481585 _string_to_dts(ts, & obj.dts, & out_local, & out_tzoffset)
@@ -1557,7 +1594,15 @@ cpdef convert_str_to_tsobject(object ts, object tz, object unit,
15571594 return obj
15581595 else :
15591596 # Keep the converter same as PyDateTime's
1560- ts = Timestamp(obj.value, tz = obj.tzinfo)
1597+ obj = convert_to_tsobject(obj.value, obj.tzinfo,
1598+ None , 0 , 0 )
1599+ dtime = datetime(obj.dts.year, obj.dts.month, obj.dts.day,
1600+ obj.dts.hour, obj.dts.min, obj.dts.sec,
1601+ obj.dts.us, obj.tzinfo)
1602+ obj = convert_datetime_to_tsobject(dtime, tz,
1603+ nanos = obj.dts.ps / 1000 )
1604+ return obj
1605+
15611606 else :
15621607 ts = obj.value
15631608 if tz is not None :
@@ -1706,7 +1751,7 @@ def datetime_to_datetime64(ndarray[object] values):
17061751 else :
17071752 inferred_tz = get_timezone(val.tzinfo)
17081753
1709- _ts = convert_to_tsobject (val, None , None , 0 , 0 )
1754+ _ts = convert_datetime_to_tsobject (val, None )
17101755 iresult[i] = _ts.value
17111756 _check_dts_bounds(& _ts.dts)
17121757 else :
@@ -2026,7 +2071,7 @@ cpdef array_to_datetime(ndarray[object] values, errors='raise',
20262071 seen_datetime= 1
20272072 if val.tzinfo is not None :
20282073 if utc_convert:
2029- _ts = convert_to_tsobject (val, None , ' ns ' , 0 , 0 )
2074+ _ts = convert_datetime_to_tsobject (val, None )
20302075 iresult[i] = _ts.value
20312076 try :
20322077 _check_dts_bounds(& _ts.dts)
@@ -2135,7 +2180,7 @@ cpdef array_to_datetime(ndarray[object] values, errors='raise',
21352180 raise TypeError (" invalid string coercion to datetime" )
21362181
21372182 try :
2138- _ts = convert_to_tsobject (py_dt, None , None , 0 , 0 )
2183+ _ts = convert_datetime_to_tsobject (py_dt, None )
21392184 iresult[i] = _ts.value
21402185 except ValueError :
21412186 if is_coerce:
0 commit comments