@@ -708,7 +708,7 @@ class Timestamp(_Timestamp):
708
708
# reconstruct & check bounds
709
709
ts_input = datetime(dts.year, dts.month, dts.day, dts.hour, dts.min,
710
710
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)
712
712
value = ts.value + (dts.ps // 1000 )
713
713
if value != NPY_NAT:
714
714
_check_dts_bounds(& dts)
@@ -1455,52 +1455,11 @@ cdef convert_to_tsobject(object ts, object tz, object unit,
1455
1455
obj.value = ts
1456
1456
pandas_datetime_to_datetimestruct(ts, PANDAS_FR_ns, & obj.dts)
1457
1457
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)
1500
1459
elif PyDate_Check(ts):
1501
1460
# Keep the converter same as PyDateTime's
1502
1461
ts = datetime.combine(ts, datetime_time())
1503
- return convert_to_tsobject (ts, tz, None , 0 , 0 )
1462
+ return convert_datetime_to_tsobject (ts, tz)
1504
1463
elif getattr (ts, ' _typ' , None ) == ' period' :
1505
1464
raise ValueError (
1506
1465
" Cannot convert Period to Timestamp "
@@ -1518,6 +1477,83 @@ cdef convert_to_tsobject(object ts, object tz, object unit,
1518
1477
return obj
1519
1478
1520
1479
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
+
1521
1557
cpdef convert_str_to_tsobject(object ts, object tz, object unit,
1522
1558
dayfirst = False , yearfirst = False ):
1523
1559
""" ts must be a string """
@@ -1538,11 +1574,12 @@ cpdef convert_str_to_tsobject(object ts, object tz, object unit,
1538
1574
elif ts == ' now' :
1539
1575
# Issue 9000, we short-circuit rather than going
1540
1576
# into np_datetime_strings which returns utc
1541
- ts = Timestamp .now(tz)
1577
+ ts = datetime .now(tz)
1542
1578
elif ts == ' today' :
1543
1579
# Issue 9000, we short-circuit rather than going
1544
1580
# 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)
1546
1583
else :
1547
1584
try :
1548
1585
_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,
1557
1594
return obj
1558
1595
else :
1559
1596
# 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
+
1561
1606
else :
1562
1607
ts = obj.value
1563
1608
if tz is not None :
@@ -1706,7 +1751,7 @@ def datetime_to_datetime64(ndarray[object] values):
1706
1751
else :
1707
1752
inferred_tz = get_timezone(val.tzinfo)
1708
1753
1709
- _ts = convert_to_tsobject (val, None , None , 0 , 0 )
1754
+ _ts = convert_datetime_to_tsobject (val, None )
1710
1755
iresult[i] = _ts.value
1711
1756
_check_dts_bounds(& _ts.dts)
1712
1757
else :
@@ -2026,7 +2071,7 @@ cpdef array_to_datetime(ndarray[object] values, errors='raise',
2026
2071
seen_datetime= 1
2027
2072
if val.tzinfo is not None :
2028
2073
if utc_convert:
2029
- _ts = convert_to_tsobject (val, None , ' ns ' , 0 , 0 )
2074
+ _ts = convert_datetime_to_tsobject (val, None )
2030
2075
iresult[i] = _ts.value
2031
2076
try :
2032
2077
_check_dts_bounds(& _ts.dts)
@@ -2135,7 +2180,7 @@ cpdef array_to_datetime(ndarray[object] values, errors='raise',
2135
2180
raise TypeError (" invalid string coercion to datetime" )
2136
2181
2137
2182
try :
2138
- _ts = convert_to_tsobject (py_dt, None , None , 0 , 0 )
2183
+ _ts = convert_datetime_to_tsobject (py_dt, None )
2139
2184
iresult[i] = _ts.value
2140
2185
except ValueError :
2141
2186
if is_coerce:
0 commit comments