@@ -98,6 +98,7 @@ except NameError: # py3
98
98
cdef inline object create_timestamp_from_ts(
99
99
int64_t value, pandas_datetimestruct dts,
100
100
object tz, object freq):
101
+ """ convenience routine to construct a Timestamp from its parts """
101
102
cdef _Timestamp ts_base
102
103
ts_base = _Timestamp.__new__ (Timestamp, dts.year, dts.month,
103
104
dts.day, dts.hour, dts.min,
@@ -112,6 +113,7 @@ cdef inline object create_timestamp_from_ts(
112
113
cdef inline object create_datetime_from_ts(
113
114
int64_t value, pandas_datetimestruct dts,
114
115
object tz, object freq):
116
+ """ convenience routine to construct a datetime.datetime from its parts """
115
117
return datetime(dts.year, dts.month, dts.day, dts.hour,
116
118
dts.min, dts.sec, dts.us, tz)
117
119
@@ -378,7 +380,6 @@ class Timestamp(_Timestamp):
378
380
# Mixing pydatetime positional and keyword arguments is forbidden!
379
381
380
382
cdef _TSObject ts
381
- cdef _Timestamp ts_base
382
383
383
384
if offset is not None :
384
385
# deprecate offset kwd in 0.19.0, GH13593
@@ -412,17 +413,7 @@ class Timestamp(_Timestamp):
412
413
from pandas.tseries.frequencies import to_offset
413
414
freq = to_offset(freq)
414
415
415
- # make datetime happy
416
- ts_base = _Timestamp.__new__ (cls , ts.dts.year, ts.dts.month,
417
- ts.dts.day, ts.dts.hour, ts.dts.min,
418
- ts.dts.sec, ts.dts.us, ts.tzinfo)
419
-
420
- # fill out rest of data
421
- ts_base.value = ts.value
422
- ts_base.freq = freq
423
- ts_base.nanosecond = ts.dts.ps / 1000
424
-
425
- return ts_base
416
+ return create_timestamp_from_ts(ts.value, ts.dts, ts.tzinfo, freq)
426
417
427
418
def _round (self , freq , rounder ):
428
419
@@ -660,8 +651,80 @@ class Timestamp(_Timestamp):
660
651
astimezone = tz_convert
661
652
662
653
def replace (self , **kwds ):
663
- return Timestamp(datetime.replace(self , ** kwds),
664
- freq = self .freq)
654
+ """
655
+ implements datetime.replace, handles nanoseconds
656
+
657
+ Parameters
658
+ ----------
659
+ kwargs: key-value dict
660
+
661
+ accepted keywords are:
662
+ year, month, day, hour, minute, second, microsecond, nanosecond, tzinfo
663
+
664
+ values must be integer, or for tzinfo, a tz-convertible
665
+
666
+ Returns
667
+ -------
668
+ Timestamp with fields replaced
669
+ """
670
+
671
+ cdef:
672
+ pandas_datetimestruct dts
673
+ int64_t value
674
+ object tzinfo, result, k, v
675
+ _TSObject ts
676
+
677
+ # set to naive if needed
678
+ tzinfo = self .tzinfo
679
+ value = self .value
680
+ if tzinfo is not None :
681
+ value = tz_convert_single(value, ' UTC' , tzinfo)
682
+
683
+ # setup components
684
+ pandas_datetime_to_datetimestruct(value, PANDAS_FR_ns, & dts)
685
+ dts.ps = self .nanosecond * 1000
686
+
687
+ # replace
688
+ def validate (k , v ):
689
+ """ validate integers """
690
+ if not isinstance (v, int ):
691
+ raise ValueError (" value must be an integer, received {v} for {k}" .format(v = type (v), k = k))
692
+ return v
693
+
694
+ for k, v in kwds.items():
695
+ if k == ' year' :
696
+ dts.year = validate(k, v)
697
+ elif k == ' month' :
698
+ dts.month = validate(k, v)
699
+ elif k == ' day' :
700
+ dts.day = validate(k, v)
701
+ elif k == ' hour' :
702
+ dts.hour = validate(k, v)
703
+ elif k == ' minute' :
704
+ dts.min = validate(k, v)
705
+ elif k == ' second' :
706
+ dts.sec = validate(k, v)
707
+ elif k == ' microsecond' :
708
+ dts.us = validate(k, v)
709
+ elif k == ' nanosecond' :
710
+ dts.ps = validate(k, v) * 1000
711
+ elif k == ' tzinfo' :
712
+ tzinfo = v
713
+ else :
714
+ raise ValueError (" invalid name {} passed" .format(k))
715
+
716
+ # reconstruct & check bounds
717
+ value = pandas_datetimestruct_to_datetime(PANDAS_FR_ns, & dts)
718
+ if value != NPY_NAT:
719
+ _check_dts_bounds(& dts)
720
+
721
+ # set tz if needed
722
+ if tzinfo is not None :
723
+ value = tz_convert_single(value, tzinfo, ' UTC' )
724
+
725
+ result = create_timestamp_from_ts(value, dts, tzinfo, self .freq)
726
+
727
+ return result
665
728
666
729
def isoformat (self , sep = ' T' ):
667
730
base = super (_Timestamp, self ).isoformat(sep = sep)
@@ -5041,7 +5104,9 @@ cpdef normalize_date(object dt):
5041
5104
-------
5042
5105
normalized : datetime.datetime or Timestamp
5043
5106
"""
5044
- if PyDateTime_Check(dt):
5107
+ if is_timestamp(dt):
5108
+ return dt.replace(hour = 0 , minute = 0 , second = 0 , microsecond = 0 , nanosecond = 0 )
5109
+ elif PyDateTime_Check(dt):
5045
5110
return dt.replace(hour = 0 , minute = 0 , second = 0 , microsecond = 0 )
5046
5111
elif PyDate_Check(dt):
5047
5112
return datetime(dt.year, dt.month, dt.day)
0 commit comments