AnnouncementsIntroducing Arkoren

    Menu

    Time Zones

    Choose UTC or named local time and account for skipped and repeated wall-clock times during daylight saving changes.

    What's on this page
    1. Choose UTC for machine schedules or a named location for local-clock work.
    2. Predict core calendar behavior across daylight saving gaps and overlaps.
    3. Interpret registration warnings and Temporal's different autumn behavior.
    On this page

    A daily account digest should follow its recipients’ local clock, while background cleanup usually needs only a predictable machine schedule. Choose the zone as part of each calendar spec: UTC avoids seasonal clock changes; a named location follows that region’s time rules.

    This page assumes you can define a calendar entry. Time zones describe matching calendar instants, not guaranteed execution or arrival times.

    Choosing Zones

    Use schedule.UTC() unless the wall-clock time matters to people. For example, schedule.UTC().Hour(6) matches 06:00 UTC each day without a daylight saving transition. Driver outages and missed-tick policies still affect delivery.

    For a local digest at 09:00, use schedule.In(location). Avoid time.Local for shared scheduling: its meaning depends on the machine, and Temporal and Restate reject the Local zone with schedule.ErrUnsupported. Load an explicit named zone instead.

    Loading Locations

    Load the desired location using the standard library before constructing a spec. Import time and arkoren.dev/core/service/schedule:

    location, err := time.LoadLocation("Europe/Amsterdam")

    Handle the load error before using location. schedule.In(nil) retains an invalid-spec error rather than selecting a default zone.

    With your application’s sendDigest function of type func(context.Context) error, construct the entry:

    digest := schedule.NewEntry("account-digest", sendDigest, func(entry *schedule.EntryBuilder) {
    	entry.When(schedule.In(location).Hour(9))
    })

    The match is 09:00 Amsterdam time, with minutes and seconds defaulting to zero. Register it with scheduler.Add(digest) before starting the scheduler.

    Zone loading needs available timezone data. If a minimal container lacks zone files, embed the standard library’s database with a blank import in your program:

    import _ "time/tzdata"

    Deploy timezone data consistently across workers and engines when local-clock behavior matters; Next cannot predict a remote engine using different rules.

    Clock Changes

    Daylight saving time creates a spring gap, when a range of local times does not exist, and an autumn overlap, when a range occurs twice. The core calendar used by memory and Restate skips nonexistent times and chooses only the first occurrence of repeated times.

    In Amsterdam on March 29, 2026, the clock jumps from 02:00 to 03:00. A 02:30 entry has no matching instant that day and is skipped, not moved to 03:30. On October 25, 2026, the hour beginning at 02:00 repeats. The core calendar matches 02:30 only on its first occurrence.

    If a business process must run for every date, do not depend on a tick inside those transition hours. Choose UTC or a local time outside the transition, and persist business progress so missed delivery can be reconciled separately.

    Inspecting Matches

    Before choosing a local time, inspect the core calendar without running any handler. Reuse the loaded location and import fmt for this inspection:

    spec := schedule.In(location).Hour(2).Minute(30)
    before := time.Date(2026, time.March, 28, 12, 0, 0, 0, location)
    fmt.Println(spec.Next(before))

    The result skips March 29:

    2026-03-30 02:30:00 +0200 CEST

    Spec.Next and Entry.Next return the first matching instant strictly after the supplied time. Invalid specs and searches with no match within five years return zero time. These methods calculate core calendar matches, not remote engine delivery times.

    Registration Warnings

    scheduler.Add examines the next year for a transition intersecting a non-UTC entry’s matching times. If it finds one, it logs one warning for that entry with its name, zone, date, wall time, and skipped or run once effect.

    The warning does not reject registration or change the spec. It describes the core calendar, including when Temporal’s own overlap behavior differs. If it identifies a risky business time, choose another time or zone; do not treat successful registration as proof that every date will have an execution.

    Driver Calendars

    Memory and Restate use the core calendar. Temporal uses its engine calendar:

    Driver Spring Gap Autumn Overlap
    Memory Skips the nonexistent time. Matches the first occurrence only.
    Temporal Skips the nonexistent time. Matches both occurrences.
    Restate Skips the nonexistent time. Matches the first occurrence only.

    A Temporal entry in a repeated hour must tolerate two calendar firings, in addition to ordinary duplicate-delivery risks. Move it outside the overlap if two intended firings are not appropriate. See Drivers for missed-tick recovery, overlap policy, and engine configuration. Hatchet remains pending and is not an available alternative.

    For every function and option, see the schedule API reference.

    Open a bulk documentation archive?

    This file contains every guide in its scope, not API declarations. Loading it all into an agent can exhaust its context window and increase processing time and cost. For coding tasks, start with the index and read only the relevant pages.

    Use the full archive for offline indexing, bulk processing, or deliberate large-context use.

    Browse the index instead
    Open archive