From 6aeb19a22eec3b525c35eaca7528b960a754bc8a Mon Sep 17 00:00:00 2001 From: Maria Ivanova Date: Mon, 2 Sep 2024 17:27:45 +0000 Subject: [PATCH 1/4] add year and nanosecond --- ci/code_checks.sh | 2 -- pandas/_libs/tslibs/timestamps.pyx | 50 ++++++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/ci/code_checks.sh b/ci/code_checks.sh index 41418e75b171d..823606e2ac09f 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -128,11 +128,9 @@ if [[ -z "$CHECK" || "$CHECK" == "docstrings" ]]; then -i "pandas.TimedeltaIndex.to_pytimedelta RT03,SA01" \ -i "pandas.Timestamp.max PR02" \ -i "pandas.Timestamp.min PR02" \ - -i "pandas.Timestamp.nanosecond GL08" \ -i "pandas.Timestamp.resolution PR02" \ -i "pandas.Timestamp.tzinfo GL08" \ -i "pandas.Timestamp.value GL08" \ - -i "pandas.Timestamp.year GL08" \ -i "pandas.api.extensions.ExtensionArray.interpolate PR01,SA01" \ -i "pandas.api.interchange.from_dataframe RT03,SA01" \ -i "pandas.api.types.is_bool PR01,SA01" \ diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index b3811eb644dc5..d03f3ce0e27fc 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -1008,6 +1008,29 @@ cdef class _Timestamp(ABCTimestamp): """ return super().fold + @property + def year(self) -> int: + """ + Return the year of the Timestamp. + + Returns + ------- + int + The year of the Timestamp. + + See Also + -------- + Timestamp.month : Return the month of the Timestamp. + Timestamp.day : Return the day of the Timestamp. + + Examples + -------- + >>> ts = pd.Timestamp("2024-08-31 16:16:30") + >>> ts.year + 2024 + """ + return super().year + @property def month(self) -> int: """ @@ -1020,8 +1043,8 @@ cdef class _Timestamp(ABCTimestamp): See Also -------- - Timestamp.day : Return the day of the year. - Timestamp.year : Return the year of the week. + Timestamp.day : Return the day of the Timestamp. + Timestamp.year : Return the year of the Timestamp. Examples -------- @@ -1123,6 +1146,29 @@ cdef class _Timestamp(ABCTimestamp): """ return super().microsecond + @property + def nanosecond(self) -> int: + """ + Return the nanosecond of the Timestamp. + + Returns + ------- + int + The nanosecond of the Timestamp. + + See Also + -------- + Timestamp.second : Return the second of the Timestamp. + Timestamp.microsecond : Return the microsecond of the Timestamp. + + Examples + -------- + >>> ts = pd.Timestamp("2024-08-31 16:16:30.230400015") + >>> ts.nanosecond + 15 + """ + return super().nanosecond + @property def week(self) -> int: """ From 7b18368331e38e85e23ad2ff56ab376bf62b03fb Mon Sep 17 00:00:00 2001 From: Maria Ivanova Date: Mon, 2 Sep 2024 20:19:51 +0000 Subject: [PATCH 2/4] add value docstring --- ci/code_checks.sh | 1 - pandas/_libs/tslibs/timestamps.pyx | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/ci/code_checks.sh b/ci/code_checks.sh index 823606e2ac09f..f0c7fba0b07ee 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -130,7 +130,6 @@ if [[ -z "$CHECK" || "$CHECK" == "docstrings" ]]; then -i "pandas.Timestamp.min PR02" \ -i "pandas.Timestamp.resolution PR02" \ -i "pandas.Timestamp.tzinfo GL08" \ - -i "pandas.Timestamp.value GL08" \ -i "pandas.api.extensions.ExtensionArray.interpolate PR01,SA01" \ -i "pandas.api.interchange.from_dataframe RT03,SA01" \ -i "pandas.api.types.is_bool PR01,SA01" \ diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index d03f3ce0e27fc..097243b36ad64 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -1169,6 +1169,30 @@ cdef class _Timestamp(ABCTimestamp): """ return super().nanosecond + @property + def value(self) -> int: + """ + Return the value of the Timestamp. + + Returns + ------- + int + The integer representation of the Timestamp object in nanoseconds + since the Unix epoch (1970-01-01 00:00:00 UTC). + + See Also + -------- + Timestamp.second : Return the second of the Timestamp. + Timestamp.minute : Return the minute of the Timestamp. + + Examples + -------- + >>> ts = pd.Timestamp("2024-08-31 16:16:30") + >>> ts.value + 1725120990000000000 + """ + return super().value + @property def week(self) -> int: """ From b5004da375a50ab9d2c6d0735ef81be7da5459ad Mon Sep 17 00:00:00 2001 From: Maria Ivanova Date: Mon, 2 Sep 2024 20:36:48 +0000 Subject: [PATCH 3/4] move value to existing function --- pandas/_libs/tslibs/timestamps.pyx | 45 ++++++++++++++---------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 097243b36ad64..fb6933718c8d6 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -240,6 +240,27 @@ cdef class _Timestamp(ABCTimestamp): @property def value(self) -> int: + """ + Return the value of the Timestamp. + + Returns + ------- + int + The integer representation of the Timestamp object in nanoseconds + since the Unix epoch (1970-01-01 00:00:00 UTC). + + See Also + -------- + Timestamp.second : Return the second of the Timestamp. + Timestamp.minute : Return the minute of the Timestamp. + + Examples + -------- + >>> ts = pd.Timestamp("2024-08-31 16:16:30") + >>> ts.value + 1725120990000000000 + """ + try: return convert_reso(self._value, self._creso, NPY_FR_ns, False) except OverflowError: @@ -1169,30 +1190,6 @@ cdef class _Timestamp(ABCTimestamp): """ return super().nanosecond - @property - def value(self) -> int: - """ - Return the value of the Timestamp. - - Returns - ------- - int - The integer representation of the Timestamp object in nanoseconds - since the Unix epoch (1970-01-01 00:00:00 UTC). - - See Also - -------- - Timestamp.second : Return the second of the Timestamp. - Timestamp.minute : Return the minute of the Timestamp. - - Examples - -------- - >>> ts = pd.Timestamp("2024-08-31 16:16:30") - >>> ts.value - 1725120990000000000 - """ - return super().value - @property def week(self) -> int: """ From 210860ebc6b2c77164a559d95e8250e1cde8ecb3 Mon Sep 17 00:00:00 2001 From: Maria Ivanova Date: Wed, 4 Sep 2024 21:27:53 +0000 Subject: [PATCH 4/4] rename year and nanosecond internally --- pandas/_libs/tslibs/timestamps.pxd | 2 +- pandas/_libs/tslibs/timestamps.pyx | 72 +++++++++++++++--------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/pandas/_libs/tslibs/timestamps.pxd b/pandas/_libs/tslibs/timestamps.pxd index bd73c713f6c04..c5ec92fabc7f8 100644 --- a/pandas/_libs/tslibs/timestamps.pxd +++ b/pandas/_libs/tslibs/timestamps.pxd @@ -21,7 +21,7 @@ cdef _Timestamp create_timestamp_from_ts(int64_t value, cdef class _Timestamp(ABCTimestamp): cdef readonly: - int64_t _value, nanosecond, year + int64_t _value, _nanosecond, _year NPY_DATETIMEUNIT _creso cdef bint _get_start_end_field(self, str field, freq) diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index fb6933718c8d6..d79fe170b5f4c 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -161,8 +161,8 @@ cdef _Timestamp create_timestamp_from_ts( dts.sec, dts.us, tz, fold=fold) ts_base._value = value - ts_base.year = dts.year - ts_base.nanosecond = dts.ps // 1000 + ts_base._year = dts.year + ts_base._nanosecond = dts.ps // 1000 ts_base._creso = reso return ts_base @@ -355,9 +355,9 @@ cdef class _Timestamp(ABCTimestamp): # ----------------------------------------------------------------- def __hash__(_Timestamp self): - if self.nanosecond: + if self._nanosecond: return hash(self._value) - if not (1 <= self.year <= 9999): + if not (1 <= self._year <= 9999): # out of bounds for pydatetime return hash(self._value) if self.fold: @@ -375,7 +375,7 @@ cdef class _Timestamp(ABCTimestamp): elif cnp.is_datetime64_object(other): ots = Timestamp(other) elif PyDateTime_Check(other): - if self.nanosecond == 0: + if self._nanosecond == 0: val = self.to_pydatetime() return PyObject_RichCompareBool(val, other, op) @@ -454,7 +454,7 @@ cdef class _Timestamp(ABCTimestamp): if not self._can_compare(other): return NotImplemented - if self.nanosecond == 0: + if self._nanosecond == 0: return PyObject_RichCompareBool(dtval, other, op) # otherwise we have dtval < self @@ -463,9 +463,9 @@ cdef class _Timestamp(ABCTimestamp): if op == Py_EQ: return False if op == Py_LE or op == Py_LT: - return self.year <= other.year + return self._year <= other.year if op == Py_GE or op == Py_GT: - return self.year >= other.year + return self._year >= other.year cdef bint _can_compare(self, datetime other): if self.tzinfo is not None: @@ -606,7 +606,7 @@ cdef class _Timestamp(ABCTimestamp): if own_tz is not None and not is_utc(own_tz): pydatetime_to_dtstruct(self, &dts) - val = npy_datetimestruct_to_datetime(self._creso, &dts) + self.nanosecond + val = npy_datetimestruct_to_datetime(self._creso, &dts) + self._nanosecond else: val = self._value return val @@ -898,7 +898,7 @@ cdef class _Timestamp(ABCTimestamp): >>> ts.is_leap_year True """ - return bool(ccalendar.is_leapyear(self.year)) + return bool(ccalendar.is_leapyear(self._year)) @property def day_of_week(self) -> int: @@ -942,7 +942,7 @@ cdef class _Timestamp(ABCTimestamp): >>> ts.day_of_year 74 """ - return ccalendar.get_day_of_year(self.year, self.month, self.day) + return ccalendar.get_day_of_year(self._year, self.month, self.day) @property def quarter(self) -> int: @@ -1050,7 +1050,7 @@ cdef class _Timestamp(ABCTimestamp): >>> ts.year 2024 """ - return super().year + return self._year @property def month(self) -> int: @@ -1188,7 +1188,7 @@ cdef class _Timestamp(ABCTimestamp): >>> ts.nanosecond 15 """ - return super().nanosecond + return self._nanosecond @property def week(self) -> int: @@ -1210,7 +1210,7 @@ cdef class _Timestamp(ABCTimestamp): >>> ts.week 11 """ - return ccalendar.get_week_of_year(self.year, self.month, self.day) + return ccalendar.get_week_of_year(self._year, self.month, self.day) @property def days_in_month(self) -> int: @@ -1232,7 +1232,7 @@ cdef class _Timestamp(ABCTimestamp): >>> ts.days_in_month 31 """ - return ccalendar.get_days_in_month(self.year, self.month) + return ccalendar.get_days_in_month(self._year, self.month) # ----------------------------------------------------------------- # Transformation Methods @@ -1306,7 +1306,7 @@ cdef class _Timestamp(ABCTimestamp): The full format looks like 'YYYY-MM-DD HH:MM:SS.mmmmmmnnn'. By default, the fractional part is omitted if self.microsecond == 0 - and self.nanosecond == 0. + and self._nanosecond == 0. If self.tzinfo is not None, the UTC offset is also attached, giving giving a full format of 'YYYY-MM-DD HH:MM:SS.mmmmmmnnn+HH:MM'. @@ -1342,9 +1342,9 @@ cdef class _Timestamp(ABCTimestamp): base_ts = "microseconds" if timespec == "nanoseconds" else timespec base = super(_Timestamp, self).isoformat(sep=sep, timespec=base_ts) # We need to replace the fake year 1970 with our real year - base = f"{self.year:04d}-" + base.split("-", 1)[1] + base = f"{self._year:04d}-" + base.split("-", 1)[1] - if self.nanosecond == 0 and timespec != "nanoseconds": + if self._nanosecond == 0 and timespec != "nanoseconds": return base if self.tzinfo is not None: @@ -1352,11 +1352,11 @@ cdef class _Timestamp(ABCTimestamp): else: base1, base2 = base, "" - if timespec == "nanoseconds" or (timespec == "auto" and self.nanosecond): + if timespec == "nanoseconds" or (timespec == "auto" and self._nanosecond): if self.microsecond or timespec == "nanoseconds": - base1 += f"{self.nanosecond:03d}" + base1 += f"{self._nanosecond:03d}" else: - base1 += f".{self.nanosecond:09d}" + base1 += f".{self._nanosecond:09d}" return base1 + base2 @@ -1390,14 +1390,14 @@ cdef class _Timestamp(ABCTimestamp): def _date_repr(self) -> str: # Ideal here would be self.strftime("%Y-%m-%d"), but # the datetime strftime() methods require year >= 1900 and is slower - return f"{self.year}-{self.month:02d}-{self.day:02d}" + return f"{self._year}-{self.month:02d}-{self.day:02d}" @property def _time_repr(self) -> str: result = f"{self.hour:02d}:{self.minute:02d}:{self.second:02d}" - if self.nanosecond != 0: - result += f".{self.nanosecond + 1000 * self.microsecond:09d}" + if self._nanosecond != 0: + result += f".{self._nanosecond + 1000 * self.microsecond:09d}" elif self.microsecond != 0: result += f".{self.microsecond:06d}" @@ -1561,11 +1561,11 @@ cdef class _Timestamp(ABCTimestamp): >>> pd.NaT.to_pydatetime() NaT """ - if self.nanosecond != 0 and warn: + if self._nanosecond != 0 and warn: warnings.warn("Discarding nonzero nanoseconds in conversion.", UserWarning, stacklevel=find_stack_level()) - return datetime(self.year, self.month, self.day, + return datetime(self._year, self.month, self.day, self.hour, self.minute, self.second, self.microsecond, self.tzinfo, fold=self.fold) @@ -2044,7 +2044,7 @@ class Timestamp(_Timestamp): '2020-03-14 15:32:52' """ try: - _dt = datetime(self.year, self.month, self.day, + _dt = datetime(self._year, self.month, self.day, self.hour, self.minute, self.second, self.microsecond, self.tzinfo, fold=self.fold) except ValueError as err: @@ -2087,7 +2087,7 @@ class Timestamp(_Timestamp): 'Sun Jan 1 10:00:00 2023' """ try: - _dt = datetime(self.year, self.month, self.day, + _dt = datetime(self._year, self.month, self.day, self.hour, self.minute, self.second, self.microsecond, self.tzinfo, fold=self.fold) except ValueError as err: @@ -2127,7 +2127,7 @@ class Timestamp(_Timestamp): datetime.date(2023, 1, 1) """ try: - _dt = dt.date(self.year, self.month, self.day) + _dt = dt.date(self._year, self.month, self.day) except ValueError as err: raise NotImplementedError( "date not yet supported on Timestamps which " @@ -2176,7 +2176,7 @@ class Timestamp(_Timestamp): datetime.IsoCalendarDate(year=2022, week=52, weekday=7) """ try: - _dt = datetime(self.year, self.month, self.day, + _dt = datetime(self._year, self.month, self.day, self.hour, self.minute, self.second, self.microsecond, self.tzinfo, fold=self.fold) except ValueError as err: @@ -2318,7 +2318,7 @@ class Timestamp(_Timestamp): tm_hour=10, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=1, tm_isdst=-1) """ try: - _dt = datetime(self.year, self.month, self.day, + _dt = datetime(self._year, self.month, self.day, self.hour, self.minute, self.second, self.microsecond, self.tzinfo, fold=self.fold) except ValueError as err: @@ -2379,7 +2379,7 @@ class Timestamp(_Timestamp): 738521 """ try: - _dt = datetime(self.year, self.month, self.day, + _dt = datetime(self._year, self.month, self.day, self.hour, self.minute, self.second, self.microsecond, self.tzinfo, fold=self.fold) except ValueError as err: @@ -3268,7 +3268,7 @@ default 'raise' # setup components pandas_datetime_to_datetimestruct(value, self._creso, &dts) - dts.ps = self.nanosecond * 1000 + dts.ps = self._nanosecond * 1000 # replace def validate(k, v): @@ -3358,7 +3358,7 @@ default 'raise' >>> ts.to_julian_date() 2458923.147824074 """ - year = self.year + year = self._year month = self.month day = self.day if month <= 2: @@ -3375,7 +3375,7 @@ default 'raise' self.minute / 60.0 + self.second / 3600.0 + self.microsecond / 3600.0 / 1e+6 + - self.nanosecond / 3600.0 / 1e+9 + self._nanosecond / 3600.0 / 1e+9 ) / 24.0) def isoweekday(self): @@ -3426,7 +3426,7 @@ default 'raise' """ # same as super().weekday(), but that breaks because of how # we have overridden year, see note in create_timestamp_from_ts - return ccalendar.dayofweek(self.year, self.month, self.day) + return ccalendar.dayofweek(self._year, self.month, self.day) # Aliases