-
-
Notifications
You must be signed in to change notification settings - Fork 18.6k
API: Timestamp(pydatetime) microsecond reso #49034
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
Changes from all commits
261719c
a8c6906
6f5d4b5
ad51d10
74105d8
43436ce
dad131f
8802add
4c6f0f6
5c18738
17682b5
aeadbdc
382c46e
85aba3f
f8cef09
bc6f014
343954f
7f8db31
25db552
fe8c444
d5e94d1
7717c10
b4ebc62
06945fc
bf9705a
40f28a1
e32996e
83cf179
0eafbd5
072eaee
fd0125d
c7c0cee
eab61b9
afe09bb
257276d
6975db1
a640de0
c15675d
be83f35
8155f2a
497ee62
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,7 @@ from pandas._libs.tslibs.dtypes cimport ( | |
from pandas._libs.tslibs.np_datetime cimport ( | ||
NPY_DATETIMEUNIT, | ||
NPY_FR_ns, | ||
NPY_FR_us, | ||
check_dts_bounds, | ||
convert_reso, | ||
get_datetime64_unit, | ||
|
@@ -212,7 +213,12 @@ cdef class _TSObject: | |
|
||
cdef int64_t ensure_reso(self, NPY_DATETIMEUNIT creso) except? -1: | ||
if self.creso != creso: | ||
self.value = convert_reso(self.value, self.creso, creso, False) | ||
try: | ||
self.value = convert_reso(self.value, self.creso, creso, False) | ||
except OverflowError as err: | ||
raise OutOfBoundsDatetime from err | ||
|
||
self.creso = creso | ||
return self.value | ||
|
||
|
||
|
@@ -288,11 +294,22 @@ cdef _TSObject convert_to_tsobject(object ts, tzinfo tz, str unit, | |
obj.value = ts | ||
pandas_datetime_to_datetimestruct(ts, NPY_FR_ns, &obj.dts) | ||
elif PyDateTime_Check(ts): | ||
return convert_datetime_to_tsobject(ts, tz, nanos) | ||
if nanos == 0: | ||
if isinstance(ts, ABCTimestamp): | ||
reso = abbrev_to_npy_unit(ts.unit) # TODO: faster way to do this? | ||
else: | ||
# TODO: what if user explicitly passes nanos=0? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it possible to hit this? Maybe we should raise instead? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think it could happen with |
||
reso = NPY_FR_us | ||
else: | ||
reso = NPY_FR_ns | ||
return convert_datetime_to_tsobject(ts, tz, nanos, reso=reso) | ||
elif PyDate_Check(ts): | ||
# Keep the converter same as PyDateTime's | ||
# For date object we give the lowest supported resolution, i.e. "s" | ||
ts = datetime.combine(ts, time()) | ||
return convert_datetime_to_tsobject(ts, tz) | ||
return convert_datetime_to_tsobject( | ||
ts, tz, nanos=0, reso=NPY_DATETIMEUNIT.NPY_FR_s | ||
) | ||
else: | ||
from .period import Period | ||
if isinstance(ts, Period): | ||
|
@@ -346,6 +363,7 @@ cdef _TSObject convert_datetime_to_tsobject( | |
_TSObject obj = _TSObject() | ||
int64_t pps | ||
|
||
obj.creso = reso | ||
obj.fold = ts.fold | ||
if tz is not None: | ||
tz = maybe_get_tz(tz) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -360,7 +360,14 @@ def wrapper( | |
if out_dtype is not None: | ||
out = out.view(out_dtype) | ||
if fill_wrap is not None: | ||
# FIXME: if we get here with dt64/td64 we need to be sure we have | ||
# matching resos | ||
if fill_value.dtype.kind == "m": | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be worth making a re-usable function for this? I could see this useful in other areas. Something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i'd like to hold off on that as out of scope |
||
fill_value = fill_value.astype("m8[ns]") | ||
else: | ||
fill_value = fill_value.astype("M8[ns]") | ||
fill_value = fill_wrap(fill_value) | ||
|
||
f(arr, indexer, out, fill_value=fill_value) | ||
|
||
return wrapper | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -445,7 +445,7 @@ def _generate_range( # type: ignore[override] | |
i8values = generate_regular_range(start, end, periods, freq, unit=unit) | ||
else: | ||
xdr = _generate_range( | ||
start=start, end=end, periods=periods, offset=freq | ||
start=start, end=end, periods=periods, offset=freq, unit=unit | ||
) | ||
i8values = np.array([x.value for x in xdr], dtype=np.int64) | ||
|
||
|
@@ -508,7 +508,10 @@ def _unbox_scalar(self, value) -> np.datetime64: | |
if not isinstance(value, self._scalar_type) and value is not NaT: | ||
raise ValueError("'value' should be a Timestamp.") | ||
self._check_compatible_with(value) | ||
return value.asm8 | ||
if value is NaT: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Possible I've missed this conversation but do we need to give consideration to a generic NaT type that can hold different precisions? Or are we always going to use numpy's value? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The closest I've seen to this has been a discussion of having a separate NaT-like for timedelta. I'm not aware of any discussion of a resolution-specific NaT. |
||
return np.datetime64(value.value, self.unit) | ||
else: | ||
return value.as_unit(self.unit).asm8 | ||
|
||
def _scalar_from_string(self, value) -> Timestamp | NaTType: | ||
return Timestamp(value, tz=self.tz) | ||
|
@@ -2475,6 +2478,8 @@ def _generate_range( | |
end: Timestamp | None, | ||
periods: int | None, | ||
offset: BaseOffset, | ||
*, | ||
unit: str, | ||
): | ||
""" | ||
Generates a sequence of dates corresponding to the specified time | ||
|
@@ -2486,7 +2491,8 @@ def _generate_range( | |
start : Timestamp or None | ||
end : Timestamp or None | ||
periods : int or None | ||
offset : DateOffset, | ||
offset : DateOffset | ||
unit : str | ||
|
||
Notes | ||
----- | ||
|
@@ -2506,13 +2512,20 @@ def _generate_range( | |
start = Timestamp(start) # type: ignore[arg-type] | ||
# Non-overlapping identity check (left operand type: "Timestamp", right | ||
# operand type: "NaTType") | ||
start = start if start is not NaT else None # type: ignore[comparison-overlap] | ||
if start is not NaT: # type: ignore[comparison-overlap] | ||
start = start.as_unit(unit) | ||
else: | ||
start = None | ||
|
||
# Argument 1 to "Timestamp" has incompatible type "Optional[Timestamp]"; | ||
# expected "Union[integer[Any], float, str, date, datetime64]" | ||
end = Timestamp(end) # type: ignore[arg-type] | ||
# Non-overlapping identity check (left operand type: "Timestamp", right | ||
# operand type: "NaTType") | ||
end = end if end is not NaT else None # type: ignore[comparison-overlap] | ||
if end is not NaT: # type: ignore[comparison-overlap] | ||
end = end.as_unit(unit) | ||
else: | ||
end = None | ||
|
||
if start and not offset.is_on_offset(start): | ||
# Incompatible types in assignment (expression has type "datetime", | ||
|
@@ -2553,7 +2566,7 @@ def _generate_range( | |
break | ||
|
||
# faster than cur + offset | ||
next_date = offset._apply(cur) | ||
next_date = offset._apply(cur).as_unit(unit) | ||
if next_date <= cur: | ||
raise ValueError(f"Offset {offset} did not increment date") | ||
cur = next_date | ||
|
@@ -2567,7 +2580,7 @@ def _generate_range( | |
break | ||
|
||
# faster than cur + offset | ||
next_date = offset._apply(cur) | ||
next_date = offset._apply(cur).as_unit(unit) | ||
if next_date >= cur: | ||
raise ValueError(f"Offset {offset} did not decrement date") | ||
cur = next_date |
Uh oh!
There was an error while loading. Please reload this page.