Tcl Source Code

View Ticket
Login
Ticket UUID: 51aa53616067cb63900b17ca1d71f07b094ffa1a
Title: clock timezone tests fail when ran against system tzdata
Type: Bug Created on: 2026-02-27 17:34:56
Submitter: rossburton Assigned to: nobody
Subsystem: 34. tcltest Package Severity: Minor
Priority: 5 Medium Last modified: 2026-03-07 11:58:26
Status: Closed Closed by: sebres
Resolution: Fixed Closed on: 2026-03-07 11:58:26
Version:
Description:

I'm in a cross-compiled environment so running the tcl test suite outside of the build tree on the target to verify that tcl is working and integrated correctly.

I build tcltest and install that and the tests/ directory. Most tests work:

$ ./tcltest tests/dict.test
dict.test:	Total	373	Passed	371	Skipped	2	Failed	0
Number of tests skipped for each constraint:
	2	memory

However, if I run the clock tests with a tcl that didn't install the tzdata package in the library as we have /usr/share/zoneinfo:

$ ./tcltest tests/clock.test
  Validity default mode: on


==== clock-59.2.vm:1 correct time zone names, format and scan back, bug and regression [2c237beffbace823] FAILED
==== Contents of test case:

    set result {}
    foreach {base tz} {
	 1700000000 "Etc/GMT-2"
	 1700000000 "Etc/GMT+2"
	 1301184000 "Europe/Kaliningrad"
	  152632800 "Pacific/Chatham"
	 -765317964 "America/Paramaribo"
	-2337928528 "Australia/Eucla"
    } {
	set v [clock format $base -timezone Etc/GMT-2 -format "%Y-%m-%d %H:%M:%S %Z"]
	lappend result [expr {[set t [clock scan $v -format "%Y-%m-%d %H:%M:%S %Z"]] == $base ? 1 : "0 ($t != $base for $v)"}]
	lappend result [expr {[set t [clock scan $v]] == $base ? 1 : "0 ($t != $base for $v)"}]
    }
    set result

---- Result was:
1 {0 (1700007080 != 1700000000 for 2023-11-15 00:13:20 +02)} 1 {0 (1700007080 != 1700000000 for 2023-11-15 00:13:20 +02)} 1 {0 (1301191080 != 1301184000 for 2011-03-27 02:00:00 +02)} 1 {0 (152639880 != 152632800 for 1974-11-02 16:00:00 +02)} 1 {0 (-765310884 != -765317964 for 1945-10-01 05:40:36 +02)} 1 {0 (-2337921448 != -2337928528 for 1895-11-30 17:24:32 +02)}
---- Result should have been (exact matching):
1 1 1 1 1 1 1 1 1 1 1 1
==== clock-59.2.vm:1 FAILED

Note that the in-tree tests work as they set TCL_LIBRARY to point at the source tree, which includes tzdata.

It's entirely possible that I'm doing something wrong/dumb, but it's also possible that the tzdata loading has broke, or the copy of tzdata in tcl doesn't match the "real" tzdata 2025c that I have installed.

User Comments:
sebres added on 2026-03-02 13:14:16:

Short analyze shows that there are basically 2 issues:

1. the format of TZ without Tcl's tzdata uses +02 instead of +0200 for %Z token, so the value of v contains:

2023-11-15 00:13:20 +02    # - no tzdata
2023-11-15 00:13:20 +0200  # - with tzdata
what would be not a large problem, if we didn't have another issue, namely:

2. the free scan consider +02 in opposite to formatted scan as +2 minutes "zone", so for the free scan it is the same than +0002 and not +0200:

% puts [clock format [clock scan "2023-11-15 00:13:20 +02" -format "%Y-%m-%d %H:%M:%S %Z"] -gmt 1]
Tue Nov 14 22:13:20 GMT 2023
% puts [clock format [clock scan "2023-11-15 00:13:20 +02"] -gmt 1]
Wed Nov 15 00:11:20 GMT 2023
% puts [clock format [clock scan "2023-11-15 00:13:20 +0002"] -gmt 1]
Wed Nov 15 00:11:20 GMT 2023
% puts [clock format [clock scan "2023-11-15 00:13:20 +0200"] -gmt 1]
Tue Nov 14 22:13:20 GMT 2023
what, regardless the issue 1, is definitely a bug in my opinion.


jan.nijtmans added on 2026-03-04 08:01:13:

@sebres, is this ticket fixed now as well with your change?


sebres added on 2026-03-04 11:18:17:

> is this ticket fixed now as well with your change?

No, it is not (probably even much worse, because of different TZs now since last change)... I'm still in... got no time yet to fix it (or rather found another issue in the meantime, which is fixed now).


sebres added on 2026-03-04 17:36:14:

OK, I can confirm that a lot of tests failed if there is no "tzdata in the library (as we have /usr/share/zoneinfo)".

Besides mentioned issues, there are several others...
Many of them are simply fixed by removal of colon before the TZ-name.
Another can be fixed by adding a constraint that checking whether tcl's tzdata is available, but...

But I see failures on all tests covering daylight switch, timestamps around DST-hole, etc. And such failures are generally not OK in my opinion. For instance:

==== clock-34.69.2.vm:1 relative time, daylight switch FAILED
==== Contents of test case:
set base [clock scan "03/27/2016" -timezone CET] set res {} lappend res [clock format [clock scan "+1 hour" -base $base -timezone CET] -timezone CET -format {%Y-%m-%d %H:%M:%S %Z}] lappend res [clock format [clock scan "+2 hour" -base $base -timezone CET] -timezone CET -format {%Y-%m-%d %H:%M:%S %Z}]
---- Result was: {2016-03-27 01:00:00 +0100} {2016-03-27 02:00:00 +0100} ---- Result should have been (exact matching): {2016-03-27 01:00:00 CET} {2016-03-27 03:00:00 CEST} ==== clock-34.69.2.vm:1 FAILED
I understand that it uses numeric TZ by representing its name (e. g. +0100 instead of CET), but the 2nd timestamp is completely wrong...
Because "2016-03-27 02:00:00 +0100" doesn't exist in CET (it is in the DST-hole) and basically it shall be "2016-03-27 03:00:00 +0200" (since it shall switch to CEST).

So either some aliasing is wrong in zones of "/usr/share/zoneinfo" (e. g. CET is really an alias to +0100, without DST-switches etc).
Or we have something fundamentally wrong in handling of system timezones.

Thus the issue grows and grows.
At the moment, I can only say that usage of Tcl without its tzdata is not advisable.


sebres added on 2026-03-04 22:41:23:

[6ea85b82c5b408c6] fixes that for v.9.0+, starting with the issue 2 (see below), so free scan would consider +02 as hours only time zone now.
It also fixes the clock tests, so they would pass with and without tcls tzdata...

However there is probably a bit more stuff to do:

  • not clear is why system TZ CET (without tzdata) doesn't consider DST-switches (although I can imagine that it is expected situation, so in the tests it was replaced with Europe/Berlin if it running without tzdata);
  • better would be to introduce new yacc/bison tokens like tNMZONE2 and tNMZONE4 to represent 1, 2 and 4-digit numeric zones like ±01 or ±0100, but then it'd imply more complex lexer, because it'd expect several lookaheads to resolve ambiguity with relunit (e. g. +10 hours) or sign tUNUMBER tDAY, etc; or tNMZONE2 and tNMZONE4 become subclasses of tUNUMBER, so bison resolves them by itself;
  • probably system zones (without tzdata) shall prefer 4-digit TZ-name, so +0200 instead of +02 by format %Z (much better would be the regular names like CET/CEST).


sebres added on 2026-03-07 11:58:26:

Fixed for 9.x in [a37536d4d7] and [7018ffb43e].

The case without Tcls tzdata can also be tested from build using -constraints clock-no-tzdata (optional, off by default).

Still open or known issues (by system TZs only without Tcls tzdata) are:

  • not clear is why system TZ CET doesn't consider DST-switches (although I can imagine that it is expected situation, so in the tests it was replaced with Europe/Berlin if it running without tzdata);
  • probably system zones (if without tzdata) shall prefer 4-digit TZ-name, so +0200 instead of +02 by format %Z (much better would be the regular names like CET/CEST).

I am unsure I shall backport it to 8.6, but if yes theoretically it may be possible only partial, because I don't know earlier bison/yacc versions support semantic predicates aka C-condition in token (don't remember whether tclDate will be generated with newer bison than 3.8.1).