Cron Expression Parser

Parse cron expressions into human-readable schedules with next 5 run times. 100% client-side.

Last reviewed: April 2026

New to this tool? Click here for instructions

minute   hour   day-of-month   month   day-of-week
Description
Next 5 Execution Times
Field Breakdown
Enter a cron expression above or select a preset.

Paste any 5-field cron expression and instantly see its next five fire times in your local time zone and UTC, a plain-English description, and a field-by-field breakdown — entirely in your browser, with no data leaving the page.

What This Tool Does

The Cron Expression Parser accepts a classic 5-field cron expression — minute hour day-of-month month day-of-week — and produces three independent outputs that together describe the schedule completely. First, it validates each field against the canonical range and the supported step, range, list, and wildcard syntax; invalid input is rejected with a precise error message pointing at the offending field. Second, it generates a human-readable description such as “Every 15 minutes between 9 AM and 5 PM, Monday through Friday.” Third, it walks forward from the current moment and lists the next five times the job would actually fire in your browser's local time zone, with the original cron string echoed alongside for context.

Every computation runs client-side using a deterministic minute-by-minute scan over a one-year window. No expression you enter is uploaded, logged, or stored anywhere outside the current browser tab. This matters when the schedules you are debugging touch production credentials or describe sensitive automation cadence — both routine concerns in regulated environments where the contents of a job spec might themselves be classified information. The tool covers the syntax accepted by Vixie cron (the de facto Linux standard since 1987), Anacron, Kubernetes CronJob, GitHub Actions schedule triggers, and AWS EventBridge cron rules. Quartz-style 6-field and 7-field expressions, along with the special L, W, and # characters, are not parsed by this tool — see the Edge Cases section for the practical reasons and the Comparison Matrix for what to use instead.

How to Use It: Paste, Read, Verify

The tool is built around three interaction loops: paste-and-read, preset-and-tweak, and field-by-field exploration. Each loop maps to a different debugging stage.

Pasting an Existing Expression

If you already have a cron string — pulled from a crontab -l dump, a Kubernetes manifest, or a GitHub Actions workflow file — paste it directly into the input field at the top of the tool. The parser activates as you type, with a 150 ms debounce so it does not thrash on every keystroke. Within roughly a quarter second after you stop typing, the description, the next five execution times, and the per-field breakdown table all refresh together. Invalid expressions surface in a red status bar identifying which field rejected — for example, “Invalid month field: 13” — rather than a generic parse error.

Starting from a Preset

Click any preset chip (“Every minute,” “Every hour,” “Daily midnight,” “Weekly Monday,” “Monthly 1st”) to load a known-good baseline expression into the input, then edit specific fields to match your real schedule. This is the fastest path when you know roughly what cadence you want but cannot remember whether day-of-month or day-of-week comes first, or whether Sunday is 0 or 7.

Reading the Three Outputs Together

The description pane shows the intended schedule in English. The next-five-runs pane shows when that schedule actually fires next, formatted as “Mon, May 13, 2026, 09:30 AM” with the day-of-week prefix so you can verify the weekday matches your intent. The field breakdown table at the bottom shows each of the five fields, its valid range, the value you entered, and a short interpretation. When the description disagrees with what you expected, the breakdown table usually reveals which field is responsible — often a confused day-of-week numbering or an off-by-one hour.

Copying and Reusing Results

The Copy button next to the next-runs pane copies all five timestamps as plain text, one per line, suitable for pasting into a ticket, a runbook, or a Slack thread. The expression in the input field is itself selectable and copyable — if you arrived with a malformed string and corrected it inside the tool, you can grab the validated version back out.

Worked Example: 0 9 * * 1-5 and */15 9-17 * * 1-5

The two expressions below are common scheduling patterns drawn from real CI/CD configurations. Walking through each one field by field makes the parser's behavior concrete.

Example 1: 0 9 * * 1-5 — Every Weekday at 9:00 AM

This is the canonical “business hours kickoff” schedule used for daily standup reminders, morning ETL refreshes, and overnight-results email digests.

Field 1 (minute) = 0
Fire only at minute 0 of the matching hour. A single literal value, no list or range.
Field 2 (hour) = 9
Fire only at hour 9 (09:00 in 24-hour time, 9 AM in 12-hour time). Again a literal, no wildcard.
Field 3 (day-of-month) = *
Wildcard — any day of the month satisfies this field.
Field 4 (month) = *
Wildcard — any month satisfies this field.
Field 5 (day-of-week) = 1-5
Range from 1 (Monday) through 5 (Friday). This is the constraint that turns “every day at 9 AM” into “weekdays only.”

The human-readable description renders as “At 09:00, on Monday, Tuesday, Wednesday, Thursday, Friday.” The next five runs starting from any Wednesday morning are Wednesday 09:00, Thursday 09:00, Friday 09:00, Monday 09:00 (skipping Saturday and Sunday), and Tuesday 09:00. Because day-of-month is the wildcard and day-of-week is restricted, the standard Vixie-cron OR-rule between those two fields effectively reduces to the day-of-week constraint alone.

Example 2: */15 9-17 * * 1-5 — Every 15 Minutes During Business Hours

This pattern drives intra-day polling jobs: queue depth monitors, lead-database freshness checks, slack-status pingers that should be silent outside working hours.

Field 1 (minute) = */15
Step of 15 anchored at 0 — fires at minutes 0, 15, 30, and 45 of every matching hour. Not “every 15 minutes counting from now” — see the Edge Cases section.
Field 2 (hour) = 9-17
Range from 9 (09:00) through 17 (17:00) inclusive. The job fires during hours 9, 10, 11, 12, 13, 14, 15, 16, and 17 — nine distinct hours, not eight. The last fire in a given day is at 17:45, not 17:00, because the minute field is */15 and not a single literal.
Field 3 (day-of-month) = *
Any day of the month.
Field 4 (month) = *
Any month.
Field 5 (day-of-week) = 1-5
Monday through Friday.

This expression fires 36 times per business day (4 fires per hour times 9 hours), 180 times per business week, and on the order of 9,400 times per year. That cadence is fine for an HTTP-poll job that completes in milliseconds and tolerable for a database query that runs in under a second — but it is dangerous for any job that holds a connection, locks a row, or sends an external email, because overlapping invocations are not prevented by cron itself. The classic defensive pattern is to wrap the command in flock on Linux or in a Kubernetes Job with concurrencyPolicy: Forbid at the CronJob layer.

Field Reference: Ranges, Syntax, and Special Characters

The table below summarizes the five fields, their valid ranges, and which special characters are accepted within each. This parser supports the four-character set used by Vixie cron: asterisk for wildcard, comma for list, hyphen for range, and slash for step.

Cron Field Reference: Ranges and Supported Syntax
Position Field Valid Range Special Characters Common Pitfall
1 Minute 0–59 * , - / Step */N is anchored at minute 0, not at install time
2 Hour 0–23 * , - / 24-hour format only; hour 24 is invalid, midnight is hour 0
3 Day of Month 1–31 * , - / (Quartz also: L W ?) February 30 and February 31 are accepted but never fire
4 Month 1–12 * , - / (and 3-letter names: JAN–DEC) Month names are accepted but case-sensitive in some implementations
5 Day of Week 0–6 (Sun–Sat) or 1–7 (Quartz) * , - / (Quartz also: L # ?) Sunday is 0 in Vixie, 1 in Quartz; both 0 and 7 accept Sunday in many implementations
Vixie cron is the de facto Linux standard. Quartz (Java) and AWS EventBridge add the L (last), W (nearest weekday), # (nth weekday), and ? (no-specific-value) characters. This tool implements the Vixie subset.

The asterisk wildcard is the most common operator and means “every valid value for this field.” A comma-separated list such as 1,15 in the day-of-month field selects the 1st and 15th of every month. A hyphen range like 9-17 in the hour field includes both endpoints. A slash step like */15 selects every 15th value starting from the field's lowest valid value — see the next section for why this trips up engineers expecting interval semantics.

Common Use Cases: Where Cron Syntax Shows Up

Cron syntax has outgrown its original Unix-daemon home and now appears in cloud schedulers, orchestrators, CI/CD systems, and workflow engines across the stack. Each system inherits the syntax with small but consequential dialect differences.

Unix Cron Jobs

The classic /etc/crontab file and per-user crontab -e entries on Linux and macOS use 5-field expressions with an optional 6th column for the user under which the job should run (system crontab only). The cron daemon — usually cron from Vixie, or its descendants cronie and ISC cron — wakes once per minute, evaluates every installed schedule, and forks any matches. PATH, MAILTO, and SHELL can be set as environment variables at the top of the crontab to control execution context. Logs land in /var/log/cron or are routed through syslog, depending on distribution defaults.

Kubernetes CronJob

The CronJob resource in Kubernetes wraps standard 5-field cron syntax and adds production-grade scheduling primitives that classic cron lacks: concurrencyPolicy (Allow, Forbid, or Replace) prevents overlapping job invocations; startingDeadlineSeconds caps how far behind a scheduled run can fall before being skipped; successfulJobsHistoryLimit and failedJobsHistoryLimit control retention of completed Pods. Since Kubernetes 1.27, the spec.timeZone field accepts IANA zone names so schedules no longer default to UTC silently.

AWS EventBridge Scheduler

AWS EventBridge (formerly CloudWatch Events) uses a 6-field cron syntax: minute, hour, day-of-month, month, day-of-week, year. It also requires exactly one of day-of-month and day-of-week to be ? (no-specific-value), mirroring Quartz semantics — the OR-rule from Vixie cron is forbidden. EventBridge supports the L, W, and # characters and interprets the schedule in UTC by default, with an optional ScheduleExpressionTimezone parameter on the rule.

Jenkins Build Triggers

Jenkins's “Build periodically” and “Poll SCM” triggers use 5-field cron syntax with one extension that classic cron lacks: the H (hash) character distributes load by deterministically jittering the actual fire time within the field's range, based on a hash of the job name. H 2 * * * means “some fixed minute between 0 and 59 at 2 AM, the same minute every day for this job” — preventing the thundering-herd problem when hundreds of jobs all literally fire at 02:00.

GitHub Actions Schedule Trigger

GitHub Actions on.schedule.cron accepts standard 5-field POSIX cron syntax, always interpreted in UTC, with no support for the L, W, #, or H characters. The official documentation warns that scheduled workflows may be delayed during periods of high load on the GitHub-hosted runner fleet, and that the minimum effective cadence is one trigger per five minutes regardless of what the cron string requests.

Apache Airflow DAG Schedules

Airflow uses 5-field cron syntax for its schedule_interval parameter, with two important Airflow-specific behaviors: a DAG run for interval ending at time T fires at time T (the “data interval” convention), not at the start of the interval; and Airflow's catchup parameter controls whether missed past intervals are backfilled when the scheduler is restarted. Airflow 2.4 added timetables as a more expressive replacement for cron, but cron syntax remains the default.

Edge Cases and Implementation Quirks

The behaviors below are the ones that most frequently cause production incidents and most frequently surprise engineers reading a cron string for the first time.

DST Transitions Can Skip or Duplicate Jobs

Cron schedules in local time. In the spring-forward transition (typically the second Sunday of March in U.S. zones), the wall clock jumps from 02:00 directly to 03:00 — the entire hour from 02:00 to 03:00 does not exist. Any cron job scheduled with a literal hour or minute inside that window is silently skipped. In the fall-back transition (typically the first Sunday of November), the wall clock falls from 02:00 back to 01:00, and the entire hour from 01:00 to 02:00 occurs twice. Vixie cron's response to this duplication has changed across versions: older versions ran jobs in the duplicated hour twice; newer versions track wallclock-vs-monotonic time and skip the second pass. The reliable mitigation is to run cron with TZ=UTC in its environment, scheduling everything against a clock that never jumps. Kubernetes CronJob with timeZone: UTC is the equivalent.

0 0 31 2 * Is Valid Syntax for an Impossible Date

Each field passes its own range validator independently: 31 is a valid day-of-month, 2 is a valid month. The combination “February 31” is never checked because cron has no semantic cross-field validator. The job is silently installed and silently never runs. The same trap catches 0 0 30 2 * (February 30), 0 0 31 4 * (April 31), and any other combination of a high day-of-month with a short month. Some validators (this tool included) compute the next five fire times and will display zero upcoming runs, which is the only obvious signal that something is wrong; a server-side cron daemon will give no signal at all.

*/7 Does Not Mean “Every 7”

The step operator anchors at the field's minimum value, not at install time and not at the previous fire time. In the minute field, */7 fires at minutes 0, 7, 14, 21, 28, 35, 42, 49, and 56 — and then jumps back to 0 of the next hour. The gap between minute 56 and the next minute 0 is only 4 minutes, not 7. This breaks any reasoning that depends on uniform spacing between fires. The same pattern affects */15 (clean), */30 (clean), */45 (broken: fires at 0 and 45 only, with a 15-minute gap at the hour boundary), and */13 (broken throughout). For genuine fixed-interval scheduling, use systemd timers with OnUnitActiveSec= or a sleep-loop daemon.

5-Field vs. 6-Field vs. 7-Field Crons

POSIX cron and Vixie cron use 5 fields. Quartz cron prefixes a seconds field for a 6-field format and appends a year field for a 7-field format — the full Quartz expression is seconds minutes hours day-of-month month day-of-week year. Spring's @Scheduled annotation uses the Quartz 6-field format. AWS EventBridge uses 6 fields with year (not seconds). The same string is therefore not portable across systems without explicit translation: 0 0 12 * * ? in Quartz means “noon every day” (with day-of-week explicitly disabled), but pasting it into Vixie cron produces a parse error because Vixie sees too many fields.

Leap Year Handling

The day-of-month field accepts 29 unconditionally. A job scheduled at 0 0 29 2 * fires on February 29 of leap years and is silently skipped in non-leap years — a four-year cadence that is rarely intentional but easy to write by accident. Both this tool and standard Vixie cron compute the next-fire date against the actual Gregorian calendar, so leap year semantics emerge correctly from the minute-by-minute scan; no special-case code is required.

Day-of-Month and Day-of-Week Are OR-ed in Vixie Cron

When both day-of-month and day-of-week are restricted (neither is the wildcard), Vixie cron fires if either field matches — not if both match. The expression 0 0 15 * 1 fires at midnight on the 15th of every month and every Monday, not “the 15th when it is also a Monday.” This dates back to Paul Vixie's 1987 implementation and is documented in the cron(8) man page, but it routinely surprises engineers who reason about it as logical conjunction. Quartz and EventBridge forbid the ambiguity by requiring exactly one of those two fields to be the ? character.

Behind the Scenes: The Cron Specification and Its Forks

POSIX Cron and the Vixie Lineage

The POSIX specification for cron is sparse — it standardizes the 5-field format, the four special characters (asterisk, comma, hyphen, slash), and the eight named shortcuts (@reboot, @yearly, @annually, @monthly, @weekly, @daily, @midnight, @hourly). Paul Vixie's 1987 reimplementation, distributed with BSD and later adopted by every major Linux distribution, added the small set of behaviors that practitioners now treat as “standard cron”: per-user crontabs via crontab -e, MAILTO routing of stdout, the OR-rule for day-of-month and day-of-week, and 3-letter month and day-of-week name aliases. cronie (Red Hat) and ISC cron (Debian) both descend directly from Vixie cron with minor patches.

Quartz, the Java Scheduling Library

Quartz extended classic cron to support sub-minute scheduling (the leading seconds field), single-fire scheduling (the trailing year field), and three additional special characters: L for “last” (last day of month, last weekday), W for “nearest weekday,” and # for “nth weekday of the month” (e.g., 2#1 means “the first Monday of the month”). Quartz forbids the Vixie OR-rule by requiring the ? character in exactly one of day-of-month and day-of-week, which removes the ambiguity at the syntax level.

systemd Timers as a Cron Replacement

systemd timers, introduced with systemd 197 in 2013, provide a deliberately different scheduling model. Calendar-based timers use the OnCalendar= directive with systemd's own calendar event syntax, which is more verbose than cron but less ambiguous: OnCalendar=Mon..Fri 09:00 is the systemd equivalent of 0 9 * * 1-5. Monotonic timers use OnUnitActiveSec=2d for true 48-hour intervals independent of calendar boundaries — solving the “every other day” problem that classic cron cannot express. Timers also gain systemd's full unit machinery: dependency ordering, resource limits, persistent state across reboots, and journal-based logging.

Leap Seconds and Local Time

Cron evaluates schedules against the system's local time, advanced by the kernel's wallclock. Leap seconds — extra seconds inserted at midnight UTC on June 30 or December 31 to keep UTC aligned with the actual rotation of the Earth — are handled by the kernel either as a 61-second minute (the traditional method) or as a smear across multiple seconds (Google's method, now common in cloud environments). Neither method causes cron to skip or duplicate jobs, because cron operates at minute granularity and a 61-second minute still has exactly one minute-0 transition. The cron(8) man page documents this behavior and recommends running cron under TZ=UTC for any job whose timing is genuinely critical.

Why Cron Uses Local Time by Default

The original 1975 cron, written by Brian Kernighan for Unix V7, used the system's local time because there was no other clock to use — UTC as a distinct concept on Unix systems was not formalized until later. Every cron implementation since has preserved that default for backward compatibility, even though it is the source of most DST-related outages in modern systems. Both Kubernetes CronJob (1.27+) and AWS EventBridge default to UTC, deliberately breaking from the cron tradition because their users overwhelmingly run jobs that should not respect local DST shifts.

Comparison: Classic Cron vs. systemd Timers vs. Quartz vs. Kubernetes CronJob vs. AWS EventBridge

Five different schedulers, five overlapping but non-identical dialects of cron syntax. The table below summarizes the most consequential differences when porting an expression between systems.

Scheduler Feature Comparison: Cron Dialects in Five Production Systems
Feature Classic Cron (Vixie) systemd Timers Quartz Kubernetes CronJob AWS EventBridge
Field count 5 N/A (own syntax) 6 or 7 5 6 (with year)
Minimum granularity 1 minute 1 second 1 second 1 minute 1 minute
Time zone Local (server) Local or per-unit Per-trigger UTC default, per-job since 1.27 UTC default, per-rule
Last-day-of-month Not supported (workaround required) Not supported L character Not supported L character
Nth weekday Not supported Not supported # character Not supported # character
DoM/DoW interaction OR (both restricted) AND Requires ? in one OR (Vixie-style) Requires ? in one
Concurrency control External (flock) Unit-level Built-in concurrencyPolicy Not built-in
Persistence across reboots Yes (file-based) Yes (Persistent=true) Depends on store Yes (etcd) Yes (AWS-managed)
DST handling Skips/duplicates jobs Monotonic option Per-trigger TZ UTC avoids issue UTC avoids issue
The most common porting mistake: copying a Vixie expression like 0 0 15 * 1 into AWS EventBridge or Quartz, where it is rejected because both day-of-month and day-of-week are restricted without a ?. The OR-rule that makes the expression meaningful in Vixie is forbidden by syntax in the stricter dialects.

For new infrastructure, the practical guidance is to default to UTC scheduling regardless of platform (this eliminates the entire class of DST bugs), prefer systemd timers for single-host scheduling on Linux (better logging, better dependency model, monotonic intervals), and prefer Kubernetes CronJob for clustered workloads (concurrency policy and resource quotas are first-class). Classic cron remains useful for personal crontabs and legacy systems, but new production schedules increasingly belong somewhere else.

Related Tools

After validating a cron expression, the natural next step is often to convert the next-fire times between zones, to test a related time-handling routine in your code, or to compute a date offset by hand. The Timestamp Converter converts Unix epoch values to ISO 8601 strings in any time zone — useful when comparing the timestamps your cron job produces to the timestamps the scheduler logs internally. The Time Zone Converter handles the inverse case: you have a fire time in your local zone and need to know what UTC offset that becomes for a Kubernetes CronJob spec.

For batch work with many timestamps at once — for example, when verifying that a cron-driven export produced files at the expected cadence — the Batch Timestamp Converter handles columns of epoch values rather than one at a time. The Date Calculator answers “what is the date 47 weekdays from today,” which closes the loop on schedules where the gating condition is calendar-based rather than time-based. And the Crontab Cheat Sheet is the one-page reference for the syntax surface this parser implements.

Frequently Asked Questions

The expression */5 * * * * runs the job at minutes 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, and 55 of every hour of every day. The slash defines a step, not an interval relative to the moment the job was installed: */5 starts counting from 0, not from the current minute. So a job installed at 12:03 with the schedule */5 * * * * first fires at 12:05, not 12:08. This zero-anchored stepping is a frequent source of confusion when migrating ad-hoc setInterval logic into cron.
There is no clean way to express “every other day” in classic cron, because the step value in the day-of-month field is anchored to day 1 and resets on the first of every month. The expression 0 0 */2 * * fires on days 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31 — but then the next firing is day 1 of the following month, which may be only one day later if the previous month had 31 days. For a true 48-hour cadence, run daily and gate the body of the job with an external counter (a file, environment variable, or database row), or migrate to systemd timers, which support OnUnitActiveSec=2d for accurate interval scheduling independent of calendar boundaries.
Classic Unix cron interprets schedules in the server's local time zone. When the clock springs forward in spring DST, the interval from 02:00 to 03:00 simply does not exist — any job scheduled at 02:30 is skipped silently. When the clock falls back in autumn, the interval from 01:00 to 02:00 occurs twice, and Vixie cron will run a job scheduled in that window twice as well unless the job has explicit deduplication. The safest fix is to run sensitive jobs in UTC: either run cron itself with TZ=UTC in its environment, or schedule the job outside the DST transition window (jobs scheduled at 04:00 or later avoid the issue entirely in U.S. time zones). Kubernetes CronJob supports timeZone: 'UTC' as a per-job field, and systemd timers default to the unit's CLOCK_REALTIME, which advances cleanly through DST transitions.
The expression 0 0 31 2 * is syntactically valid — it passes field-range validation, since 31 falls inside the 1–31 day-of-month range and 2 falls inside the 1–12 month range. Semantically, however, it never fires: February 31 does not exist in any calendar year. Cron does not warn about this; the job is silently scheduled and silently never runs. The parser on this page accepts the expression and will compute zero upcoming run times within the next year. Other impossible combinations include 0 0 30 2 * (February 30) and 0 0 31 4 * (April 31). To run a job on the actual last day of a month, see the next FAQ — classic cron has no native solution and requires a Sunday-style workaround.
Classic POSIX cron has no native syntax for “last day of month” — every day-of-month value must be a literal integer in the 1–31 range. The standard workaround is to run a daily job and gate it on a date check inside the script: 0 23 28-31 * * [ "$(date +%d -d tomorrow)" = "01" ] && /path/to/job. This runs every day from the 28th through the 31st, then checks whether tomorrow's date is the first of the next month — which is true only on the actual last day of the current month. Quartz extends classic cron with an L character for exactly this case: 0 0 0 L * ? fires at midnight on the last day of every month. Kubernetes CronJob, AWS EventBridge, and most other modern schedulers inherit either the classic POSIX syntax (no L support) or the Quartz extensions (L supported).
This is the most surprising semantic in cron, and it differs between implementations. In Vixie cron — the standard on most Linux distributions — when both day-of-month and day-of-week are restricted (neither is the wildcard *), the job runs when either condition matches, not when both match. The expression 0 0 15 * 1 fires at midnight on the 15th of every month AND every Monday — not “the 15th if it is also a Monday.” This OR-instead-of-AND behavior dates back to the original Vixie cron in 1987 and is documented in the man page, but it routinely surprises engineers who reason about it as logical conjunction. Quartz, by contrast, requires that exactly one of day-of-month and day-of-week be a question mark (?) — it forbids the ambiguity entirely. AWS EventBridge follows the Quartz convention.
Classic Unix cron uses 5-field expressions whose smallest unit is one minute — sub-minute scheduling is not expressible. Quartz cron and Spring's @Scheduled extension use a 6-field format with a leading seconds field (0–59), which permits scheduling down to once per second. Kubernetes CronJob uses classic 5-field syntax and inherits the 60-second floor; for sub-minute work in Kubernetes, the standard pattern is a deployment with a sleep-loop container or a sidecar that fans out work internally. AWS EventBridge supports per-minute as its tightest schedule. If you need genuine sub-second cadence, cron is the wrong tool — use a long-running daemon, a message queue with delay support, or a tick-based scheduler within your application process.
Kubernetes 1.27 and later support a timeZone field directly on the CronJob spec: under spec.timeZone, set an IANA time zone name such as America/New_York or Asia/Tokyo. Before 1.27, the kube-controller-manager interpreted the schedule in UTC regardless of the cluster node's local time, which routinely caused “midnight” jobs to fire at 4 PM local for U.S. East Coast clusters. Always specify the timezone explicitly even if it matches the cluster default — relying on the default makes the manifest non-portable to a cluster in a different region. The timeZone field accepts only the canonical zoneinfo names from the IANA database (the tzdata package on Linux). Aliases like EST or PST are rejected by the validator.