def tick_values(self, vmin, vmax): vmin, vmax = mtransforms.nonsingular(vmin, vmax, expander=1e-7, tiny=1e-13) self.ndays = float(abs(vmax - vmin)) utime = cftime.utime(self.date_unit, self.calendar) lower = utime.num2date(vmin) upper = utime.num2date(vmax) resolution, n = self.compute_resolution(vmin, vmax, lower, upper) if resolution == 'YEARLY': # TODO START AT THE BEGINNING OF A DECADE/CENTURY/MILLENIUM as # appropriate. years = self._max_n_locator.tick_values(lower.year, upper.year) ticks = [cftime.datetime(int(year), 1, 1) for year in years] elif resolution == 'MONTHLY': # TODO START AT THE BEGINNING OF A DECADE/CENTURY/MILLENIUM as # appropriate. months_offset = self._max_n_locator.tick_values(0, n) ticks = [] for offset in months_offset: year = lower.year + np.floor((lower.month + offset) / 12) month = ((lower.month + offset) % 12) + 1 ticks.append(cftime.datetime(int(year), int(month), 1)) elif resolution == 'DAILY': # TODO: It would be great if this favoured multiples of 7. days = self._max_n_locator_days.tick_values(vmin, vmax) ticks = [utime.num2date(dt) for dt in days] elif resolution == 'HOURLY': hour_unit = 'hours since 2000-01-01' hour_utime = cftime.utime(hour_unit, self.calendar) in_hours = hour_utime.date2num([lower, upper]) hours = self._max_n_locator.tick_values(in_hours[0], in_hours[1]) ticks = [hour_utime.num2date(dt) for dt in hours] elif resolution == 'MINUTELY': minute_unit = 'minutes since 2000-01-01' minute_utime = cftime.utime(minute_unit, self.calendar) in_minutes = minute_utime.date2num([lower, upper]) minutes = self._max_n_locator.tick_values(in_minutes[0], in_minutes[1]) ticks = [minute_utime.num2date(dt) for dt in minutes] elif resolution == 'SECONDLY': second_unit = 'seconds since 2000-01-01' second_utime = cftime.utime(second_unit, self.calendar) in_seconds = second_utime.date2num([lower, upper]) seconds = self._max_n_locator.tick_values(in_seconds[0], in_seconds[1]) ticks = [second_utime.num2date(dt) for dt in seconds] else: msg = 'Resolution {} not implemented yet.'.format(resolution) raise ValueError(msg) return utime.date2num(ticks)
def list_class4_forecasts(class4_id: str) -> List[dict]: """Get list of all forecasts for a given class4 id. Arguments: * `class4_id` -- {str} Class4 ID (e.g. `class4_20190501_GIOPS_CONCEPTS_2.3_profile_343`) Returns: List of dictionaries with `id` and `name` fields. """ dataset_url = current_app.config["CLASS4_FNAME_PATTERN"] % ( class4_id[7:11], class4_id.rsplit('_', maxsplit=1)[0]) with xr.open_dataset(dataset_url, decode_times=False) as ds: forecast_date = [ f"{d:%d %B %Y}" for d in cftime.utime(ds.modeljuld.units).num2date(ds.modeljuld) ] result = [{ 'id': 'best', 'name': 'Best Estimate', }] if len(set(forecast_date)) > 1: for idx, date in enumerate(forecast_date): if result[-1]['name'] == date: continue result.append({'id': idx, 'name': date}) return result
def check(self, max_n_ticks, num1, num2): locator = NetCDFTimeDateLocator(max_n_ticks=max_n_ticks, calendar=self.calendar, date_unit=self.date_unit) utime = cftime.utime(self.date_unit, self.calendar) return locator.compute_resolution(num1, num2, utime.num2date(num1), utime.num2date(num2))
def get_list_dates_from_nc(nc, type_dates): ''' Returns list of dates from NetCDF dataset. :param nc: NetCDF dataset :type nc: netCDF4.Dataset :param type_dates: type of dates ('dt' for datetime objects, 'num' for float objects) :type type_dates: str :rtype: list of datetime/float ''' var_time = nc.variables['time'] time_units = var_time.units # str (ex.: 'days since 1850-01-01 00:00:00') try: time_calend = var_time.calendar # str (ex.: 'standard'/'gregorian'/...) except: time_calend = 'gregorian' if type_dates == 'num': arr_dt = var_time[:] list_dt = arr_dt.tolist() # numpy array -> list if type_dates == 'dt': t = cftime.utime(time_units, time_calend) arr_dt = t.num2date(var_time[:]) list_dt = arr_dt.tolist() # numpy array -> list del arr_dt return list_dt
def day_number_to_datetime_array(time_in, calendar_type, units_in): cdftime = utime(units_in, calendar=calendar_type) date_out = cdftime.num2date(time_in) return date_out
def _get_time_range(year, months, calendar='proleptic_gregorian'): """ Creates a start and end date (a datetime.date timestamp) for a given year and a list of months. If the list of months overlaps into the following year (for example [11,12,1,2,3,4]) then the end date adds 1 to the original year """ #start_date = datetime.datetime(year, months[0], 1) #print 'get_time_range ',start_date start_date = cftime.datetime(year, months[0], 1) cdftime = cftime.utime('hours since 1950-01-01 00:00:00', calendar=calendar) t = cdftime.date2num(start_date) t1 = cdftime.num2date(t) end_year = year end_month = months[-1] + 1 if months[-1] + 1 < months[0] or months[-1] + 1 == 13 or len(months) >= 12: end_year = year + 1 if months[-1] + 1 == 13: end_month = 1 #end_date = datetime.datetime(end_year, end_month, 1) end_date = cftime.datetime(end_year, end_month, 1) t = cdftime.date2num(end_date) t2 = cdftime.num2date(t) return t1, t2
def _get_source_timedata(self, grid, t_adjust): """ Get the source time data information. builds up sourcedata objects of a given grid """ dir_list = self._get_dir_list(grid) group = GridGroup() group.data_list = [] group.time_counter = [] group.date_counter = [] for filename in dir_list: nc = Dataset(filename, 'r') varid = nc.variables['time_counter'] for index in range(0, len(varid)): x = [filename, index] group.data_list.append(x) group.time_counter.append(varid[index] + t_adjust) group.date_counter.append( utime(varid.units, varid.calendar).num2date(varid[index] + t_adjust)) group.units = varid.units group.calendar = varid.calendar nc.close() tmp_data_list = copy.deepcopy(group.data_list) tmp_time_counter = copy.deepcopy(group.time_counter) for index in range(len(group.time_counter)): tmp_data_list[index] = group.data_list[index] tmp_time_counter[index] = group.time_counter[index] group.data_list = tmp_data_list group.time_counter = tmp_time_counter return group
def test_multidim_sequence(self): utime = cftime.utime('seconds since 1970-01-01', 'gregorian') nums = [[20., 40., 60.], [80, 100., 120.]] exp_shape = (2, 3) res = _num2date_to_nearest_second(nums, utime) self.assertEqual(exp_shape, res.shape)
def get_time_range(files, time_range=None, temporal_var_name='time'): ''' If time_range is None, this function will get a time range from input files. Else, this function will adjust the time_range by setting hour value to datetime.datetime objects. :param files: netCDF file(s) (including OPeNDAP URL(s)) :type files: list of str :param time_range: time_range (default: None) :type time_range: list two datetime objects: [begin, end] :param temporal_var_name: name of temporal variable from netCDF file (default: "time") :type temporal_var_name: str :rtype Returns a time range: a list two datetime objects: [begin, end], where "begin" is the first date, and "end" is the last. ''' try: nc = Dataset(files[0], 'r') except RuntimeError: raise MissingIcclimInputError("Failed to access dataset: " + files[0]) time = nc.variables[temporal_var_name] try: calend = time.calendar except: calend = 'gregorian' units = time.units t = cftime.utime(units, calend) any_dt = t.num2date(time[0]) nc.close() if time_range != None: time_range = harmonize_hourly_timestamp(time_range, calend, any_dt) else: try: nc = MFDataset(files, 'r', aggdim='time') except RuntimeError: raise MissingIcclimInputError("Failed to access dataset: " + files) time_arr = nc.variables[temporal_var_name][:] nc.close() begin_num = min(time_arr) end_num = max(time_arr) begin_dt = num2date(begin_num, calend, units) end_dt = num2date(end_num, calend, units) time_range = [begin_dt, end_dt] return time_range
def __new__(self, ncfile, name='time', units=None, calendar='standard'): self._nc = pyroms.io.Dataset(ncfile) data = self._nc.variables[name][:] data = data.view(time) if units == None: units = self._nc.variables[name].units data.utime = cftime.utime(units, calendar=calendar) return data
def test_masked_ndarray(self): utime = cftime.utime('seconds since 1970-01-01', 'gregorian') nums = np.ma.masked_array([20., 40., 60.], [False, True, False]) exp = [datetime.datetime(1970, 1, 1, 0, 0, 20), None, datetime.datetime(1970, 1, 1, 0, 1)] res = _num2date_to_nearest_second(nums, utime) np.testing.assert_array_equal(exp, res)
def _get_source_timedata(self, grid, t_adjust): """ Get the source time data information. builds up sourcedata objects of a given grid """ timevar = grid[self.time_counter] grid.time_counter = timevar[:] + t_adjust grid.date_counter = [] for index in range(0, len(grid.time_counter)): grid.date_counter.append( utime(grid.units, grid.calendar).num2date(grid.time_counter[index]))
def _get_time_axis(filename, means=False): """Get a utime based at the actual start date of the data.""" _STEP = 3 # Time step length (hours). _SPD = 24 // _STEP # Steps per day. with nc.Dataset(filename, "r") as ncid: t = ncid.variables["time"] ut = utime(t.units, t.calendar) t0 = ut.num2date(t[0]) t1 = ut.num2date(t[-1]) units = "days since {} 00:00:00".format(t0.strftime("%Y-%m-%d")) ut_out = utime(units, ut.calendar) pad_beg = t0.hour // _STEP pad_end = (_SPD - 1) - (t1.hour // _STEP) % _SPD return ut_out, (pad_beg, pad_end)
def test_yearly_yr0_remove(self): for calendar in self.all_calendars: # convert values to dates, check that none of them has year 0 num2date = cftime.utime(self.date_unit, calendar).num2date ticks = self.check(5, 0, 100 * 365, calendar) year_ticks = [num2date(t).year for t in ticks] if calendar in self.yr0_remove_calendars: self.assertNotIn(0, year_ticks) else: self.assertIn(0, year_ticks)
def test_sequence(self): utime = cftime.utime('seconds since 1970-01-01', 'gregorian') nums = [20., 40., 60., 80, 100.] exp = [datetime.datetime(1970, 1, 1, 0, 0, 20), datetime.datetime(1970, 1, 1, 0, 0, 40), datetime.datetime(1970, 1, 1, 0, 1), datetime.datetime(1970, 1, 1, 0, 1, 20), datetime.datetime(1970, 1, 1, 0, 1, 40)] res = _num2date_to_nearest_second(nums, utime) np.testing.assert_array_equal(exp, res)
def test_extract_conversion_factors_from_string(self): u = utime('hours since 1970-01-01 00:00:00') t_origin = api.Calendar(int(u.tzoffset)).time( api.YMDhms(int(u.origin.year), int(u.origin.month), int(u.origin.day), int(u.origin.hour), int(u.origin.minute), int(u.origin.second))) delta_t_dic = { 'days': api.deltahours(24), 'hours': api.deltahours(1), 'minutes': api.deltaminutes(1) } delta_t = delta_t_dic[u.units] self.assertIsNotNone(u) self.assertEqual(delta_t, api.deltahours(1)) self.assertEqual(t_origin, 0)
def get_list_dates(ifile, type_dates): ''' Returns list of dates from one file. :param ifile: NetCDF file :type ifile: str :param type_dates: type of dates ('dt' for datetime objects, 'num' for float objects) :type type_dates: str :rtype: list of datetime/float ''' try: nc = Dataset(ifile, 'r') except RuntimeError: raise MissingIcclimInputError("Failed to access dataset: " + ifile) var_time = nc.variables['time'] time_units = var_time.units # str (ex.: 'days since 1850-01-01 00:00:00') try: time_calend = var_time.calendar # str (ex.: 'standard'/'gregorian'/...) except: time_calend = 'gregorian' if type_dates == 'num': arr_dt = var_time[:] list_dt = arr_dt.tolist() # numpy array -> list del arr_dt if type_dates == 'dt': try: arr_dt = cftime.num2date(var_time[:], units=time_units, calendar=time_calend) list_dt = arr_dt.tolist() del arr_dt except: t = cftime.utime(time_units, time_calend) list_dt = [ cftime.num2date(var_time_i, units=time_units, calendar=time_calend) for var_time_i in var_time ] #list_dt = arr_dt.tolist() # numpy array -> list nc.close() return list_dt
def datetime_to_timestamp(datetime: datetime.datetime, time_units: str): """Converts a given datetime object and time units string into a netcdf timestamp integer with UTC encoding. Arguments: datetime {datetime.datetime} -- some datetime object time_units {str} -- time units (e.g. 'seconds since 1950-01-01 00:00:00') Returns: [int] -- timestamp integer """ t = cftime.utime(time_units) datetime = datetime.replace(tzinfo=pytz.UTC) return t.date2num(datetime)
def get_nc_time(nc_filepath): """ Extract the netCDF time as pandas Timestamp or return NaT if the time can't be parsed """ try: with Dataset(nc_filepath) as f: time_var = f.variables['time'] time_raw = time_var[-1] time_units = time_var.units time_calendar = getattr(time_var, 'calendar', 'gregorian') time_conv = utime(time_units, time_calendar) return pd.to_datetime(time_conv.num2date(time_raw)) except Exception as e: print(str(e)) return pd.NaT
def asc_events_read(file_in): """ Read an existing dry spell events file and return it as a list of event.Event objects. Parameters ---------- file_in : str Name of file containing a catalogue dry spell events in the format written by file_io.asc_events_write(). Returns ------- events : list of lists of <event.Event> instances List of dry spell events. ut_events : <cftime.utime> instance Base time of the dry spells in events. The start_index of each Event is associated with this base time. """ with open(file_in, "r") as fi: logger.info("Reading dry spell events from %s", file_in) basetime, calendar = fi.readline().split(",") ut_events = utime(basetime, calendar=calendar.strip()) nland = int(fi.readline()) events = [] nevents = [int(n.strip()) for n in fi.readline().split(",")] for n in nevents: logger.info(fi.readline()) events_sub = [[] for _ in range(nland)] for _ in range(n): line = fi.readline().split(",") args = (int(line[0]), int(line[1]), ut_events, int(line[2]), float(line[3])) E = Event(*args) events_sub[E.land].append(E) events.append(events_sub) return events, ut_events
def date2num(dt, calend, units): ''' Converts datetime object to numerical date. :param dt: datetime object :type dt: datetime.datetime object :param calend: calendar attribute of variable "time" in netCDF file :type calend: str :param units: units of variable "time" in netCDF file :type units: str :rtype: float ''' t = cftime.utime(units, calend) dt_num = t.date2num(dt) return dt_num
def num2date(num, calend, units): ''' Converts numerical date to datetime object. :param num: numerical date :type num: float :param calend: calendar attribute of variable "time" in netCDF file :type calend: str :param units: units of variable "time" in netCDF file :type units: str :rtype: datetime.datetime object ''' t = cftime.utime(units, calend) dt = t.num2date(num) return dt
def convert(cls, value, unit, axis): """ Converts value, if it is not already a number or sequence of numbers, with :func:`cftime.utime().date2num`. """ shape = None if isinstance(value, np.ndarray): # Don't do anything with numeric types. if value.dtype != np.object: return value shape = value.shape value = value.reshape(-1) first_value = value[0] else: # Don't do anything with numeric types. if munits.ConversionInterface.is_numlike(value): return value first_value = value if not isinstance(first_value, (CalendarDateTime, cftime.datetime)): raise ValueError('The values must be numbers or instances of ' '"nc_time_axis.CalendarDateTime" or ' '"cftime.datetime".') if isinstance(first_value, CalendarDateTime): if not isinstance(first_value.datetime, cftime.datetime): raise ValueError('The datetime attribute of the ' 'CalendarDateTime object must be of type ' '`cftime.datetime`.') ut = cftime.utime(cls.standard_unit, calendar=first_value.calendar) if isinstance(value, (CalendarDateTime, cftime.datetime)): value = [value] if isinstance(first_value, CalendarDateTime): result = ut.date2num([v.datetime for v in value]) else: result = ut.date2num(value) if shape is not None: result = result.reshape(shape) return result
def drifters_time(drifter_id): drifters = drifter_id.split(",") mins = [] maxes = [] for d in drifters: with Dataset(current_app.config["DRIFTER_URL"] % d, 'r') as ds: var = ds['data_date'] ut = cftime.utime(var.units) mins.append(ut.num2date(var[:].min())) maxes.append(ut.num2date(var[:].max())) min_time = np.amin(mins) max_time = np.amax(maxes) return { 'min': min_time.isoformat(), 'max': max_time.isoformat(), }
def convert_netcdf_time(time_spec, t): """ Converts supplied numpy array to shyft time given netcdf time_spec. Throws exception if time-unit is not supported, i.e. not part of delta_t_dic as specified in this file. Parameters ---------- time_spec: string from netcdef like 'hours since 1970-01-01 00:00:00' t: numpy array Returns ------- numpy array type int64 with new shyft time units (seconds since 1970utc) """ u = utime(time_spec) t_origin = api.Calendar(int(u.tzoffset)).time(u.origin.year, u.origin.month, u.origin.day, u.origin.hour, u.origin.minute, u.origin.second).seconds delta_t = delta_t_dic[u.units] return t_origin + delta_t * t[:].astype(np.int64)
def list_class4_forecasts(class4_id): # Expecting specific class4 ID format: "class4_YYYMMDD_*.nc" dataset_url = current_app.config["CLASS4_FNAME_PATTERN"] % ( class4_id[7:11], class4_id) with xr.open_dataset(dataset_url) as ds: var = ds['modeljuld'] forecast_date = [ d.strftime("%d %B %Y") for d in cftime.utime(var.units).num2date(var[:]) ] res = [{ 'id': 'best', 'name': 'Best Estimate', }] if len(set(forecast_date)) > 1: for idx, date in enumerate(forecast_date): if res[-1]['name'] == date: continue res.append({'id': idx, 'name': date}) return res
def setUp(self): self.cdftime_mixed = utime('hours since 0001-01-01 00:00:00') self.cdftime_julian = utime( 'hours since 0001-01-01 00:00:00', calendar='julian') self.cdftime_mixed_tz = utime('hours since 0001-01-01 00:00:00 -06:00') self.cdftime_pg = utime('seconds since 0001-01-01 00:00:00', calendar='proleptic_gregorian') self.cdftime_noleap = utime( 'days since 1600-02-28 00:00:00', calendar='noleap') self.cdftime_leap = utime( 'days since 1600-02-29 00:00:00', calendar='all_leap') self.cdftime_360day = utime( 'days since 1600-02-30 00:00:00', calendar='360_day') self.cdftime_jul = utime( 'hours since 1000-01-01 00:00:00', calendar='julian') self.cdftime_iso = utime("seconds since 1970-01-01T00:00:00Z") self.cdftime_leading_space = utime("days since 850-01-01 00:00:00") self.cdftime_mixed_capcal = utime('hours since 0001-01-01 00:00:00', calendar='Standard') self.cdftime_noleap_capcal = utime( 'days since 1600-02-28 00:00:00', calendar='NOLEAP')
def read_ut_var(file_var): """Return a cftime.utime from a netCDF file 'time' coord.""" with nc.Dataset(file_var, "r") as ncid: tim = ncid.variables["time"] ut_var = utime(tim.units, calendar=tim.calendar) return ut_var
def test_scalar(self): utime = cftime.utime('seconds since 1970-01-01', 'gregorian') num = 5. exp = datetime.datetime(1970, 1, 1, 0, 0, 5) res = _num2date_to_nearest_second(num, utime) self.assertEqual(exp, res)
def setup_units(self, calendar): self.useconds = cftime.utime('seconds since 1970-01-01', calendar) self.uminutes = cftime.utime('minutes since 1970-01-01', calendar) self.uhours = cftime.utime('hours since 1970-01-01', calendar) self.udays = cftime.utime('days since 1970-01-01', calendar)
def runTest(self): """testing netcdftime""" # test mixed julian/gregorian calendar # check attributes. self.assertTrue(self.cdftime_mixed.units == 'hours') self.assertTrue( str(self.cdftime_mixed.origin) == '0001-01-01 00:00:00') self.assertTrue( self.cdftime_mixed.unit_string == 'hours since 0001-01-01 00:00:00') self.assertTrue(self.cdftime_mixed.calendar == 'standard') # check date2num method. (date before switch) d = datetime(1582, 10, 4, 23) t1 = self.cdftime_mixed.date2num(d) assert_almost_equal(t1, 13865687.0) # check num2date method. d2 = self.cdftime_mixed.num2date(t1) self.assertTrue(str(d) == str(d2)) # this is a non-existant date, should raise ValueError. d = datetime(1582, 10, 5, 0) self.assertRaises(ValueError, self.cdftime_mixed.date2num, d) # check date2num/num2date with date after switch. d = datetime(1582, 10, 15, 0) t2 = self.cdftime_mixed.date2num(d) assert_almost_equal(t2, 13865688.0) d2 = self.cdftime_mixed.num2date(t2) self.assertTrue(str(d) == str(d2)) # check day of year. ndayr = d.timetuple()[7] self.assertTrue(ndayr == 288) # test using numpy arrays. t = numpy.arange(t2, t2 + 240.0, 12.) t = numpy.reshape(t, (4, 5)) d = self.cdftime_mixed.num2date(t) self.assertTrue(d.shape == t.shape) d_check = "1582-10-15 00:00:001582-10-15 12:00:001582-10-16 00:00:001582-10-16 12:00:001582-10-17 00:00:001582-10-17 12:00:001582-10-18 00:00:001582-10-18 12:00:001582-10-19 00:00:001582-10-19 12:00:001582-10-20 00:00:001582-10-20 12:00:001582-10-21 00:00:001582-10-21 12:00:001582-10-22 00:00:001582-10-22 12:00:001582-10-23 00:00:001582-10-23 12:00:001582-10-24 00:00:001582-10-24 12:00:00" d2 = [str(dd) for dd in d.flat] self.assertTrue(d_check == ''.join(d2)) # test julian calendar with numpy arrays d = self.cdftime_julian.num2date(t) self.assertTrue(d.shape == t.shape) d_check = "1582-10-05 00:00:001582-10-05 12:00:001582-10-06 00:00:001582-10-06 12:00:001582-10-07 00:00:001582-10-07 12:00:001582-10-08 00:00:001582-10-08 12:00:001582-10-09 00:00:001582-10-09 12:00:001582-10-10 00:00:001582-10-10 12:00:001582-10-11 00:00:001582-10-11 12:00:001582-10-12 00:00:001582-10-12 12:00:001582-10-13 00:00:001582-10-13 12:00:001582-10-14 00:00:001582-10-14 12:00:00" d2 = [str(dd) for dd in d.flat] self.assertTrue(d_check == ''.join(d2)) # test proleptic gregorian calendar. self.assertTrue(self.cdftime_pg.units == 'seconds') self.assertTrue(str(self.cdftime_pg.origin) == '0001-01-01 00:00:00') self.assertTrue( self.cdftime_pg.unit_string == 'seconds since 0001-01-01 00:00:00') self.assertTrue(self.cdftime_pg.calendar == 'proleptic_gregorian') # check date2num method. d = datetime(1990, 5, 5, 2, 17) t1 = numpy.around(self.cdftime_pg.date2num(d)) self.assertTrue(t1 == 62777470620.0) # check num2date method. d2 = self.cdftime_pg.num2date(t1) self.assertTrue(str(d) == str(d2)) # check day of year. ndayr = d.timetuple()[7] self.assertTrue(ndayr == 125) # check noleap calendar. # this is a non-existant date, should raise ValueError. self.assertRaises( ValueError, utime, 'days since 1600-02-29 00:00:00', calendar='noleap') self.assertTrue(self.cdftime_noleap.units == 'days') self.assertTrue( str(self.cdftime_noleap.origin) == '1600-02-28 00:00:00') self.assertTrue( self.cdftime_noleap.unit_string == 'days since 1600-02-28 00:00:00') self.assertTrue(self.cdftime_noleap.calendar == 'noleap') assert_almost_equal( self.cdftime_noleap.date2num(self.cdftime_noleap.origin), 0.0) # check date2num method. d1 = datetime(2000, 2, 28) d2 = datetime(1600, 2, 28) t1 = self.cdftime_noleap.date2num(d1) t2 = self.cdftime_noleap.date2num(d2) assert_almost_equal(t1, 400 * 365.) assert_almost_equal(t2, 0.) t12 = self.cdftime_noleap.date2num([d1, d2]) assert_almost_equal(t12, [400 * 365., 0]) # check num2date method. d2 = self.cdftime_noleap.num2date(t1) self.assertTrue(str(d1) == str(d2)) # check day of year. ndayr = d2.timetuple()[7] self.assertTrue(ndayr == 59) # non-existant date, should raise ValueError. date = datetime(2000, 2, 29) self.assertRaises(ValueError, self.cdftime_noleap.date2num, date) # check all_leap calendar. self.assertTrue(self.cdftime_leap.units == 'days') self.assertTrue( str(self.cdftime_leap.origin) == '1600-02-29 00:00:00') self.assertTrue( self.cdftime_leap.unit_string == 'days since 1600-02-29 00:00:00') self.assertTrue(self.cdftime_leap.calendar == 'all_leap') assert_almost_equal( self.cdftime_leap.date2num(self.cdftime_leap.origin), 0.0) # check date2num method. d1 = datetime(2000, 2, 29) d2 = datetime(1600, 2, 29) t1 = self.cdftime_leap.date2num(d1) t2 = self.cdftime_leap.date2num(d2) assert_almost_equal(t1, 400 * 366.) assert_almost_equal(t2, 0.) # check num2date method. d2 = self.cdftime_leap.num2date(t1) self.assertTrue(str(d1) == str(d2)) # check day of year. ndayr = d2.timetuple()[7] self.assertTrue(ndayr == 60) # double check date2num,num2date methods. d = datetime(2000, 12, 31) t1 = self.cdftime_mixed.date2num(d) d2 = self.cdftime_mixed.num2date(t1) self.assertTrue(str(d) == str(d2)) ndayr = d2.timetuple()[7] self.assertTrue(ndayr == 366) # check 360_day calendar. self.assertTrue(self.cdftime_360day.units == 'days') self.assertTrue( str(self.cdftime_360day.origin) == '1600-02-30 00:00:00') self.assertTrue( self.cdftime_360day.unit_string == 'days since 1600-02-30 00:00:00') self.assertTrue(self.cdftime_360day.calendar == '360_day') assert_almost_equal( self.cdftime_360day.date2num(self.cdftime_360day.origin), 0.0) # check date2num,num2date methods. # use datetime from netcdftime, since this date doesn't # exist in "normal" calendars. d = datetimex(2000, 2, 30) t1 = self.cdftime_360day.date2num(d) assert_almost_equal(t1, 360 * 400.) d2 = self.cdftime_360day.num2date(t1) assert_equal(str(d), str(d2)) # check day of year. d = datetime(2001, 12, 30) t = self.cdftime_360day.date2num(d) assert_almost_equal(t, 144660.0) date = self.cdftime_360day.num2date(t) self.assertTrue(str(d) == str(date)) ndayr = date.timetuple()[7] self.assertTrue(ndayr == 360) # Check fraction d = datetime(1969, 12, 30, 12) t = self.cdftime_360day.date2num(d) date = self.cdftime_360day.num2date(t) assert_equal(str(d), str(date)) # test proleptic julian calendar. d = datetime(1858, 11, 17, 12) t = self.cdftime_jul.date2num(d) assert_almost_equal(t, 7528932.0) d1 = datetime(1582, 10, 4, 23) d2 = datetime(1582, 10, 15, 0) assert_almost_equal( self.cdftime_jul.date2num(d1) + 241.0, self.cdftime_jul.date2num(d2)) date = self.cdftime_jul.num2date(t) self.assertTrue(str(d) == str(date)) # test julian day from date, date from julian day d = datetime(1858, 11, 17) mjd = JulianDayFromDate(d) assert_almost_equal(mjd, 2400000.5) date = DateFromJulianDay(mjd) self.assertTrue(str(date) == str(d)) # test iso 8601 units string d = datetime(1970, 1, 1, 1) t = self.cdftime_iso.date2num(d) assert_equal(numpy.around(t), 3600) # test fix for issue 75 (seconds hit 60 at end of month, # day goes out of range). t = 733499.0 d = num2date(t, units='days since 0001-01-01 00:00:00') dateformat = '%Y-%m-%d %H:%M:%S' assert_equal(d.strftime(dateformat), '2009-04-01 00:00:00') # test edge case of issue 75 for numerical problems for t in (733498.999, 733498.9999, 733498.99999, 733498.999999, 733498.9999999): d = num2date(t, units='days since 0001-01-01 00:00:00') t2 = date2num(d, units='days since 0001-01-01 00:00:00') assert(abs(t2 - t) < 1e-5) # values should be less than second # Check equality testing d1 = datetimex(1979, 6, 21, 9, 23, 12) d2 = datetime(1979, 6, 21, 9, 23, 12) assert(d1 == d2) # check timezone offset d = datetime(2012, 2, 29, 15) # mixed_tz is -6 hours from UTC, mixed is UTC so # difference in elapsed time is -6 hours. assert(self.cdftime_mixed_tz.date2num( d) - self.cdftime_mixed.date2num(d) == -6) # Check comparisons with Python datetime types # Note that d1 has to use the proleptic Gregorian calendar to # be comparable to d2: datetime.datetime uses the proleptic # Gregorian calendar and year 1000 is before the # Julian/Gregorian transition (1582-10-15). d1 = num2date(0, 'days since 1000-01-01', 'proleptic_gregorian') d2 = datetime(2000, 1, 1) # The date d3 is well after the Julian/Gregorian transition # and so this Gregorian date can be compared to the proleptic # Gregorian date d2. d3 = num2date(0, 'days since 3000-01-01', 'standard') assert d1 < d2 assert d2 < d3 # check all comparisons assert d1 != d2 assert d1 <= d2 assert d2 > d1 assert d2 >= d1 # check datetime hash d1 = datetimex(1995, 1, 1) d2 = datetime(1995, 1, 1) d3 = datetimex(2001, 2, 30) assert hash(d1) == hash(d1) assert hash(d1) == hash(d2) assert hash(d1) != hash(d3) assert hash(d3) == hash(d3) # check datetime immutability # using assertRaises as a context manager # only works with python >= 2.7 (issue #497). immutability_tests = {"year": 1999, "month": 6, "day": 5, "hour": 10, "minute": 33, "second": 45, "dayofwk": 1, "dayofyr": 52, "format": '%Y'} for name, value in immutability_tests.items(): self.assertRaises(AttributeError, setattr, d1, name, value) # Check leading white space self.assertEqual( str(self.cdftime_leading_space.origin), '0850-01-01 00:00:00') #issue 330 units = "seconds since 1970-01-01T00:00:00Z" t = utime(units) for n in range(10): assert n == int(round(t.date2num(t.num2date(n)))) #issue 344 units = 'hours since 2013-12-12T12:00:00' assert(1.0 == date2num(num2date(1.0, units), units)) # test rountrip accuracy # also tests error found in issue #349 calendars=['standard', 'gregorian', 'proleptic_gregorian', 'noleap', 'julian',\ 'all_leap', '365_day', '366_day', '360_day'] dateformat = '%Y-%m-%d %H:%M:%S' dateref = datetime(2015,2,28,12) ntimes = 1001 for calendar in calendars: eps = 100. units = 'microseconds since 1800-01-30 01:01:01' microsecs1 = date2num(dateref,units,calendar=calendar) for n in range(ntimes): microsecs1 += 1. date1 = num2date(microsecs1, units, calendar=calendar) microsecs2 = date2num(date1, units, calendar=calendar) date2 = num2date(microsecs2, units, calendar=calendar) err = numpy.abs(microsecs1 - microsecs2) assert(err < eps) assert(date1.strftime(dateformat) == date2.strftime(dateformat)) units = 'milliseconds since 1800-01-30 01:01:01' eps = 0.1 millisecs1 = date2num(dateref,units,calendar=calendar) for n in range(ntimes): millisecs1 += 0.001 date1 = num2date(millisecs1, units, calendar=calendar) millisecs2 = date2num(date1, units, calendar=calendar) date2 = num2date(millisecs2, units, calendar=calendar) err = numpy.abs(millisecs1 - millisecs2) assert(err < eps) assert(date1.strftime(dateformat) == date2.strftime(dateformat)) eps = 1.e-4 units = 'seconds since 0001-01-30 01:01:01' secs1 = date2num(dateref,units,calendar=calendar) for n in range(ntimes): secs1 += 0.1 date1 = num2date(secs1, units, calendar=calendar) secs2 = date2num(date1, units, calendar=calendar) date2 = num2date(secs2, units, calendar=calendar) err = numpy.abs(secs1 - secs2) assert(err < eps) assert(date1.strftime(dateformat) == date2.strftime(dateformat)) eps = 1.e-5 units = 'minutes since 0001-01-30 01:01:01' mins1 = date2num(dateref,units,calendar=calendar) for n in range(ntimes): mins1 += 0.01 date1 = num2date(mins1, units, calendar=calendar) mins2 = date2num(date1, units, calendar=calendar) date2 = num2date(mins2, units, calendar=calendar) err = numpy.abs(mins1 - mins2) assert(err < eps) assert(date1.strftime(dateformat) == date2.strftime(dateformat)) eps = 1.e-5 units = 'hours since 0001-01-30 01:01:01' hrs1 = date2num(dateref,units,calendar=calendar) for n in range(ntimes): hrs1 += 0.001 date1 = num2date(hrs1, units, calendar=calendar) hrs2 = date2num(date1, units, calendar=calendar) date2 = num2date(hrs2, units, calendar=calendar) err = numpy.abs(hrs1 - hrs2) assert(err < eps) assert(date1.strftime(dateformat) == date2.strftime(dateformat)) eps = 1.e-5 units = 'days since 0001-01-30 01:01:01' days1 = date2num(dateref,units,calendar=calendar) for n in range(ntimes): days1 += 0.00001 date1 = num2date(days1, units, calendar=calendar) days2 = date2num(date1, units, calendar=calendar) date2 = num2date(days2, units, calendar=calendar) err = numpy.abs(days1 - days2) assert(err < eps) assert(date1.strftime(dateformat) == date2.strftime(dateformat)) # issue 353 assert (num2date(0, 'hours since 2000-01-01 0') == datetime(2000,1,1,0)) # issue 354 num1 = numpy.array([[0, 1], [2, 3]]) num2 = numpy.array([[0, 1], [2, 3]]) dates1 = num2date(num1, 'days since 0001-01-01') dates2 = num2date(num2, 'days since 2001-01-01') assert( dates1.shape == (2,2) ) assert( dates2.shape == (2,2) ) num1b = date2num(dates1, 'days since 0001-01-01') num2b = date2num(dates2, 'days since 2001-01-01') assert( num1b.shape == (2,2) ) assert( num2b.shape == (2,2) ) assert_almost_equal(num1,num1b) assert_almost_equal(num2,num2b) # issue 357 (make sure time zone offset in units done correctly) # Denver time, 7 hours behind UTC units = 'hours since 1682-10-15 -07:00 UTC' # date after gregorian switch, python datetime used date = datetime(1682,10,15) # assumed UTC num = date2num(date,units) # UTC is 7 hours ahead of units, so num should be -7 assert (num == -7) assert (num2date(num, units) == date) units = 'hours since 1482-10-15 -07:00 UTC' # date before gregorian switch, netcdftime datetime used date = datetime(1482,10,15) num = date2num(date,units) date2 = num2date(num, units) assert (num == -7) assert (date2.year == date.year) assert (date2.month == date.month) assert (date2.day == date.day) assert (date2.hour == date.hour) assert (date2.minute == date.minute) assert (date2.second == date.second) # issue 362: case insensitive calendars self.assertTrue(self.cdftime_mixed_capcal.calendar == 'standard') self.assertTrue(self.cdftime_noleap_capcal.calendar == 'noleap') d = datetime(2015, 3, 4, 12, 18, 30) units = 'days since 0001-01-01' for cap_cal, low_cal in (('STANDARD', 'standard'), ('NoLeap', 'noleap'), ('Gregorian', 'gregorian'), ('ALL_LEAP', 'all_leap')): d1 = date2num(d, units, cap_cal) d2 = date2num(d, units, low_cal) self.assertEqual(d1, d2) self.assertEqual(num2date(d1, units, cap_cal), num2date(d1, units, low_cal)) # issue 415 t = datetimex(2001, 12, 1, 2, 3, 4) self.assertEqual(t, copy.deepcopy(t)) # issue 442 units = "days since 0000-01-01 00:00:00" # this should fail (year zero not allowed with real-world calendars) try: date2num(datetime(1, 1, 1), units, calendar='standard') except ValueError: pass # this should not fail (year zero allowed in 'fake' calendars) t = date2num(datetime(1, 1, 1), units, calendar='360_day') self.assertEqual(t, 360) d = num2date(t, units, calendar='360_day') self.assertEqual(d, Datetime360Day(1,1,1)) d = num2date(0, units, calendar='360_day') self.assertEqual(d, Datetime360Day(0,1,1)) # list around missing dates in Gregorian calendar # scalar units = 'days since 0001-01-01 12:00:00' t1 = date2num(datetime(1582, 10, 4), units, calendar='gregorian') t2 = date2num(datetime(1582, 10, 15), units, calendar='gregorian') self.assertEqual(t1+1, t2) # list t1, t2 = date2num([datetime(1582, 10, 4), datetime(1582, 10, 15)], units, calendar='gregorian') self.assertEqual(t1+1, t2) t1, t2 = date2num([datetime(1582, 10, 4), datetime(1582, 10, 15)], units, calendar='standard') self.assertEqual(t1+1, t2) # this should fail: days missing in Gregorian calendar try: t1, t2, t3 = date2num([datetime(1582, 10, 4), datetime(1582, 10, 10), datetime(1582, 10, 15)], units, calendar='standard') except ValueError: pass # test fix for issue #596 - julian day calculations wrong for negative years, # caused incorrect rountrip num2date(date2num(date)) roundtrip for dates with year # < 0. u = utime("seconds since 1-1-1",calendar='julian') date1 = datetimex(-1, 1, 1) date2 = u.num2date(u.date2num(date1)) assert (date2.year == date1.year) assert (date2.month == date1.month) assert (date2.day == date1.day) assert (date2.hour == date1.hour) assert (date2.minute == date1.minute) assert (date2.second == date1.second) assert_almost_equal(JulianDayFromDate(date1), 1721057.5) # issue 596 - negative years fail in utime.num2date u = utime("seconds since 1-1-1", "proleptic_gregorian") d = u.num2date(u.date2num(datetimex(-1, 1, 1))) assert (d.year == -1) assert (d.month == 1) assert (d.day == 1) assert (d.hour == 0) # test fix for issue #659 (proper treatment of negative time values). #units = 'days since 1800-01-01 00:00:0.0' #d = num2date(-657073, units, calendar='standard') #assert (d.year == 1) #assert (d.month == 1) #assert (d.day == 1) #assert (d.hour == 0) # issue 685: wrong time zone conversion # 'The following times all refer to the same moment: "18:30Z", "22:30+04", "1130-0700", and "15:00-03:30' # (https://en.wikipedia.org/w/index.php?title=ISO_8601&oldid=787811367#Time_offsets_from_UTC) # test num2date utc_date = datetime(2000,1,1,18,30) for units in ("hours since 2000-01-01 22:30+04:00", "hours since 2000-01-01 11:30-07:00", "hours since 2000-01-01 15:00-03:30"): d = num2date(0, units, calendar="standard") assert(numpy.abs((d-utc_date).total_seconds()) < 1.e-3) # also test with negative values to cover 2nd code path d = num2date(-1, units, calendar="standard") assert(numpy.abs((d - \ (utc_date-timedelta(hours=1))).total_seconds()) < 1.e-3) n = date2num(utc_date, units, calendar="standard") # n should always be 0 as all units refer to the same point in time self.assertEqual(n, 0) # explicitly test 2nd code path for date2num units = "hours since 2000-01-01 22:30+04:00" n = date2num(utc_date, units, calendar="julian") # n should always be 0 as all units refer to the same point in time assert_almost_equal(n, 0)
def setUp(self): self.converters = {"360_day" : utime("days since 1-1-1", "360_day"), "noleap" : utime("days since 1-1-1", "365_day")}
def setUp(self): self.converters = { "360_day": utime("days since 1-1-1", "360_day"), "noleap": utime("days since 1-1-1", "365_day") }
def __call__(self, x, pos=0): format_string = self.pick_format(ndays=self.locator.ndays) dt = cftime.utime(self.time_units, self.calendar).num2date(x) return dt.strftime(format_string)