diff --git a/esmvalcore/cmor/_fixes/icon/icon.py b/esmvalcore/cmor/_fixes/icon/icon.py index 8a170eb730..5200cfed33 100644 --- a/esmvalcore/cmor/_fixes/icon/icon.py +++ b/esmvalcore/cmor/_fixes/icon/icon.py @@ -270,25 +270,29 @@ def _fix_time(self, cube, cubes): new_t_unit = cf_units.Unit('days since 1850-01-01', calendar='proleptic_gregorian') - # New routine to convert time of daily and hourly data - # The string %f (fraction of day) is not a valid format string - # for datetime.strptime, so we have to convert it ourselves - time_str = [str(x) for x in time_coord.points] - - # First, extract date (year, month, day) from string - # and convert it to datetime object - year_month_day_str = pd.Series(time_str).str.extract( - r'(\d*)\.?\d*', expand=False - ) + # New routine to convert time of daily and hourly data. The string %f + # (fraction of day) is not a valid format string for datetime.strptime, + # so we have to convert it ourselves. + time_str = pd.Series(time_coord.points, dtype=str) + + # First, extract date (year, month, day) from string and convert it to + # datetime object + year_month_day_str = time_str.str.extract(r'(\d*)\.?\d*', expand=False) year_month_day = pd.to_datetime(year_month_day_str, format='%Y%m%d') + # Second, extract day fraction and convert it to timedelta object - day_float_str = pd.Series(time_str).str.extract( + day_float_str = time_str.str.extract( r'\d*(\.\d*)', expand=False ).fillna('0.0') day_float = pd.to_timedelta(day_float_str.astype(float), unit='D') - # Finally, add date and day fraction to get final datetime - # and convert it to correct units - new_datetimes = (year_month_day + day_float).dt.to_pydatetime() + + # Finally, add date and day fraction to get final datetime and convert + # it to correct units. Note: we also round to next second, otherwise + # this results in times that are off by 1s (e.g., 13:59:59 instead of + # 14:00:00). + new_datetimes = (year_month_day + day_float).round( + 'S' + ).dt.to_pydatetime() new_dt_points = date2num(np.array(new_datetimes), new_t_unit) time_coord.points = new_dt_points diff --git a/tests/integration/cmor/_fixes/icon/test_icon.py b/tests/integration/cmor/_fixes/icon/test_icon.py index e7f714beef..87ac889ff2 100644 --- a/tests/integration/cmor/_fixes/icon/test_icon.py +++ b/tests/integration/cmor/_fixes/icon/test_icon.py @@ -1346,13 +1346,13 @@ def test_hourly_data(cubes_2d): """Test fix.""" fix = get_allvars_fix('Amon', 'tas') for cube in cubes_2d: - cube.coord('time').points = [20220314.1] + cube.coord('time').points = [20041104.5833333] fixed_cubes = fix.fix_metadata(cubes_2d) cube = check_tas_metadata(fixed_cubes) date = cube.coord('time').units.num2date(cube.coord('time').points) - np.testing.assert_array_equal(date, [datetime(2022, 3, 14, 2, 24)]) + np.testing.assert_array_equal(date, [datetime(2004, 11, 4, 14, 0)]) assert cube.coord('time').bounds is None