From: Frantisek Sumsal Date: Thu, 2 Jul 2026 12:32:36 +0000 (+0200) Subject: test: ignore fails when the formatted timezone differs from the current one X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7273d383355fd15c17dc21afe945d949789c87f7;p=thirdparty%2Fsystemd.git test: ignore fails when the formatted timezone differs from the current one When formatting a timestamp the C API takes into account historical data from tzdata, so it returns a date strings with a historically-correct timezone abbreviation. However, tzname[] doesn't do this and it returns the most recent abbreviation for the given zone. For example, according to tzdata America/Cancun switched from EST/EDT to CST/CDT on 1998-08-02: Zone America/Cancun -5:47:04 - LMT 1922 Jan 1 6:00u -6:00 - CST 1981 Dec 26 2:00 -5:00 - EST 1983 Jan 4 0:00 -6:00 Mexico C%sT 1997 Oct 26 2:00 -5:00 Mexico E%sT 1998 Aug 2 2:00 -6:00 Mexico C%sT 2015 Feb 1 2:00 -5:00 - EST So, formatting a timestamp from this time will yield a string with the EDT timezone: $ TZ=America/Cancun date -d "@902035565" Sun Aug 2 01:26:05 EDT 1998 But using tzname[] (or strptime %z) shows the most recent data, where America/Cancun uses EST (and doesn't use DST anymore, hence tzname[1]=CDT that glibc remembers from the previous zone epoch): $ TZ=America/Cancun ./tz {EST, CDT} This means that when we parse the formatted timestamp back we don't use the historical timezone data, so we might end up with a different offset: TZ=America/Cancun, tzname[0]=EST, tzname[1]=CDT @902035565603993 → Sun 1998-08-02 01:26:05 EDT → @902039165000000 → Sun 1998-08-02 01:26:05 CDT src/test/test-time-util.c:452: Assertion failed: Expected "ignore" to be true Aborted (core dumped) build-local/test-time-util Instead of adding exceptions for every single timezone that switched between different offsets in the past, let's address this a bit more generally and skip the check if the parsed timezone doesn't match any of the current timezones - this still keeps the check that the time difference in such case is exactly one hour, so its effect should be limited mostly to DST-related changes. Resolves: #37684 --- diff --git a/src/test/test-time-util.c b/src/test/test-time-util.c index 392b06214b0..1a1370eda6d 100644 --- a/src/test/test-time-util.c +++ b/src/test/test-time-util.c @@ -433,15 +433,27 @@ static void test_format_timestamp_impl(usec_t x) { if (x_sec == y_sec && streq(xx, yy)) return; /* Yay! */ - /* When the timezone is built with rearguard being enabled (e.g. old Ubuntu and RHEL), the timezone - * Africa/Windhoek may provide time shifted 1 hour from the original. See - * https://github.com/systemd/systemd/issues/28472 and https://github.com/systemd/systemd/pull/35471. - * Also, the same may happen on MSK timezone (e.g. Europe/Volgograd or Europe/Kirov), or on - * Africa/Tripoli (Libya) which switched between CET and EET multiple times historically, causing - * certain timestamps to round-trip with a 1h offset. */ + /* There are two classes of known round-trip failures that produce exactly a 1h offset: + * + * 1) The formatted abbreviation doesn't match the current timezone's abbreviations - the timestamp + * is from a historical era (e.g. Africa/Tripoli switched between CET and EET multiple times + * historically, America/Cancun switched between EST/EDT and CST/CDT several times in the past, + * etc.), and the round-trip is inherently unreliable on platforms where parse_gmtoff() resolves + * such abbreviations with incorrect offsets. + * + * 2) Rearguard/vanguard database format differences where the abbreviation matches but the + * offset is still wrong (e.g. Africa/Windhoek, Europe/Kirov, Europe/Volgograd). + * + * See: + * - https://github.com/systemd/systemd/issues/28472 + * - https://github.com/systemd/systemd/pull/35471 + * - https://github.com/systemd/systemd/issues/37684 + */ bool ignore = - (STRPTR_IN_SET(getenv("TZ"), "Africa/Windhoek", "Africa/Tripoli", "Libya") || - STRPTR_IN_SET(get_tzname(/* dst= */ false), "CAT", "EAT", "MSK", "WET")) && + ((!streq_ptr(tz, get_tzname(/* dst= */ false)) && + !streq_ptr(tz, get_tzname(/* dst= */ true))) || + streq_ptr(getenv("TZ"), "Africa/Windhoek") || + STRPTR_IN_SET(get_tzname(/* dst= */ false), "MSK", "WET")) && (x_sec > y_sec ? x_sec - y_sec : y_sec - x_sec) == 3600; log_full(ignore ? LOG_WARNING : LOG_ERR, @@ -459,16 +471,17 @@ static void test_format_timestamp_loop(void) { test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX-1); test_format_timestamp_impl(USEC_TIMESTAMP_FORMATTABLE_MAX); - /* Two cases which trigger https://github.com/systemd/systemd/issues/28472 */ + /* Specific timestamps known to cause a 1h round-trip discrepancy with certain timezones: + * + * Two cases which trigger https://github.com/systemd/systemd/issues/28472. */ test_format_timestamp_impl(1504938962980066); test_format_timestamp_impl(1509482094632752); - /* With tzdata-2025c, the timestamp (randomly?) fails on MSK time zone (e.g. Europe/Volgograd). */ test_format_timestamp_impl(1414277092997572); - - /* Africa/Tripoli (Libya) switched from CET to EET multiple times in the past, causing a 1h - * round-trip discrepancy for historical timestamps. */ + /* Africa/Tripoli (Libya) switched from CET to EET multiple times in the past. */ test_format_timestamp_impl(378687574661411); + /* America/Cancun switched from EST/EDT to CST/CDT multiple times in the past. */ + test_format_timestamp_impl(902035565603993); for (unsigned i = 0; i < TRIAL; i++) { usec_t x;