Skip to content

Commit

Permalink
Fix docstring timestamps (Issue #59458) (#59688)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: Marco Gorelli <[email protected]>
  • Loading branch information
mimistiv and MarcoGorelli authored Nov 11, 2024
1 parent e531732 commit 156e67e
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 37 deletions.
2 changes: 0 additions & 2 deletions ci/code_checks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,8 @@ if [[ -z "$CHECK" || "$CHECK" == "docstrings" ]]; then
-i "pandas.Timedelta.resolution PR02" \
-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.year GL08" \
-i "pandas.api.types.is_re_compilable PR07,SA01" \
-i "pandas.api.types.pandas_dtype PR07,RT03,SA01" \
-i "pandas.arrays.ArrowExtensionArray PR07,SA01" \
Expand Down
2 changes: 1 addition & 1 deletion pandas/_libs/tslibs/timestamps.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
114 changes: 80 additions & 34 deletions pandas/_libs/tslibs/timestamps.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,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
Expand Down Expand Up @@ -356,9 +356,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:
Expand All @@ -376,7 +376,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)

Expand Down Expand Up @@ -455,7 +455,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
Expand All @@ -464,9 +464,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:
Expand Down Expand Up @@ -607,7 +607,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
Expand Down Expand Up @@ -899,7 +899,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:
Expand Down Expand Up @@ -943,7 +943,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:
Expand Down Expand Up @@ -1030,6 +1030,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 self._year
@property
def month(self) -> int:
"""
Expand Down Expand Up @@ -1145,6 +1168,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 self._nanosecond
@property
def week(self) -> int:
"""
Expand All @@ -1165,7 +1211,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:
Expand All @@ -1187,7 +1233,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
Expand Down Expand Up @@ -1261,7 +1307,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'.
Expand Down Expand Up @@ -1297,21 +1343,21 @@ 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:
base1, base2 = base[:-6], base[-6:]
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
Expand Down Expand Up @@ -1345,14 +1391,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}"
Expand Down Expand Up @@ -1516,11 +1562,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)
Expand Down Expand Up @@ -1999,7 +2045,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:
Expand Down Expand Up @@ -2042,7 +2088,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:
Expand Down Expand Up @@ -2082,7 +2128,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 "
Expand Down Expand Up @@ -2131,7 +2177,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:
Expand Down Expand Up @@ -2273,7 +2319,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:
Expand Down Expand Up @@ -2334,7 +2380,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:
Expand Down Expand Up @@ -3223,7 +3269,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):
Expand Down Expand Up @@ -3313,7 +3359,7 @@ default 'raise'
>>> ts.to_julian_date()
2458923.147824074
"""
year = self.year
year = self._year
month = self.month
day = self.day
if month <= 2:
Expand All @@ -3330,7 +3376,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):
Expand Down Expand Up @@ -3381,7 +3427,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
Expand Down

0 comments on commit 156e67e

Please sign in to comment.