From 5013a2eadedc480ffb51db41c3044bfac9738288 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Thu, 19 Dec 2024 09:12:00 -0700 Subject: [PATCH 1/2] fix correction for no_leap calendar in tests --- CIME/SystemTests/system_tests_common.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CIME/SystemTests/system_tests_common.py b/CIME/SystemTests/system_tests_common.py index 845d09a9bb2..60423e876d4 100644 --- a/CIME/SystemTests/system_tests_common.py +++ b/CIME/SystemTests/system_tests_common.py @@ -225,14 +225,15 @@ def _set_restart_interval( smon = startdatetime.month ryr = restdatetime.year rmon = restdatetime.month - while ryr > syr: - if rmon > 2 and calendar.isleap(ryr): + while ryr > syr and (ryr < restdatetime.year or rmon > 2): + if calendar.isleap(ryr): dayscorrected += 1 ryr = ryr - 1 - if rmon > 2 and smon <= 2: + if rmon > 2 and smon <= 2 or restdatetime.year > syr: if calendar.isleap(syr): dayscorrected += 1 restdatetime = restdatetime + timedelta(days=dayscorrected) + logger.info("correcting calendar for no leap {}".format(dayscorrected)) self._rest_time = ( f".{restdatetime.year:04d}-{restdatetime.month:02d}-{restdatetime.day:02d}-" ) From 42f8ce6e455fee84324e2976e07de2e15c95a1b0 Mon Sep 17 00:00:00 2001 From: Jim Edwards Date: Fri, 20 Dec 2024 11:52:44 -0700 Subject: [PATCH 2/2] add some doc tests for calculating leap year corrections --- CIME/SystemTests/system_tests_common.py | 49 ++++++++++++++++++------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/CIME/SystemTests/system_tests_common.py b/CIME/SystemTests/system_tests_common.py index 60423e876d4..320bc08b283 100644 --- a/CIME/SystemTests/system_tests_common.py +++ b/CIME/SystemTests/system_tests_common.py @@ -219,21 +219,13 @@ def _set_restart_interval( expect(False, f"stop_option {stop_option} not available for this test") restdatetime = startdatetime + rtd + # We are working with python datatime and the model uses a NO_LEAP 365 day calendar + # so we need to correct for leap years if cal == "NO_LEAP": - dayscorrected = 0 - syr = startdatetime.year - smon = startdatetime.month - ryr = restdatetime.year - rmon = restdatetime.month - while ryr > syr and (ryr < restdatetime.year or rmon > 2): - if calendar.isleap(ryr): - dayscorrected += 1 - ryr = ryr - 1 - if rmon > 2 and smon <= 2 or restdatetime.year > syr: - if calendar.isleap(syr): - dayscorrected += 1 - restdatetime = restdatetime + timedelta(days=dayscorrected) - logger.info("correcting calendar for no leap {}".format(dayscorrected)) + restdatetime = restdatetime + self._leap_year_correction( + startdatetime, restdatetime + ) + self._rest_time = ( f".{restdatetime.year:04d}-{restdatetime.month:02d}-{restdatetime.day:02d}-" ) @@ -251,6 +243,35 @@ def _set_restart_interval( return rest_n + @staticmethod + def _leap_year_correction(startdatetime, restdatetime): + """ + Compute correction needed for restdate time if model is using NO_LEAP calendar + + >>> SystemTestsCommon._leap_year_correction(datetime.strptime("20000225","%Y%m%d"), datetime.strptime("20000301","%Y%m%d")) + datetime.timedelta(days=1) + >>> SystemTestsCommon._leap_year_correction(datetime.strptime("20010225","%Y%m%d"), datetime.strptime("20010301","%Y%m%d")) + datetime.timedelta(0) + >>> SystemTestsCommon._leap_year_correction(datetime.strptime("20010225","%Y%m%d"), datetime.strptime("20050301","%Y%m%d")) + datetime.timedelta(days=1) + >>> SystemTestsCommon._leap_year_correction(datetime.strptime("18500101","%Y%m%d"), datetime.strptime("20201231","%Y%m%d")) + datetime.timedelta(days=42) + """ + dayscorrected = 0 + syr = startdatetime.year + smon = startdatetime.month + ryr = syr + rmon = restdatetime.month + while ryr < restdatetime.year: + if calendar.isleap(ryr): + dayscorrected += 1 + ryr = ryr + 1 + if rmon > 2 and smon <= 2 or restdatetime.year > syr: + if calendar.isleap(ryr): + dayscorrected += 1 + logger.info("correcting calendar for no leap {}".format(dayscorrected)) + return timedelta(days=dayscorrected) + def _init_environment(self, caseroot): """ Do initializations of environment variables that are needed in __init__