# Buggy code
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.

    For standard (Gregorian) calendars, this function uses vectorized
    operations, which makes it much faster than netCDF4.num2date. In such a
    case, the returned array will be of type np.datetime64.

    See also
    --------
    netCDF4.num2date
    """
    import netCDF4 as nc4

    num_dates = np.asarray(num_dates).astype(float)
    if calendar is None:
        calendar = "standard"

    def nan_safe_num2date(num):
        return pd.NaT if np.isnan(num) else nc4.num2date(num, units, calendar)

    min_num = np.nanmin(num_dates)
    max_num = np.nanmax(num_dates)
    min_date = nan_safe_num2date(min_num)
    if num_dates.size > 1:
        max_date = nan_safe_num2date(max_num)
    else:
        max_date = min_date

    if (
        calendar not in ["standard", "gregorian", "proleptic_gregorian"]
        or min_date < datetime(1678, 1, 1)
        or max_date > datetime(2262, 4, 11)
    ):
        dates = nc4.num2date(num_dates, units, calendar)
    else:
        # we can safely use np.datetime64 with nanosecond precision (pandas
        # likes ns precision so it can directly make DatetimeIndex objects)
        if pd.isnull(min_num):
            # pandas.NaT doesn't cast to numpy.datetime64('NaT'), so handle it
            # separately
            dates = np.repeat(np.datetime64("NaT"), num_dates.size)
        elif min_num == max_num:
            # we can't safely divide by max_num - min_num
            dates = np.repeat(np.datetime64(min_date), num_dates.size)
            if dates.size > 1:
                # don't bother with one element, since it will be fixed at
                # min_date and isn't indexable anyways
                dates[np.isnan(num_dates)] = np.datetime64("NaT")
        else:
            # Calculate the date as a np.datetime64 array from linear scaling
            # of the max and min dates calculated via num2date.
            flat_num_dates = num_dates.reshape(-1)
            # Use second precision for the timedelta to decrease the chance of
            # a numeric overflow
            time_delta = np.timedelta64(max_date - min_date).astype("m8[s]")
            if time_delta != max_date - min_date:
                raise ValueError(
                    "unable to exactly represent max_date minus"
                    "min_date with second precision"
                )
            # apply the numerator and denominator separately so we don't need
            # to cast to floating point numbers under the assumption that all
            # dates can be given exactly with ns precision
            numerator = flat_num_dates - min_num
            denominator = max_num - min_num
            dates = time_delta * numerator / denominator + np.datetime64(min_date)
        # restore original shape and ensure dates are given in ns
        dates = dates.reshape(num_dates.shape).astype("M8[ns]")
    return dates


# Traceback (TypeError)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-46-65c280e7a283> in <module>()
1 ds = xray.open_dataset('sample_for_xray.nc')
----> 2 print ds['time']

/home/jhamman/anaconda/lib/python2.7/site-packages/xray/common.pyc in __repr__(self)
40
41     def __repr__(self):
---> 42         return array_repr(self)
43
44     def _iter(self):

/home/jhamman/anaconda/lib/python2.7/site-packages/xray/common.pyc in array_repr(arr)
122     summary = ['<xray.%s %s(%s)>'% (type(arr).__name__, name_str, dim_summary)]
123     if arr.size < 1e5 or arr._in_memory():
--> 124         summary.append(repr(arr.values))
125     else:
126         summary.append('[%s values with dtype=%s]' % (arr.size, arr.dtype))

/home/jhamman/anaconda/lib/python2.7/site-packages/xray/data_array.pyc in values(self)
147     def values(self):
148         """The variables's data as a numpy.ndarray"""
--> 149         return self.variable.values
150
151     @values.setter

/home/jhamman/anaconda/lib/python2.7/site-packages/xray/variable.pyc in values(self)
217     def values(self):
218         """The variable's data as a numpy.ndarray"""
--> 219         return utils.as_array_or_item(self._data_cached())
220
221     @values.setter

/home/jhamman/anaconda/lib/python2.7/site-packages/xray/utils.pyc in as_array_or_item(values, dtype)
56         # converted into an integer instead :(
57         return values
---> 58     values = as_safe_array(values, dtype=dtype)
59     if values.ndim == 0 and values.dtype.kind == 'O':
60         # unpack 0d object arrays to be consistent with numpy

/home/jhamman/anaconda/lib/python2.7/site-packages/xray/utils.pyc in as_safe_array(values, dtype)
40     """Like np.asarray, but convert all datetime64 arrays to ns precision
41     """
---> 42     values = np.asarray(values, dtype=dtype)
43     if values.dtype.kind == 'M':
44         # np.datetime64

/home/jhamman/anaconda/lib/python2.7/site-packages/numpy/core/numeric.pyc in asarray(a, dtype, order)
458
459     """
--> 460     return array(a, dtype, copy=False, order=order)
461
462 def asanyarray(a, dtype=None, order=None):

/home/jhamman/anaconda/lib/python2.7/site-packages/xray/variable.pyc in __array__(self, dtype)
121         if dtype is None:
122             dtype = self.dtype
--> 123         return self.array.values.astype(dtype)
124
125     def __getitem__(self, key):

TypeError: Cannot cast datetime.date object from metadata [D] to [ns] according to the rule 'same_kind'

# Fixed code
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.

    For standard (Gregorian) calendars, this function uses vectorized
    operations, which makes it much faster than netCDF4.num2date. In such a
    case, the returned array will be of type np.datetime64.

    See also
    --------
    netCDF4.num2date
    """
    import netCDF4 as nc4

    num_dates = np.asarray(num_dates).astype(float)
    if calendar is None:
        calendar = "standard"

    def nan_safe_num2date(num):
        return pd.NaT if np.isnan(num) else nc4.num2date(num, units, calendar)

    min_num = np.nanmin(num_dates)
    max_num = np.nanmax(num_dates)
    min_date = nan_safe_num2date(min_num)
    if num_dates.size > 1:
        max_date = nan_safe_num2date(max_num)
    else:
        max_date = min_date

    if (
        calendar not in _STANDARD_CALENDARS
        or min_date < datetime(1678, 1, 1)
        or max_date > datetime(2262, 4, 11)
    ):
        dates = nc4.num2date(num_dates, units, calendar)
    else:
        # we can safely use np.datetime64 with nanosecond precision (pandas
        # likes ns precision so it can directly make DatetimeIndex objects)
        if pd.isnull(min_num):
            # pandas.NaT doesn't cast to numpy.datetime64('NaT'), so handle it
            # separately
            dates = np.repeat(np.datetime64("NaT"), num_dates.size)
        elif min_num == max_num:
            # we can't safely divide by max_num - min_num
            dates = np.repeat(np.datetime64(min_date), num_dates.size)
            if dates.size > 1:
                # don't bother with one element, since it will be fixed at
                # min_date and isn't indexable anyways
                dates[np.isnan(num_dates)] = np.datetime64("NaT")
        else:
            # Calculate the date as a np.datetime64 array from linear scaling
            # of the max and min dates calculated via num2date.
            flat_num_dates = num_dates.reshape(-1)
            # Use second precision for the timedelta to decrease the chance of
            # a numeric overflow
            time_delta = np.timedelta64(max_date - min_date).astype("m8[s]")
            if time_delta != max_date - min_date:
                raise ValueError(
                    "unable to exactly represent max_date minus"
                    "min_date with second precision"
                )
            # apply the numerator and denominator separately so we don't need
            # to cast to floating point numbers under the assumption that all
            # dates can be given exactly with ns precision
            numerator = flat_num_dates - min_num
            denominator = max_num - min_num
            dates = time_delta * numerator / denominator + np.datetime64(min_date)
        # restore original shape and ensure dates are given in ns
        dates = dates.reshape(num_dates.shape).astype("M8[ns]")
    return dates