-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
ENH/BUG: Add is_dst method to DatetimeIndex and Timestamp to solve AmbiguousTimeError #22560
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 8 commits
be2b6dd
18f8611
442f888
254b5a2
7c73d0a
b0938d5
641e295
820df35
9304b50
83109eb
627bb19
c03792e
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 |
---|---|---|
|
@@ -186,16 +186,28 @@ cdef object get_utc_trans_times_from_dateutil_tz(object tz): | |
return new_trans | ||
|
||
|
||
cdef int64_t[:] unbox_utcoffsets(object transinfo): | ||
cdef int64_t[:] unbox_utcoffsets(object transinfo, dst): | ||
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. can you add bint to type dst |
||
""" | ||
Unpack the offset information from pytz timezone objects | ||
|
||
Parameters | ||
---------- | ||
transinfo : list of tuples | ||
Each tuple contains (UTC offset, DST offset, tz abbreviation) | ||
dst : boolean | ||
True returns an array of the DST offsets | ||
False returns an array of UTC offsets | ||
""" | ||
cdef: | ||
Py_ssize_t i, sz | ||
int64_t[:] arr | ||
int key | ||
|
||
sz = len(transinfo) | ||
arr = np.empty(sz, dtype='i8') | ||
|
||
key = int(dst) | ||
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. you may not need this if typing bint |
||
for i in range(sz): | ||
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. can you add a comment about what you are extracting |
||
arr[i] = int(transinfo[i][0].total_seconds()) * 1000000000 | ||
arr[i] = int(transinfo[i][key].total_seconds()) * 1000000000 | ||
|
||
return arr | ||
|
||
|
@@ -204,9 +216,22 @@ cdef int64_t[:] unbox_utcoffsets(object transinfo): | |
# Daylight Savings | ||
|
||
|
||
cdef object get_dst_info(object tz): | ||
cdef object get_dst_info(object tz, dst): | ||
""" | ||
return a tuple of : | ||
Return DST info from a timezone | ||
|
||
Parameters | ||
---------- | ||
tz : object | ||
timezone | ||
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 we accept only timezone objects and not strings here? |
||
dst : bool | ||
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. type with bitn |
||
True returns the DST specific offset | ||
False returns the UTC offset | ||
Specific for pytz timezones only | ||
|
||
Returns | ||
------- | ||
tuple | ||
(UTC times of DST transitions, | ||
UTC offsets in microseconds corresponding to DST transitions, | ||
string of type of transitions) | ||
|
@@ -230,7 +255,7 @@ cdef object get_dst_info(object tz): | |
trans[0] = NPY_NAT + 1 | ||
except Exception: | ||
pass | ||
deltas = unbox_utcoffsets(tz._transition_info) | ||
deltas = unbox_utcoffsets(tz._transition_info, dst) | ||
typ = 'pytz' | ||
|
||
elif treat_tz_as_dateutil(tz): | ||
|
@@ -278,6 +303,44 @@ cdef object get_dst_info(object tz): | |
return dst_cache[cache_key] | ||
|
||
|
||
def _is_dst(int64_t[:] values, object tz): | ||
""" | ||
Return a boolean array indicating whether each epoch timestamp is in | ||
daylight savings time with respect with the passed timezone. | ||
|
||
Parameters | ||
---------- | ||
values : ndarray | ||
i8 representation of the datetimes | ||
tz : object | ||
timezone | ||
|
||
Returns | ||
------- | ||
ndarray of booleans | ||
True indicates daylight savings time | ||
""" | ||
cdef: | ||
Py_ssize_t n = len(values) | ||
# Cython boolean memoryviews are not supported yet | ||
# https://github.com/cython/cython/issues/2204 | ||
# bint[:] result | ||
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 the workaround is to use a uint8 |
||
object typ | ||
|
||
result = np.zeros(n, dtype=bool) | ||
if tz is None: | ||
return result | ||
transitions, offsets, typ = get_dst_info(tz, True) | ||
offsets = np.array(offsets) | ||
# Fixed timezone offsets do not have DST transitions | ||
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. new line here |
||
if typ not in {'pytz', 'dateutil'}: | ||
return result | ||
positions = transitions.searchsorted(values, side='right') | ||
# DST has 0 offset | ||
result = offsets[positions] == 0 | ||
return result | ||
|
||
|
||
def infer_tzinfo(start, end): | ||
if start is not None and end is not None: | ||
tz = start.tzinfo | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -266,7 +266,7 @@ def _add_comparison_methods(cls): | |
_datetimelike_methods = ['to_period', 'tz_localize', | ||
'tz_convert', | ||
'normalize', 'strftime', 'round', 'floor', | ||
'ceil', 'month_name', 'day_name'] | ||
'ceil', 'month_name', 'day_name', 'is_dst'] | ||
|
||
_is_numeric_dtype = False | ||
_infer_as_myclass = True | ||
|
@@ -443,6 +443,36 @@ def tz(self, value): | |
raise AttributeError("Cannot directly set timezone. Use tz_localize() " | ||
"or tz_convert() as appropriate") | ||
|
||
def is_dst(self): | ||
""" | ||
Returns an Index of booleans indicating if each corresponding timestamp | ||
is in daylight savings time. | ||
|
||
If the DatetimeIndex does not have a timezone, returns an Index | ||
who's values are all False. | ||
|
||
Returns | ||
------- | ||
Index | ||
True if the timestamp is in daylight savings time else False | ||
|
||
Example | ||
------- | ||
>>> dti = pd.date_range('2018-11-04', periods=4, freq='H', | ||
tz='US/Pacific') | ||
|
||
>>> dti | ||
DatetimeIndex(['2018-11-04 00:00:00-07:00', | ||
'2018-11-04 01:00:00-07:00', | ||
'2018-11-04 01:00:00-08:00', | ||
'2018-11-04 02:00:00-08:00'], | ||
dtype='datetime64[ns, US/Pacific]', freq='H') | ||
|
||
>>> dti.is_dst() | ||
Index([True, True, False, False], dtype='object') | ||
""" | ||
return Index(timezones._is_dst(self.asi8, self.tz)) | ||
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. Make is_dst public? |
||
|
||
@property | ||
def size(self): | ||
# TODO: Remove this when we have a DatetimeTZArray | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why removing?