# How to test time zone and DST bugs in agent code

> Time zone testing should cover daylight saving transitions, ambiguous and missing local times, time zone database updates, and an injectable clock. Learn the test matrix to require on agent-written date code and how Factory runs it on each pull request.

URL: https://factory.com/articles/time-zone-testing-agent-generated-code
Published: 2026-09-27
Updated: 2026-10-23

To test time zone handling, inject a fixed clock and run each scheduling path against UTC, a zone with daylight saving time, and a zone without it. Cover an ordinary date, the boundary before a transition, the missing or repeated local hour, and the next valid run, and assert the conversion in both directions.

Time zone testing catches failures that stay invisible when every developer and CI runner uses UTC. Agent-generated code may replace a library, move a conversion, or simplify a schedule while preserving common dates. The defect appears later at a daylight-saving transition, after a time zone database update, or when a user enters an ambiguous local time.

The [IANA Time Zone Database](https://www.iana.org/time-zones) records civil-time rules that governments can change. Language libraries consume that data. Python's [time zone documentation](https://docs.python.org/3/library/zoneinfo.html), for example, explains how the standard library uses system data or the first-party `tzdata` package and represents ambiguous times with the `fold` attribute.

## Define time zone testing contracts

Separate instants from local civil time. An instant identifies one point on the timeline and can be stored in UTC. A local schedule such as "09:00 every business day in São Paulo" depends on a named region and its changing rules. Replacing that region with a fixed numeric offset loses the rule history.

Write the product decision for nonexistent and repeated local times. During a forward clock change, some wall times never occur. During a backward change, one wall time can map to two instants. The application may reject, shift, or ask the user to disambiguate, but the behavior must be explicit.

Every local input should pass through the same decision before it becomes a stored instant.

Local input</span><br/><span style='color:#8A8380 !important'>wall time plus named zone</span>"]
    B["<span style='color:#FAFAFA !important;font-weight:600'>Resolve with the time zone database</span><br/><span style='color:#8A8380 !important'>pinned or recorded version</span>"]
    C{"<span style='color:#FAFAFA !important;font-weight:600'>Missing or repeated time?</span>"}
    D["<span style='color:#FAFAFA !important;font-weight:600'>Apply product policy</span><br/><span style='color:#8A8380 !important'>reject, shift, or ask</span>"]
    E["<span style='color:#FAFAFA !important;font-weight:600'>Store the instant in UTC</span><br/><span style='color:#8A8380 !important'>keep the named zone for recurrence</span>"]
    F["<span style='color:#FAFAFA !important;font-weight:600'>Display in the viewer's zone</span>"]
    A --> B --> C
    C -- yes --> D --> E
    C -- no --> E
    E --> F
`}
/>

Keep the clock injectable. Tests should supply an instant rather than changing the machine clock or waiting for a real transition. Pin or record the time zone database version when reproducibility matters, especially for generated schedules and long-lived fixtures.

## Build time zone testing cases

Select representative zones from the application's actual support set. Include UTC, a zone with daylight-saving transitions, a zone without current seasonal changes, and any region central to the product. Avoid assuming every transition moves by one hour.

For each scheduling path, test an ordinary date, the boundary before a transition, the missing or repeated interval, and the next valid execution. Verify both directions: local input to stored instant and stored instant back to the displayed local value.

Those cases form a small matrix that every date-handling change should pass.

| Case | Example input | Assertion |
| --- | --- | --- |
| Ordinary date | 09:00 on a mid-month weekday | Stored instant and displayed time round-trip |
| Before a transition | The last run before clocks change | Next run lands on the correct instant |
| Missing local time | A wall time skipped by a forward change | Product policy is applied |
| Repeated local time | A wall time that occurs twice | The chosen instant matches the policy |
| Zone without seasonal change | A zone with no current daylight saving | No shift is applied |
| Database update | The suite run against newer time zone data | Expectations tied to old rules are flagged |

Test serialization with an explicit offset and, when recurrence matters, the named zone. A timestamp alone can preserve an instant but cannot preserve the rule for future local events. Also run the suite against an updated time zone database in a controlled branch to identify expectations tied to old civil rules.

## Review date changes with evidence

The pull request should name the clock source, storage format, supported zone identifiers, ambiguity policy, time zone data source, and exact boundary cases. Screenshots can confirm display, but assertions over instants and local representations provide durable regression evidence.

Stop when the product has no stated policy for ambiguous input. A coding agent should not choose a business rule by copying whichever default a date library happens to use.

## How Factory runs date handling checks

Factory is a platform for running a software factory, where agents called Droids take work from a signal to a reviewed pull request. For date and time code, Factory's role is to run the same matrix on every change and keep the contract in front of the agent.

**Test the running product.** Factory's [Automated QA](https://docs.factory.com/software-factory/automated-qa) starts with `/install-qa`, which analyzes the codebase and generates a QA skill for the project. The generated `/qa` skill reads each pull request diff, picks the affected web, CLI, or API flows, and returns a structured report with evidence. Pair those flows with the deterministic lower-level tests above.

**Run the matrix after each edit.** A `PostToolUse` [hook](https://docs.factory.com/harness/hooks) runs right after a tool completes and is meant for jobs such as running validation after an edit. Pointing one at the date test suite gives the Droid feedback before it moves on.

**Keep the contract attached to longer work.** [Missions](https://docs.factory.com/missions/planning) plan features and milestones up front, and validation workers run at the end of each milestone. A scheduling rewrite can carry its ambiguity policy and boundary cases as part of that validation.

Factory's own Automations document the same trade-off this article describes. A schedule entered in local time is converted to a fixed UTC schedule when saved and does not follow daylight saving changes, so the docs tell users to update it after the clocks change if the local time matters.

## Frequently asked questions

### Why do time zone bugs pass CI?

Most developer machines and CI runners use UTC, so code that mishandles daylight saving transitions or regional rules behaves correctly in tests. The defect appears at a transition, after a time zone database update, or with an ambiguous local time.

### Should you store timestamps in UTC?

Store instants in UTC. For future local events such as a 09:00 daily schedule, also keep the named zone, because a fixed offset loses the rule history the schedule depends on.

### How do you handle a local time that happens twice?

Decide a product policy first, then implement it explicitly. Python's zoneinfo, for example, represents the two possible instants with the fold attribute, and tests should assert the chosen one.

### How do you make time zone tests deterministic?

Inject the clock and supply an instant in the test rather than changing the machine clock or waiting for a real transition. Pin or record the time zone database version when reproducibility matters.

### How does Factory test date handling changes?

Factory Automated QA generates a QA skill that runs the affected flows on each pull request, and hooks can run the date test suite after each edit. Missions can attach the date contract to milestone validation.

## Further reading

- [Localization testing](https://factory.com/articles/coding-agent-localization-testing)
- [Flaky test triage](https://factory.com/articles/flaky-test-triage-coding-agents)
- [Test impact analysis](https://factory.com/articles/test-impact-analysis-coding-agents)
- [IANA time zone data links](https://data.iana.org/time-zones/tz-link.html)
