Summary
Pod-origin x-claw.invoke schedules without a calendar gate are compiled as UTC even when the service/container TZ is a valid local zone such as America/New_York.
This affects both:
.claw-runtime/schedule.json emitted by cmd/claw/schedule_manifest.go
- OpenClaw native cron stores emitted by
internal/driver/openclaw/jobs.go
Impact
claw-api / clawdash show trader schedules in UTC instead of local market time.
- OpenClaw
config/cron/jobs.json gets schedule.tz = "UTC", so runner-native cron state is also wrong.
- For a trading desk, this shifts market-facing cadence away from Eastern time unless an external repair step rewrites the runtime after
claw up.
Observed Environment
- Live Tiverton desk on April 9, 2026
- Host timezone:
America/New_York
- Pod
.env: TZ=America/New_York
- Trader containers also report
TZ=America/New_York
claw api schedule list now confirms the correct behavior only after a local post-deploy normalizer rewrites the runtime files
Reproduction
- Set pod/service env
TZ=America/New_York.
- Add a pod-origin invoke without
when.calendar, for example:
x-claw:
invoke:
- schedule: "0 10-15 * * 1-5"
name: "Hourly macro pulse"
message: "..."
- Run
claw up.
- Inspect:
.claw-runtime/schedule.json
.claw-runtime/<agent>/config/cron/jobs.json
Actual
Both files default to UTC for those invocations.
Expected
If an invocation does not derive timezone from a calendar, it should inherit the resolved service timezone, i.e. the validated TZ from the service environment. In the example above, both files should use America/New_York.
Relevant Source
cmd/claw/schedule_manifest.go
- currently defaults to
UTC when inv.When == nil
internal/driver/openclaw/jobs.go
- currently hardcodes
jobSchedule.TZ = "UTC"
Local Fix That Worked
A local patch in my checkout fixed this by:
- using the resolved service
TZ as the default timezone for schedule manifest entries when there is no calendar-derived timezone
- using the same resolved
TZ for OpenClaw jobSchedule.TZ
- adding targeted tests around both code paths
I also had to add a desk-side runtime normalizer because the current released binary still emits UTC until the upstream fix lands.
Notes
The host and Rails API were already on Eastern time. The bug was specifically in Clawdapus schedule/runtime emission, not the machine clock.
Summary
Pod-origin
x-claw.invokeschedules without a calendar gate are compiled asUTCeven when the service/containerTZis a valid local zone such asAmerica/New_York.This affects both:
.claw-runtime/schedule.jsonemitted bycmd/claw/schedule_manifest.gointernal/driver/openclaw/jobs.goImpact
claw-api/clawdashshow trader schedules in UTC instead of local market time.config/cron/jobs.jsongetsschedule.tz = "UTC", so runner-native cron state is also wrong.claw up.Observed Environment
America/New_York.env:TZ=America/New_YorkTZ=America/New_Yorkclaw api schedule listnow confirms the correct behavior only after a local post-deploy normalizer rewrites the runtime filesReproduction
TZ=America/New_York.when.calendar, for example:claw up..claw-runtime/schedule.json.claw-runtime/<agent>/config/cron/jobs.jsonActual
Both files default to
UTCfor those invocations.Expected
If an invocation does not derive timezone from a calendar, it should inherit the resolved service timezone, i.e. the validated
TZfrom the service environment. In the example above, both files should useAmerica/New_York.Relevant Source
cmd/claw/schedule_manifest.goUTCwheninv.When == nilinternal/driver/openclaw/jobs.gojobSchedule.TZ = "UTC"Local Fix That Worked
A local patch in my checkout fixed this by:
TZas the default timezone for schedule manifest entries when there is no calendar-derived timezoneTZfor OpenClawjobSchedule.TZI also had to add a desk-side runtime normalizer because the current released binary still emits
UTCuntil the upstream fix lands.Notes
The host and Rails API were already on Eastern time. The bug was specifically in Clawdapus schedule/runtime emission, not the machine clock.