From e356329805ca6f8d74adf7e1e870145b9f1f7efc Mon Sep 17 00:00:00 2001 From: sol1105 <10836031+sol1105@users.noreply.github.com> Date: Wed, 8 Jul 2026 10:23:36 +0200 Subject: [PATCH 1/2] check_time_squareness to follow sampling times guidance for monthly instantaneous data --- checks/time_checks/check_time_squareness.py | 69 ++++++++++++++++++--- 1 file changed, 60 insertions(+), 9 deletions(-) diff --git a/checks/time_checks/check_time_squareness.py b/checks/time_checks/check_time_squareness.py index 976f30d..141ac02 100644 --- a/checks/time_checks/check_time_squareness.py +++ b/checks/time_checks/check_time_squareness.py @@ -293,16 +293,67 @@ def check_time_squareness( # for why this is np.round and not np.trunc. a_t = _round(actual, NDECIMALS) t_t = _round(theo, NDECIMALS) +<<<<<<< Updated upstream +======= + + # For monthly instantaneous data, allow three valid timestamp conventions, + # but require consistency across the whole file (single convention per file): + # - first day of each month at 00:00 + # - 15th day of each month at 00:00 + # - exact calendar-aware midpoint of each month interval + allow_mon_point_midmonth = ( + instantaneous + and (freq_id in {"mon", "monPt"}) + and (inc_unit == "months") + and (inc_val == 1) + ) +>>>>>>> Stashed changes - bad = np.where(a_t != t_t)[0] - if bad.size: - i = int(bad[0]) - ctx.add_failure( - f"Mismatch at index {i}: expected {t_t[i]:.{NDECIMALS}f}, got {a_t[i]:.{NDECIMALS}f}. " - f"(table_id={table_id}, frequency={freq_id}, var={target}, midpoint={use_midpoint})" - ) + if allow_mon_point_midmonth: + theo_mid = np.zeros(actual.size, dtype=float) + theo_center = np.zeros(actual.size, dtype=float) + cur = start_boundary + for i in range(actual.size): + nxt = _add_time_increment(cur, inc_val, inc_unit, cal) + mid = cftime.datetime(cur.year, cur.month, 15, 0, 0, 0, calendar=cal) + theo_mid[i] = float(cftime.date2num(mid, units=units, calendar=cal)) + theo_center[i] = _midpoint_num(cur, nxt, units, cal) + cur = nxt + + t_mid = _round(theo_mid, NDECIMALS) + t_center = _round(theo_center, NDECIMALS) + + # A file passes only if the full axis matches one convention end-to-end. + full_match_start = np.array_equal(a_t, t_t) + full_match_mid = np.array_equal(a_t, t_mid) + full_match_center = np.array_equal(a_t, t_center) + + if not (full_match_start or full_match_mid or full_match_center): + bad = np.where((a_t != t_t) & (a_t != t_mid) & (a_t != t_center))[0] + if bad.size: + i = int(bad[0]) + else: + # Mixed-convention axis: every point matches at least one candidate, + # but no single candidate matches the entire file. + first_start = np.where(a_t != t_t)[0] + i = int(first_start[0]) if first_start.size else 0 + ctx.add_failure( + f"Mismatch at index {i}: expected {t_t[i]:.{NDECIMALS}f} (month-start) " + f"or {t_mid[i]:.{NDECIMALS}f} (day-15) " + f"or {t_center[i]:.{NDECIMALS}f} (exact center), got {a_t[i]:.{NDECIMALS}f}. " + "The full file must consistently follow one of these conventions. " + f"(table_id={table_id}, frequency={freq_id}, var={target}, midpoint={use_midpoint})" + ) else: - if not ctx.messages: - ctx.add_pass() + bad = np.where(a_t != t_t)[0] + if bad.size: + i = int(bad[0]) + ctx.add_failure( + f"Mismatch at index {i}: expected {t_t[i]:.{NDECIMALS}f}, got {a_t[i]:.{NDECIMALS}f}. " + f"(table_id={table_id}, frequency={freq_id}, var={target}, midpoint={use_midpoint})" + ) + + if not ctx.messages: + ctx.add_pass() return [ctx.to_result()] From 55c4cc7bc51ad06ca928fd6ec1b7efd3d4bba402 Mon Sep 17 00:00:00 2001 From: sol1105 <10836031+sol1105@users.noreply.github.com> Date: Wed, 8 Jul 2026 11:36:51 +0200 Subject: [PATCH 2/2] Removed git stash remnants --- checks/time_checks/check_time_squareness.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/checks/time_checks/check_time_squareness.py b/checks/time_checks/check_time_squareness.py index 141ac02..20ef335 100644 --- a/checks/time_checks/check_time_squareness.py +++ b/checks/time_checks/check_time_squareness.py @@ -293,8 +293,6 @@ def check_time_squareness( # for why this is np.round and not np.trunc. a_t = _round(actual, NDECIMALS) t_t = _round(theo, NDECIMALS) -<<<<<<< Updated upstream -======= # For monthly instantaneous data, allow three valid timestamp conventions, # but require consistency across the whole file (single convention per file): @@ -307,7 +305,6 @@ def check_time_squareness( and (inc_unit == "months") and (inc_val == 1) ) ->>>>>>> Stashed changes if allow_mon_point_midmonth: theo_mid = np.zeros(actual.size, dtype=float)