Skip to content

Retire the TZOFFSET keyword - #152

Merged
mgrossmann merged 1 commit into
mainfrom
issue-145-remove-tzoffset
Aug 8, 2026
Merged

Retire the TZOFFSET keyword#152
mgrossmann merged 1 commit into
mainfrom
issue-145-remove-tzoffset

Conversation

@mgrossmann

Copy link
Copy Markdown
Contributor

Closes #145.

Why it goes

By the time #150 and #151 were done, TZOFFSET had one effect left: the default offset for DISPLAY TIME, a command that takes an offset as an argument anyway.

Both purposes its documentation claimed were never real:

claimed consumer what it actually uses
Date: response header gmtime64() in http1123.c — verified against a UTC clock, correct to the second
SMF record timestamps localtime() in httprepo.c — i.e. the task's CRT offset

Neither has ever read the field.

What it did have was a failure mode. TZOFFSET +02:00 reads like a display preference; it actually asserts the machine's TOD clock runs at UTC+2. Set on a system at UTC−5 it silently shifted every JES2 timestamp by seven hours, and it took measuring three separate control blocks to pin down. Its side effects pointed the same way — __tzset() reached only the task that parsed the Parmlib, so workers and modules kept the system offset, and setenvi("TZOFFSET") published a name nothing reads because tzset() looks at TZ.

The escape hatch it nominally provided — a system whose CVTTZ is wrong — already exists and works better. TZ in the STC's SYSENV or ENVIRON DD is read by tzset(), which both httpstrt.c and cgistart.c call after loadenv(), so it reaches every task instead of one.

What changes

The keyword is accepted and ignored, with a warning naming the offset actually in use and pointing at the replacement:

HTTPD025W TZOFFSET is no longer used; the system offset GMT -05:00 applies
HTTPD025W Set TZ in the SYSENV or ENVIRON DD to override it for all tasks

Accepted rather than rejected so an existing Parmlib still starts the server.

httpd->tzoffset stays at offset 0x24, written only by set_defaults() from __tzget(). Keeping the field avoids shifting the HTTPD block layout that /.dsrv — and anything else reading offsets — depends on.

DISPLAY TIME said TZOFFSET= for the value it prints, naming a setting that no longer exists. It is OFFSET= now, and the help line reads [minutes] rather than [tzoffset] — the argument is what it always was, only the label was borrowed from the keyword.

Docs

docs/configuration.md's Timezone section now says where the offset comes from and how to override it with TZ, and records the retirement as a note for anyone whose Parmlib still carries the statement. The keyword is out of both sample configurations — that file and CLAUDE.md.

Verification

make clean under -Wall -Werror, 6 modules link, make test-host 63 assertions pass. Deployed to IBMUSER.HTTPD.V4R0M0D.LINKLIB.

Live check worth doing, and the reference system is set up for it — SYS2.PARMLIB(HTTPPRM0) still has TZOFFSET +02:00, so a restart on this build should:

  1. issue both HTTPD025W lines at startup naming GMT -05:00;
  2. answer F HTTPD,DISPLAY TIME with GMT and Local five hours apart and OFFSET=-300 — where before this build it showed +120;
  3. leave /jes/status timestamps unchanged, since Return JES2 job timestamps as ISO 8601 UTC #151 already decoupled them from this field.

Then the statement can come out of the Parmlib, and (1) should stop appearing.

By the time #150 and #151 were done, TZOFFSET had one effect left: the default
offset for the DISPLAY TIME command, which takes an offset as an argument
anyway. Both purposes its documentation claimed were never real -- the Date:
header goes through gmtime64() in http1123.c and the SMF record through
localtime() in httprepo.c, and neither has ever read the field.

What it did have was a failure mode. "TZOFFSET +02:00" reads like a display
preference, but it asserts that the machine's TOD clock runs at UTC+2; set on
a system at UTC-5 it silently shifted every JES2 timestamp by seven hours, and
took a measurement of three separate control blocks to pin down. Its side
effects pointed the same way: __tzset() reached only the task that parsed the
Parmlib, so workers and modules kept the system offset, and
setenvi("TZOFFSET") published a name nothing reads because tzset() looks at TZ.

The escape hatch it nominally provided -- a system whose CVTTZ is wrong --
already exists and works better. TZ in the STC's SYSENV or ENVIRON DD is read
by tzset(), which both httpstrt.c and cgistart.c call after loadenv(), so it
reaches every task rather than one.

The keyword is now accepted and ignored with an HTTPD025W naming the system
offset in use and pointing at TZ, so an existing Parmlib still starts the
server. httpd->tzoffset stays at offset 0x24 and is written only by
set_defaults() from __tzget(); keeping the field avoids shifting the HTTPD
block layout that .dsrv and anything else reading offsets depends on.

DISPLAY TIME's output said "TZOFFSET=" for the value it shows. That named a
setting which no longer exists, so it is "OFFSET=" now, and the command's help
line says [minutes] rather than [tzoffset] -- the argument is what it always
was, the label was borrowed from the keyword.

Docs: configuration.md's Timezone section now describes where the offset comes
from and how to override it with TZ, with the retirement recorded as a note
for anyone whose Parmlib still has the statement. The keyword is out of both
sample configurations, here and in CLAUDE.md.

Closes #145
@mgrossmann
mgrossmann merged commit 070b04d into main Aug 8, 2026
1 check passed
@mgrossmann
mgrossmann deleted the issue-145-remove-tzoffset branch August 8, 2026 09:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parmlib TZOFFSET never reaches a module: __tzset() writes the per-task CRT, so CGI timestamps render with the system CVTTZ instead

1 participant