40
40
'milliseconds' , 'microseconds' ])
41
41
42
42
43
+ def _import_netcdftime ():
44
+ '''
45
+ helper function handle the transition to netcdftime as a stand-alone
46
+ package
47
+ '''
48
+ try :
49
+ # Try importing netcdftime directly
50
+ import netcdftime as nctime
51
+ if not hasattr (nctime , 'num2date' ):
52
+ # must have gotten an old version from netcdf4-python
53
+ raise ImportError
54
+ except ImportError :
55
+ # in netCDF4 the num2date/date2num function are top-level api
56
+ try :
57
+ import netCDF4 as nctime
58
+ except ImportError :
59
+ raise ImportError ("Failed to import netcdftime" )
60
+ return nctime
61
+
62
+
43
63
def _netcdf_to_numpy_timeunit (units ):
44
64
units = units .lower ()
45
65
if not units .endswith ('s' ):
@@ -59,23 +79,23 @@ def _unpack_netcdf_time_units(units):
59
79
return delta_units , ref_date
60
80
61
81
62
- def _decode_datetime_with_netcdf4 (num_dates , units , calendar ):
63
- import netCDF4 as nc4
82
+ def _decode_datetime_with_netcdftime (num_dates , units , calendar ):
83
+ nctime = _import_netcdftime ()
64
84
65
- dates = np .asarray (nc4 .num2date (num_dates , units , calendar ))
85
+ dates = np .asarray (nctime .num2date (num_dates , units , calendar ))
66
86
if (dates [np .nanargmin (num_dates )].year < 1678 or
67
87
dates [np .nanargmax (num_dates )].year >= 2262 ):
68
88
warnings .warn ('Unable to decode time axis into full '
69
89
'numpy.datetime64 objects, continuing using dummy '
70
- 'netCDF4 .datetime objects instead, reason: dates out'
90
+ 'netcdftime .datetime objects instead, reason: dates out'
71
91
' of range' , SerializationWarning , stacklevel = 3 )
72
92
else :
73
93
try :
74
94
dates = nctime_to_nptime (dates )
75
95
except ValueError as e :
76
96
warnings .warn ('Unable to decode time axis into full '
77
97
'numpy.datetime64 objects, continuing using '
78
- 'dummy netCDF4 .datetime objects instead, reason:'
98
+ 'dummy netcdftime .datetime objects instead, reason:'
79
99
'{0}' .format (e ), SerializationWarning , stacklevel = 3 )
80
100
return dates
81
101
@@ -111,15 +131,15 @@ def decode_cf_datetime(num_dates, units, calendar=None):
111
131
numpy array of date time objects.
112
132
113
133
For standard (Gregorian) calendars, this function uses vectorized
114
- operations, which makes it much faster than netCDF4 .num2date. In such a
134
+ operations, which makes it much faster than netcdftime .num2date. In such a
115
135
case, the returned array will be of type np.datetime64.
116
136
117
137
Note that time unit in `units` must not be smaller than microseconds and
118
138
not larger than days.
119
139
120
140
See also
121
141
--------
122
- netCDF4 .num2date
142
+ netcdftime .num2date
123
143
"""
124
144
num_dates = np .asarray (num_dates )
125
145
flat_num_dates = num_dates .ravel ()
@@ -137,7 +157,7 @@ def decode_cf_datetime(num_dates, units, calendar=None):
137
157
ref_date = pd .Timestamp (ref_date )
138
158
except ValueError :
139
159
# ValueError is raised by pd.Timestamp for non-ISO timestamp
140
- # strings, in which case we fall back to using netCDF4
160
+ # strings, in which case we fall back to using netcdftime
141
161
raise OutOfBoundsDatetime
142
162
143
163
# fixes: https://github.com/pydata/pandas/issues/14068
@@ -155,9 +175,8 @@ def decode_cf_datetime(num_dates, units, calendar=None):
155
175
ref_date ).values
156
176
157
177
except (OutOfBoundsDatetime , OverflowError ):
158
- dates = _decode_datetime_with_netcdf4 (flat_num_dates .astype (np .float ),
159
- units ,
160
- calendar )
178
+ dates = _decode_datetime_with_netcdftime (
179
+ flat_num_dates .astype (np .float ), units , calendar )
161
180
162
181
return dates .reshape (num_dates .shape )
163
182
@@ -215,7 +234,7 @@ def infer_timedelta_units(deltas):
215
234
216
235
217
236
def nctime_to_nptime (times ):
218
- """Given an array of netCDF4 .datetime objects, return an array of
237
+ """Given an array of netcdftime .datetime objects, return an array of
219
238
numpy.datetime64 objects of the same size"""
220
239
times = np .asarray (times )
221
240
new = np .empty (times .shape , dtype = 'M8[ns]' )
@@ -235,20 +254,20 @@ def _cleanup_netcdf_time_units(units):
235
254
return units
236
255
237
256
238
- def _encode_datetime_with_netcdf4 (dates , units , calendar ):
239
- """Fallback method for encoding dates using netCDF4-python .
257
+ def _encode_datetime_with_netcdftime (dates , units , calendar ):
258
+ """Fallback method for encoding dates using netcdftime .
240
259
241
260
This method is more flexible than xarray's parsing using datetime64[ns]
242
261
arrays but also slower because it loops over each element.
243
262
"""
244
- import netCDF4 as nc4
263
+ nctime = _import_netcdftime ()
245
264
246
265
if np .issubdtype (dates .dtype , np .datetime64 ):
247
266
# numpy's broken datetime conversion only works for us precision
248
267
dates = dates .astype ('M8[us]' ).astype (datetime )
249
268
250
269
def encode_datetime (d ):
251
- return np .nan if d is None else nc4 .date2num (d , units , calendar )
270
+ return np .nan if d is None else nctime .date2num (d , units , calendar )
252
271
253
272
return np .vectorize (encode_datetime )(dates )
254
273
@@ -268,7 +287,7 @@ def encode_cf_datetime(dates, units=None, calendar=None):
268
287
269
288
See also
270
289
--------
271
- netCDF4 .date2num
290
+ netcdftime .date2num
272
291
"""
273
292
dates = np .asarray (dates )
274
293
@@ -283,7 +302,7 @@ def encode_cf_datetime(dates, units=None, calendar=None):
283
302
delta , ref_date = _unpack_netcdf_time_units (units )
284
303
try :
285
304
if calendar not in _STANDARD_CALENDARS or dates .dtype .kind == 'O' :
286
- # parse with netCDF4 instead
305
+ # parse with netcdftime instead
287
306
raise OutOfBoundsDatetime
288
307
assert dates .dtype == 'datetime64[ns]'
289
308
@@ -293,7 +312,7 @@ def encode_cf_datetime(dates, units=None, calendar=None):
293
312
num = (dates - ref_date ) / time_delta
294
313
295
314
except (OutOfBoundsDatetime , OverflowError ):
296
- num = _encode_datetime_with_netcdf4 (dates , units , calendar )
315
+ num = _encode_datetime_with_netcdftime (dates , units , calendar )
297
316
298
317
num = cast_to_int_if_safe (num )
299
318
return (num , units , calendar )
0 commit comments