Skip to content

Commit

Permalink
convert array of netCDF4.datetime objects to numpy.datetime64 array t…
Browse files Browse the repository at this point in the history
…o support virtual_variable indexing, pydata#121
  • Loading branch information
Joe Hamman authored and Alex Kleeman committed May 16, 2014
1 parent ed3143e commit b303744
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 13 deletions.
13 changes: 8 additions & 5 deletions test/test_conventions.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,15 @@ def test_decoded_cf_datetime_array(self):
self.assertEqual(actual.dtype, np.dtype('datetime64[ns]'))
self.assertArrayEqual(actual, expected)

num_dates = [722000, 720000.5]
units = 'days since 0001-01-01 0:0:0'
calendar = 'noleap'
actual = conventions.DecodedCFDatetimeArray(num_dates, units, calendar)
expected = nc4.num2date(num_dates, units, calendar)
self.assertEqual(actual.dtype, np.dtype('O'))
units = 'days since 0001-01-01'
times = pd.date_range('2001-01-01-00', end='2001-07-31-23', freq='H')
noleap_time = nc4.date2num(times.to_pydatetime(), units,
calendar=calendar)
expected = times.values
actual = conventions.decode_cf_datetime(noleap_time, units,
calendar=calendar)
self.assertEqual(actual.dtype, np.dtype('M8[ns]'))
self.assertArrayEqual(actual, expected)

@requires_netCDF4
Expand Down
20 changes: 12 additions & 8 deletions xray/conventions.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ def nan_safe_num2date(num):
if ((calendar not in _STANDARD_CALENDARS
or min_date.year < 1678 or max_date.year >= 2262)
and min_date is not pd.NaT):
dates = nc4.num2date(num_dates, units, calendar)
ncdates = nc4.num2date(num_dates, units, calendar)
dates = nctime_to_nptime(ncdates)
else:
# we can safely use np.datetime64 with nanosecond precision (pandas
# likes ns precision so it can directly make DatetimeIndex objects)
Expand Down Expand Up @@ -144,6 +145,15 @@ def guess_time_units(dates):
return '%s since %s' % (time_unit, dates[0])


def nctime_to_nptime(times):
"""Given an array of netCDF4.datetime objects, return an array of
numpy.datetime64 objects"""
new = np.empty(len(times), dtype='M8[ns]')
for i, t in enumerate(times):
new[i] = np.datetime64(datetime(*t.timetuple()[:6]))
return new


def encode_cf_datetime(dates, units=None, calendar=None):
"""Given an array of datetime objects, returns the tuple `(num, units,
calendar)` suitable for a CF complient time variable.
Expand Down Expand Up @@ -246,13 +256,7 @@ def __init__(self, array, units, calendar=None):

@property
def dtype(self):
if self.calendar is None or self.calendar in _STANDARD_CALENDARS:
# TODO: return the proper dtype (object) for a standard calendar
# that can't be expressed in ns precision. Perhaps we could guess
# this from the units?
return np.dtype('datetime64[ns]')
else:
return np.dtype('O')
return np.dtype('datetime64[ns]')

def __getitem__(self, key):
return decode_cf_datetime(self.array, units=self.units,
Expand Down

0 comments on commit b303744

Please sign in to comment.