Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions ci/code_checks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,8 @@ 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.year GL08" \
-i "pandas.api.extensions.ExtensionArray.interpolate PR01,SA01" \
-i "pandas.api.types.is_bool PR01,SA01" \
-i "pandas.api.types.is_categorical_dtype 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 @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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)

Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -1029,6 +1029,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 @@ -1144,6 +1167,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 @@ -1164,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:
Expand All @@ -1186,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
Expand Down Expand Up @@ -1260,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'.
Expand Down Expand Up @@ -1296,21 +1342,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 @@ -1344,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}"

Expand Down Expand Up @@ -1515,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)

Expand Down Expand Up @@ -1998,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:
Expand Down Expand Up @@ -2041,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:
Expand Down Expand Up @@ -2081,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 "
Expand Down Expand Up @@ -2130,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:
Expand Down Expand Up @@ -2272,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:
Expand Down Expand Up @@ -2333,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:
Expand Down Expand Up @@ -3222,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):
Expand Down Expand Up @@ -3312,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:
Expand All @@ -3329,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):
Expand Down Expand Up @@ -3380,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
Expand Down