Skip to content

[miniflare] Default workerd subprocess to TZ=UTC to match production#13776

Open
petebacondarwin wants to merge 4 commits intomainfrom
pbd/miniflare/tz-utc
Open

[miniflare] Default workerd subprocess to TZ=UTC to match production#13776
petebacondarwin wants to merge 4 commits intomainfrom
pbd/miniflare/tz-utc

Conversation

@petebacondarwin
Copy link
Copy Markdown
Contributor

@petebacondarwin petebacondarwin commented May 1, 2026

Fixes #8106.

Cloudflare's production runtime runs Workers with TZ=UTC, but Miniflare inherited the host machine's timezone, causing dev/prod drift in Date and Intl behaviour. Local development now matches production by default.

Changes

  • packages/miniflare/src/runtime/index.ts — when spawning the workerd subprocess, default TZ to "UTC" and merge any caller-provided overrides last. Added a runtimeEnv?: Record<string, string> field to RuntimeOptions.
  • packages/miniflare/src/plugins/core/index.ts — added unsafeRuntimeEnv: z.record(z.string()).optional() to CoreSharedOptionsSchema so library consumers can override the default (e.g. { TZ: "Europe/London" } for testing timezone-dependent behaviour).
  • packages/miniflare/src/index.ts — wired the option through to the runtime.
  • packages/miniflare/README.md — documented the new unsafeRuntimeEnv option alongside the existing unsafe* shared options.

The user-facing behaviour change is that wrangler dev (and every other Miniflare-backed surface — wrangler kv/d1/r2/check, vitest-pool-workers, vite-plugin-cloudflare, etc.) now run with TZ=UTC by default, matching production. Consumers who genuinely need a different timezone can pass unsafeRuntimeEnv directly to Miniflare.


A picture of a cute animal (not mandatory, but encouraged)

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 1, 2026

🦋 Changeset detected

Latest commit: c7b3cfe

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-project-automation github-project-automation Bot moved this to Untriaged in workers-sdk May 1, 2026
@workers-devprod workers-devprod requested review from a team and ascorbic and removed request for a team May 1, 2026 20:37
@workers-devprod
Copy link
Copy Markdown
Contributor

workers-devprod commented May 1, 2026

Codeowners approval required for this PR:

  • @cloudflare/wrangler
Show detailed file reviewers
  • .changeset/miniflare-default-tz-utc.md: [@cloudflare/wrangler]
  • .changeset/wrangler-dev-tz-utc.md: [@cloudflare/wrangler]
  • packages/miniflare/README.md: [@cloudflare/wrangler]
  • packages/miniflare/src/index.ts: [@cloudflare/wrangler]
  • packages/miniflare/src/plugins/core/index.ts: [@cloudflare/wrangler]
  • packages/miniflare/src/runtime/index.ts: [@cloudflare/wrangler]
  • packages/miniflare/test/index.spec.ts: [@cloudflare/wrangler]

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 1, 2026

Changeset Review

Changesets Reviewed

  1. .changeset/miniflare-default-tz-utc.md
  2. .changeset/wrangler-dev-tz-utc.md

Validation Results

.changeset/miniflare-default-tz-utc.md

  • Version Type: minor - Appropriate for a behavioral change that could affect existing development workflows
  • Changelog Quality: Clear description explaining the dev/prod drift issue, the fix, and the new unsafeRuntimeEnv option. Includes helpful TypeScript example.
  • Markdown Headers: No h1/h2/h3 headers found
  • Analytics: No analytics changes
  • Dependabot: Not a dependency update
  • Experimental Features: N/A - unsafeRuntimeEnv is an advanced option, not an experimental feature

.changeset/wrangler-dev-tz-utc.md

  • Version Type: minor - Appropriate for a behavioral change affecting multiple commands
  • Changelog Quality: Clear description covering scope (wrangler dev and other Miniflare-backed commands), the problem, and migration guidance for users who relied on the old behavior
  • Markdown Headers: No h1/h2/h3 headers found
  • Analytics: No analytics changes
  • Dependabot: Not a dependency update
  • Experimental Features: N/A

Summary

✅ All changesets look good

Both changesets are well-written, provide clear context about the timezone fix, and appropriately use minor version bumps to signal this behavioral change to users.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk Bot commented May 1, 2026

I've now reviewed the entire PR carefully. Let me assess the issues:

  1. The onTestFinished import change: The PR removes onTestFinished from the vitest import and adds it to the test context destructuring in tests that use it. This is actually correct and aligns with the repo's convention of getting onTestFinished from the test context. However, useDispose in test-shared/miniflare.ts still uses the module-level onTestFinished from vitest — that's fine, it's not changed in this PR.

  2. The afterEach with vi.unstubAllEnvs(): This is added at the file scope, meaning it runs after every test, not just the timezone tests. This is generally fine since vi.unstubAllEnvs() is a no-op if nothing was stubbed, but it's a broader change than necessary.

  3. The FORCE_COLOR override: The ...options.runtimeEnv spread comes last, which means a caller can override FORCE_COLOR via unsafeRuntimeEnv. This is documented/intentional ("merged on top of process.env and Miniflare's own defaults"). The option is prefixed unsafe, so this is fine.

  4. The core logic: The env merge order { ...process.env, TZ: "UTC", FORCE_COLOR, ...options.runtimeEnv } is correct. TZ: "UTC" overrides whatever TZ was in process.env, and options.runtimeEnv can override both.

  5. Tests are .sequential: The timezone tests use test.sequential which is appropriate since they mutate process.env.TZ via vi.stubEnv.

  6. Changeset correctness: The miniflare changeset is minor which is appropriate for a new feature/option. The wrangler changeset is also minor which correctly reflects the behavior change.

The code is clean, the logic is correct, and the tests appropriately validate both the default UTC behavior and the override mechanism. The onTestFinished refactoring to use test context instead of module import aligns with the repo's testing guidelines.

LGTM

github run

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 1, 2026

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@13776

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@13776

miniflare

npm i https://pkg.pr.new/miniflare@13776

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@13776

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@13776

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@13776

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/@cloudflare/vitest-pool-workers@13776

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@13776

@cloudflare/workers-utils

npm i https://pkg.pr.new/@cloudflare/workers-utils@13776

wrangler

npm i https://pkg.pr.new/wrangler@13776

commit: c7b3cfe

devin-ai-integration[bot]

This comment was marked as resolved.

Cloudflare's production runtime runs Workers with TZ=UTC, but Miniflare
inherited the host machine's timezone, causing dev/prod drift in `Date`
and `Intl` behaviour. Local development now matches production by
default, with a new `unsafeRuntimeEnv` option for advanced consumers
that need to test timezone-dependent behaviour.

Closes #8106
A diagnostic probe on Windows CI proved that workerd-on-Windows always
reports `UTC` from `Intl.DateTimeFormat().resolvedOptions().timeZone`
regardless of the `TZ` env var passed to its subprocess — every value
tried (`America/Chicago`, `Asia/Tokyo`, `Europe/London`, `Etc/GMT+5`,
`Etc/UTC`, `UTC`, `PST8PDT`) resolved to `UTC`. This is a workerd
limitation on Windows.

The user-facing default (`TZ=UTC`) and the override mechanism are
unchanged — the override test simply has no observable effect on
Windows, so we skip it there.
@petebacondarwin petebacondarwin force-pushed the pbd/miniflare/tz-utc branch from e39af5a to c7b3cfe Compare May 2, 2026 10:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Untriaged

Development

Successfully merging this pull request may close these issues.

[miniflare]: Set TZ=UTC for wrangler dev

2 participants