fix(logs): respect TZ env var for timestamp display, fix Windows timezone#21859
Conversation
src/logging/timestamps.ts
Outdated
| const tzMinutes = String(Math.abs(tzOffset) % 60).padStart(2, "0"); | ||
| return `${year}-${month}-${day}T${h}:${m}:${s}.${ms}${tzSign}${tzHours}:${tzMinutes}`; | ||
| export function formatLocalIsoWithOffset(now: Date, timeZone?: string): string { | ||
| const tz = timeZone ?? process.env.TZ ?? Intl.DateTimeFormat().resolvedOptions().timeZone; |
There was a problem hiding this comment.
env.TZ needs to be checked. What happens when someone runs TZ="yo agent's" openclaw logs?
src/cli/logs-cli.ts
Outdated
| const pretty = !jsonMode && Boolean(process.stdout.isTTY) && !opts.plain; | ||
| const rich = isRich() && opts.color !== false; | ||
| const localTime = Boolean(opts.localTime); | ||
| const localTime = Boolean(opts.localTime) || Boolean(process.env.TZ); |
There was a problem hiding this comment.
Again, existence is not enough, it needs to be usable.
src/logging/timestamps.ts
Outdated
| const tz = timeZone ?? process.env.TZ ?? Intl.DateTimeFormat().resolvedOptions().timeZone; | ||
|
|
||
| // Use Intl.DateTimeFormat to get date/time parts in the target timezone | ||
| const fmt = new Intl.DateTimeFormat("en-CA", { |
There was a problem hiding this comment.
"en-CA"? Nothing against Canada, but...
src/logging/timestamps.ts
Outdated
| const partsMap = Object.fromEntries(fmt.formatToParts(now).map((p) => [p.type, p.value])); | ||
|
|
||
| // Get the UTC offset string for the target timezone | ||
| const offsetFmt = new Intl.DateTimeFormat("en", { |
There was a problem hiding this comment.
Can't those two calls be combined?
src/logging/timestamps.ts
Outdated
| // Get the UTC offset string for the target timezone | ||
| const offsetFmt = new Intl.DateTimeFormat("en", { | ||
| timeZone: tz, | ||
| timeZoneName: "shortOffset", |
There was a problem hiding this comment.
Just use longOffset and snip away the "GMT" at the beginning.
hydro13
left a comment
There was a problem hiding this comment.
Thanks for the thorough review! All 5 points addressed:
- Added
isValidTimeZone()(try/catch Intl validation) — invalidTZvalues like"yo agent's"now fall back to the system timezone instead of crashing or producing garbage localTimeinlogs-cli.tsnow requires both truthiness and a valid timezone viaisValidTimeZone()- Locale changed from
"en-CA"to"en" - Merged both
Intl.DateTimeFormatcalls into one withtimeZoneName: "longOffset"included parseGmtOffset()deleted —longOffsetalready produces zero-padded"GMT+08:00"format, so.slice(3)suffices (and"GMT"maps directly to"+00:00")
330c884 to
4449308
Compare
|
This pull request has been automatically marked as stale due to inactivity. |
4abfc11 to
8d315f2
Compare
|
Rebased on current main. Still relevant and ready for merge. |
|
The failing Windows CI check ( The failure is in All other checks pass ✅. Happy to rebase if needed. |
8d315f2 to
d995ef5
Compare
Summary
openclaw logsalways displayed UTC timestamps regardless of theTZenvironment variable. On Windows especially, Node.js does not reliably readTZto adjustgetHours()/getTimezoneOffset()— the methods used by the old implementation.Root Cause
formatLocalIsoWithOffset()insrc/logging/timestamps.tsmanually assembled a timestamp usinggetHours(),getMinutes(),getTimezoneOffset()etc. These methods read the process timezone from the OS — which on Windows does not pick up theTZenvironment variable set by the user.Fix
1.
src/logging/timestamps.ts— rewrite usingIntl.DateTimeFormatReplace the old manual approach with
Intl.DateTimeFormatusing an explicittimeZoneparameter.Intlcorrectly resolves timezone conversions on all platforms including Windows.timeZoneargument, falling back toprocess.env.TZ, thenIntl.DateTimeFormat().resolvedOptions().timeZoneparseGmtOffset()helper to normalize"GMT+8"→"+08:00"format2.
src/cli/logs-cli.ts— auto-enable local time whenTZis setUsers who set
TZ=Asia/Shanghainow see local timestamps automatically without needing--local-time.Tests
6 tests in
src/logging/timestamps.test.ts:+00:00offsetAsia/Shanghai→+08:00, correct hour conversionAmerica/New_Yorkwinter (EST) →-05:00America/New_Yorksummer (EDT) →-04:00getHours,getMinutes,getTimezoneOffsetAll 43 tests in
src/logging/pass.Fixes #21606
Greptile Summary
Replaced manual timezone offset calculation with
Intl.DateTimeFormatto properly respect theTZenvironment variable on all platforms, especially Windows. The implementation correctly usestimeZoneparameter inIntl.DateTimeFormatwhich resolves timezone conversions reliably across platforms. The PR also auto-enables local time display whenTZis set in the environment.Confidence Score: 5/5
Intl.DateTimeFormatAPI. All 6 new tests pass including timezone conversion validation, DST handling, and verification that legacy methods are no longer used. The change is backward compatible (optional parameter) and addresses a real cross-platform bug on Windows.Last reviewed commit: b39bb3a