Skip to content

ENH: DTA/DTI __repr__ support non-nano #47374

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions pandas/_libs/tslib.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def format_array_from_datetime(
tz: tzinfo | None = ...,
format: str | None = ...,
na_rep: object = ...,
reso: int = ..., # NPY_DATETIMEUNIT
) -> npt.NDArray[np.object_]: ...
def array_with_unit_to_datetime(
values: np.ndarray,
Expand Down
13 changes: 8 additions & 5 deletions pandas/_libs/tslib.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ import pytz

from pandas._libs.tslibs.np_datetime cimport (
NPY_DATETIMEUNIT,
NPY_FR_ns,
check_dts_bounds,
dt64_to_dtstruct,
dtstruct_to_dt64,
get_datetime64_value,
npy_datetimestruct,
pandas_datetime_to_datetimestruct,
pydate_to_dt64,
pydatetime_to_dt64,
string_to_dts,
Expand Down Expand Up @@ -107,7 +108,8 @@ def format_array_from_datetime(
ndarray[int64_t] values,
tzinfo tz=None,
str format=None,
object na_rep=None
object na_rep=None,
NPY_DATETIMEUNIT reso=NPY_FR_ns,
) -> np.ndarray:
"""
return a np object array of the string formatted values
Expand All @@ -120,6 +122,7 @@ def format_array_from_datetime(
a strftime capable string
na_rep : optional, default is None
a nat format
reso : NPY_DATETIMEUNIT, default NPY_FR_ns

Returns
-------
Expand All @@ -141,7 +144,7 @@ def format_array_from_datetime(
# a format based on precision
basic_format = format is None and tz is None
if basic_format:
reso_obj = get_resolution(values)
reso_obj = get_resolution(values, reso=reso)
show_ns = reso_obj == Resolution.RESO_NS
show_us = reso_obj == Resolution.RESO_US
show_ms = reso_obj == Resolution.RESO_MS
Expand All @@ -153,7 +156,7 @@ def format_array_from_datetime(
result[i] = na_rep
elif basic_format:

dt64_to_dtstruct(val, &dts)
pandas_datetime_to_datetimestruct(val, reso, &dts)
res = (f'{dts.year}-{dts.month:02d}-{dts.day:02d} '
f'{dts.hour:02d}:{dts.min:02d}:{dts.sec:02d}')

Expand All @@ -169,7 +172,7 @@ def format_array_from_datetime(

else:

ts = Timestamp(val, tz=tz)
ts = Timestamp._from_value_and_reso(val, reso=reso, tz=tz)
if format is None:
result[i] = str(ts)
else:
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/arrays/datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ def _format_native_types(
fmt = get_format_datetime64_from_values(self, date_format)

return tslib.format_array_from_datetime(
self.asi8, tz=self.tz, format=fmt, na_rep=na_rep
self.asi8, tz=self.tz, format=fmt, na_rep=na_rep, reso=self._reso
)

# -----------------------------------------------------------------
Expand Down
17 changes: 12 additions & 5 deletions pandas/io/formats/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@
NaT,
Timedelta,
Timestamp,
get_unit_from_dtype,
iNaT,
periods_per_day,
)
from pandas._libs.tslibs.nattype import NaTType
from pandas._typing import (
Expand Down Expand Up @@ -1738,16 +1740,21 @@ def is_dates_only(values: np.ndarray | DatetimeArray | Index | DatetimeIndex) ->
if not isinstance(values, Index):
values = values.ravel()

values = DatetimeIndex(values)
if not isinstance(values, (DatetimeArray, DatetimeIndex)):
values = DatetimeIndex(values)

if values.tz is not None:
return False

values_int = values.asi8
consider_values = values_int != iNaT
one_day_nanos = 86400 * 10**9
even_days = (
np.logical_and(consider_values, values_int % int(one_day_nanos) != 0).sum() == 0
)
# error: Argument 1 to "py_get_unit_from_dtype" has incompatible type
# "Union[dtype[Any], ExtensionDtype]"; expected "dtype[Any]"
reso = get_unit_from_dtype(values.dtype) # type: ignore[arg-type]
ppd = periods_per_day(reso)

# TODO: can we reuse is_date_array_normalized? would need a skipna kwd
even_days = np.logical_and(consider_values, values_int % ppd != 0).sum() == 0
if even_days:
return True
return False
Expand Down
14 changes: 14 additions & 0 deletions pandas/tests/arrays/test_datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,20 @@ def test_time_date(self, dta_dti, meth):
expected = getattr(dti, meth)
tm.assert_numpy_array_equal(result, expected)

def test_format_native_types(self, unit, reso, dtype, dta_dti):
# In this case we should get the same formatted values with our nano
# version dti._data as we do with the non-nano dta
dta, dti = dta_dti

res = dta._format_native_types()
exp = dti._data._format_native_types()
tm.assert_numpy_array_equal(res, exp)

def test_repr(self, dta_dti, unit):
dta, dti = dta_dti

assert repr(dta) == repr(dti._data).replace("[ns", f"[{unit}")


class TestDatetimeArrayComparisons:
# TODO: merge this into tests/arithmetic/test_datetime64 once it is
Expand Down
6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,11 @@ def srcpath(name=None, suffix=".pyx", subdir="src"):
"_libs.properties": {"pyxfile": "_libs/properties"},
"_libs.reshape": {"pyxfile": "_libs/reshape", "depends": []},
"_libs.sparse": {"pyxfile": "_libs/sparse", "depends": _pxi_dep["sparse"]},
"_libs.tslib": {"pyxfile": "_libs/tslib", "depends": tseries_depends},
"_libs.tslib": {
"pyxfile": "_libs/tslib",
"depends": tseries_depends,
"sources": ["pandas/_libs/tslibs/src/datetime/np_datetime.c"],
},
"_libs.tslibs.base": {"pyxfile": "_libs/tslibs/base"},
"_libs.tslibs.ccalendar": {"pyxfile": "_libs/tslibs/ccalendar"},
"_libs.tslibs.dtypes": {"pyxfile": "_libs/tslibs/dtypes"},
Expand Down