-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Switch enable_cftimeindex to True by default #2516
Changes from 8 commits
4a2acbc
2c70d32
69f6dc7
d203491
93599ca
fa729ec
939b953
1a6841d
f65b764
eaa4a44
147eace
42406e9
359016d
a72d41e
315b093
079cfdf
6d08d3b
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 |
---|---|---|
|
@@ -153,3 +153,4 @@ | |
plot.FacetGrid.map | ||
|
||
CFTimeIndex.shift | ||
CFTimeIndex.to_datetimeindex |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,6 @@ | |
from ..core import indexing | ||
from ..core.common import contains_cftime_datetimes | ||
from ..core.formatting import first_n_items, format_timestamp, last_item | ||
from ..core.options import OPTIONS | ||
from ..core.pycompat import PY3 | ||
from ..core.variable import Variable | ||
from .variables import ( | ||
|
@@ -61,8 +60,9 @@ def _require_standalone_cftime(): | |
try: | ||
import cftime # noqa: F401 | ||
except ImportError: | ||
raise ImportError('Using a CFTimeIndex requires the standalone ' | ||
'version of the cftime library.') | ||
raise ImportError('Decoding times with non-standard calendars ' | ||
'or outside the pandas.Timestamp-valid range ' | ||
'requires the standalone cftime package.') | ||
|
||
|
||
def _netcdf_to_numpy_timeunit(units): | ||
|
@@ -84,41 +84,32 @@ def _unpack_netcdf_time_units(units): | |
return delta_units, ref_date | ||
|
||
|
||
def _decode_datetime_with_cftime(num_dates, units, calendar, | ||
enable_cftimeindex): | ||
def _decode_datetime_with_cftime(num_dates, units, calendar): | ||
cftime = _import_cftime() | ||
if enable_cftimeindex: | ||
_require_standalone_cftime() | ||
|
||
if cftime.__name__ == 'cftime': | ||
dates = np.asarray(cftime.num2date(num_dates, units, calendar, | ||
only_use_cftime_datetimes=True)) | ||
else: | ||
# Must be using num2date from an old version of netCDF4 which | ||
# does not have the only_use_cftime_datetimes option. | ||
dates = np.asarray(cftime.num2date(num_dates, units, calendar)) | ||
|
||
if (dates[np.nanargmin(num_dates)].year < 1678 or | ||
dates[np.nanargmax(num_dates)].year >= 2262): | ||
if not enable_cftimeindex or calendar in _STANDARD_CALENDARS: | ||
if calendar in _STANDARD_CALENDARS: | ||
warnings.warn( | ||
'Unable to decode time axis into full ' | ||
'numpy.datetime64 objects, continuing using dummy ' | ||
'cftime.datetime objects instead, reason: dates out ' | ||
'of range', SerializationWarning, stacklevel=3) | ||
else: | ||
if enable_cftimeindex: | ||
if calendar in _STANDARD_CALENDARS: | ||
dates = cftime_to_nptime(dates) | ||
else: | ||
try: | ||
dates = cftime_to_nptime(dates) | ||
except ValueError as e: | ||
warnings.warn( | ||
'Unable to decode time axis into full ' | ||
'numpy.datetime64 objects, continuing using ' | ||
'dummy cftime.datetime objects instead, reason:' | ||
'{0}'.format(e), SerializationWarning, stacklevel=3) | ||
if calendar in _STANDARD_CALENDARS: | ||
dates = cftime_to_nptime(dates) | ||
return dates | ||
|
||
|
||
def _decode_cf_datetime_dtype(data, units, calendar, enable_cftimeindex): | ||
def _decode_cf_datetime_dtype(data, units, calendar): | ||
# Verify that at least the first and last date can be decoded | ||
# successfully. Otherwise, tracebacks end up swallowed by | ||
# Dataset.__repr__ when users try to view their lazily decoded array. | ||
|
@@ -128,8 +119,7 @@ def _decode_cf_datetime_dtype(data, units, calendar, enable_cftimeindex): | |
last_item(values) or [0]]) | ||
|
||
try: | ||
result = decode_cf_datetime(example_value, units, calendar, | ||
enable_cftimeindex) | ||
result = decode_cf_datetime(example_value, units, calendar) | ||
except Exception: | ||
calendar_msg = ('the default calendar' if calendar is None | ||
else 'calendar %r' % calendar) | ||
|
@@ -145,8 +135,7 @@ def _decode_cf_datetime_dtype(data, units, calendar, enable_cftimeindex): | |
return dtype | ||
|
||
|
||
def decode_cf_datetime(num_dates, units, calendar=None, | ||
enable_cftimeindex=False): | ||
def decode_cf_datetime(num_dates, units, calendar=None): | ||
"""Given an array of numeric dates in netCDF format, convert it into a | ||
numpy array of date time objects. | ||
|
||
|
@@ -200,8 +189,7 @@ def decode_cf_datetime(num_dates, units, calendar=None, | |
|
||
except (OutOfBoundsDatetime, OverflowError): | ||
dates = _decode_datetime_with_cftime( | ||
flat_num_dates.astype(np.float), units, calendar, | ||
enable_cftimeindex) | ||
flat_num_dates.astype(np.float), units, calendar) | ||
|
||
return dates.reshape(num_dates.shape) | ||
|
||
|
@@ -291,7 +279,12 @@ def cftime_to_nptime(times): | |
times = np.asarray(times) | ||
new = np.empty(times.shape, dtype='M8[ns]') | ||
for i, t in np.ndenumerate(times): | ||
dt = datetime(t.year, t.month, t.day, t.hour, t.minute, t.second) | ||
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. Was there a reason we did not include the 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. Possibly |
||
try: | ||
dt = pd.Timestamp(t.year, t.month, t.day, t.hour, t.minute, | ||
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 switched to using
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. sounds good -- please note this in a comment in the code The usual rule is that if you have to comment on your pull request to explain why you did something, you should just comment the code instead! :) |
||
t.second) | ||
except ValueError as e: | ||
raise ValueError('Cannot convert date {} to a date in the ' | ||
'standard calendar. Reason: {}.'.format(t, e)) | ||
new[i] = np.datetime64(dt) | ||
return new | ||
|
||
|
@@ -399,15 +392,12 @@ def encode(self, variable, name=None): | |
def decode(self, variable, name=None): | ||
dims, data, attrs, encoding = unpack_for_decoding(variable) | ||
|
||
enable_cftimeindex = OPTIONS['enable_cftimeindex'] | ||
if 'units' in attrs and 'since' in attrs['units']: | ||
units = pop_to(attrs, encoding, 'units') | ||
calendar = pop_to(attrs, encoding, 'calendar') | ||
dtype = _decode_cf_datetime_dtype( | ||
data, units, calendar, enable_cftimeindex) | ||
dtype = _decode_cf_datetime_dtype(data, units, calendar) | ||
transform = partial( | ||
decode_cf_datetime, units=units, calendar=calendar, | ||
enable_cftimeindex=enable_cftimeindex) | ||
decode_cf_datetime, units=units, calendar=calendar) | ||
data = lazy_elemwise_func(data, transform, dtype) | ||
|
||
return Variable(dims, data, attrs, encoding) | ||
|
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.
This looks great, but can we add a keyword argument for silencing the warning? Maybe
index.to_datetimeindex(unsafe=True)
could silence the warning?