Skip to content
GitHub Agentic Workflows

Fuzzy Schedule Time Syntax Specification

Version: 1.1.0
Status: Draft Specification
Latest Version: fuzzy-schedule-specification
Editor: GitHub Agentic Workflows Team


This specification defines the Fuzzy Schedule Time Syntax, a human-friendly scheduling language for GitHub Agentic Workflows that automatically distributes workflow execution times to prevent server load spikes. The syntax supports daily, hourly, weekly, and interval-based schedules with optional time constraints and timezone conversions. The specification includes a deterministic scattering algorithm that uses hash functions to assign consistent execution times to workflows based on their identifiers, ensuring predictable behavior across multiple compilations while distributing load across an organization’s infrastructure.

This section describes the status of this document at the time of publication. This is a draft specification and may be updated, replaced, or made obsolete by other documents at any time.

This document is governed by the GitHub Agentic Workflows project specifications process.

  1. Introduction
  2. Conformance
  3. Core Syntax
  4. Time Specifications
  5. Timezone Support
  6. Scattering Algorithm
  7. Cron Expression Generation
  8. Error Handling
  9. Compliance Testing

The Fuzzy Schedule Time Syntax addresses the problem of server load spikes that occur when multiple workflows execute simultaneously using fixed-time schedules. Traditional cron expressions require explicit time specifications, leading developers to commonly use convenient times (e.g., midnight, on-the-hour) that create load concentration. This specification defines a natural language syntax that automatically distributes execution times while preserving schedule semantics.

This specification covers:

  • Natural language schedule expressions for daily, hourly, weekly, and interval-based schedules
  • Time constraint syntax using around and between modifiers
  • Timezone conversion syntax for local-to-UTC time translation
  • Deterministic scattering algorithm for execution time distribution
  • Cron expression generation from fuzzy syntax
  • Validation requirements and error handling

This specification does NOT cover:

  • Standard cron expression syntax (handled by GitHub Actions)
  • Monthly or yearly schedule patterns
  • Dynamic schedule adjustment based on load metrics
  • Schedule conflict resolution between workflows

This specification prioritizes:

  1. Human readability: Natural language expressions that clearly communicate intent
  2. Load distribution: Automatic scattering prevents simultaneous workflow execution
  3. Determinism: Same workflow identifier always produces same execution time
  4. Predictability: Execution times remain consistent across recompilations
  5. Timezone awareness: Support for local time specifications with UTC conversion

A conforming implementation is a parser that satisfies all MUST, MUST NOT, REQUIRED, SHALL, and SHALL NOT requirements in this specification.

A conforming fuzzy schedule expression is a schedule string that conforms to the syntax grammar defined in Section 3 and produces a valid fuzzy cron placeholder.

A conforming scattering implementation is an implementation that satisfies all scattering algorithm requirements in Section 6.

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

Level 1 (Basic): Supports daily and weekly schedules without time constraints

Level 2 (Standard): Adds support for time constraints (around, between) and hourly schedules

Level 3 (Complete): Includes timezone conversion, interval schedules, and bi-weekly/tri-weekly patterns


A fuzzy schedule expression MUST conform to the following ABNF grammar:

fuzzy-schedule = daily-schedule / hourly-schedule / weekly-schedule / interval-schedule
daily-schedule = "daily" [time-constraint]
weekly-schedule = "weekly" ["on" weekday] [time-constraint]
hourly-schedule = "hourly" / ("every" hour-interval)
interval-schedule = "every" (minute-interval / hour-interval / day-interval / week-interval)
time-constraint = around-constraint / between-constraint
around-constraint = "around" time-spec
between-constraint = "between" time-spec "and" time-spec
time-spec = (hour-24 ":" minute) [utc-offset]
/ (hour-12 am-pm) [utc-offset]
/ time-keyword [utc-offset]
time-keyword = "midnight" / "noon"
am-pm = "am" / "pm"
utc-offset = "utc" ("+" / "-") (hours / hours ":" minutes)
weekday = "sunday" / "monday" / "tuesday" / "wednesday"
/ "thursday" / "friday" / "saturday"
hour-24 = 1*2DIGIT ; 0-23
hour-12 = 1*2DIGIT ; 1-12
minute = 2DIGIT ; 00-59
hours = 1*2DIGIT
minutes = 2DIGIT
minute-interval = 1*DIGIT ("m" / "minutes" / "minute")
hour-interval = 1*DIGIT ("h" / "hours" / "hour")
day-interval = 1*DIGIT ("d" / "days" / "day")
week-interval = 1*DIGIT ("w" / "weeks" / "week")

A basic daily schedule expression SHALL take the form:

daily

An implementation MUST generate a fuzzy cron placeholder: FUZZY:DAILY * * *

The execution time SHALL be deterministically scattered across all 24 hours and 60 minutes of the day.

A daily around schedule expression SHALL take the form:

daily around <time-spec>

An implementation MUST generate a fuzzy cron placeholder: FUZZY:DAILY_AROUND:HH:MM * * *

The execution time SHALL be scattered within a ±60 minute window around the specified time.

Example:

daily around 14:00
# Generates: FUZZY:DAILY_AROUND:14:0 * * *
# Scatters within window: 13:00 to 15:00

A daily between schedule expression SHALL take the form:

daily between <start-time> and <end-time>

An implementation MUST generate a fuzzy cron placeholder: FUZZY:DAILY_BETWEEN:START_H:START_M:END_H:END_M * * *

The execution time SHALL be scattered uniformly within the specified time range, including handling of midnight-crossing ranges.

Example:

daily between 9:00 and 17:00
# Generates: FUZZY:DAILY_BETWEEN:9:0:17:0 * * *
# Scatters within window: 09:00 to 17:00
daily between 22:00 and 02:00
# Generates: FUZZY:DAILY_BETWEEN:22:0:2:0 * * *
# Scatters within window: 22:00 to 02:00 (crossing midnight)

A basic weekly schedule expression SHALL take the form:

weekly

An implementation MUST generate a fuzzy cron placeholder: FUZZY:WEEKLY * * *

The execution SHALL be scattered across all seven days of the week and all hours/minutes of each day.

A weekly day schedule expression SHALL take the form:

weekly on <weekday>

An implementation MUST generate a fuzzy cron placeholder: FUZZY:WEEKLY:DOW * * DOW

Example:

weekly on monday
# Generates: FUZZY:WEEKLY:1 * * 1
# Scatters across all hours on Monday

A weekly schedule MAY include time constraints using around or between:

weekly on <weekday> around <time-spec>
weekly on <weekday> between <start-time> and <end-time>

Example:

weekly on friday around 17:00
# Generates: FUZZY:WEEKLY:5:AROUND:17:0 * * 5
# Scatters Friday 16:00-18:00

A basic hourly schedule expression SHALL take the form:

hourly

An implementation MUST generate a fuzzy cron placeholder: FUZZY:HOURLY * * *

The minute offset SHALL be scattered across 0-59 minutes but remain consistent for each hour.

Example:

hourly
# Generates: FUZZY:HOURLY * * *
# Might scatter to: 43 * * * * (runs at minute 43 every hour)

An hour interval schedule expression SHALL take the form:

every <N>h
every <N> hours
every <N> hour

Where <N> MUST be a positive integer.

An implementation MUST generate a fuzzy cron placeholder: FUZZY:HOURLY:<N> * * *

Valid hour intervals SHOULD be: 1, 2, 3, 4, 6, 8, 12 (factors of 24 for even distribution).

Example:

every 2h
# Generates: FUZZY:HOURLY:2 * * *
# Might scatter to: 53 */2 * * * (runs at minute 53 every 2 hours)

A bi-weekly schedule expression SHALL take the form:

bi-weekly

An implementation MUST generate a fuzzy cron placeholder: FUZZY:BI-WEEKLY * * *

The schedule SHALL execute once every 14 days with scattered time.

A tri-weekly schedule expression SHALL take the form:

tri-weekly

An implementation MUST generate a fuzzy cron placeholder: FUZZY:TRI-WEEKLY * * *

The schedule SHALL execute once every 21 days with scattered time.

An interval schedule expression SHALL take the form:

every <N> <unit>

Where:

  • <N> MUST be a positive integer
  • <unit> MUST be one of: minutes, minute, m, hours, hour, h, days, day, d, weeks, week, w

An implementation MUST generate appropriate cron expressions based on the unit:

  • Minutes: */N * * * * (minimum N=5 per GitHub Actions constraint)
  • Hours: FUZZY:HOURLY:N * * * (scattered minute)
  • Days: 0 0 */N * * (fixed midnight)
  • Weeks: 0 0 */N*7 * * (fixed Sunday midnight)

Example:

every 5 minutes
# Generates: */5 * * * *
every 6h
# Generates: FUZZY:HOURLY:6 * * *
every 2 days
# Generates: 0 0 */2 * *

An implementation MUST support the following time formats:

The 24-hour format SHALL use the pattern HH:MM:

  • Hours MUST be in range 0-23
  • Minutes MUST be in range 0-59
  • Leading zeros MAY be omitted for hours
  • Minutes MUST use two digits with leading zero if necessary

Valid examples: 00:00, 9:30, 14:00, 23:59

The 12-hour format SHALL use the pattern H[H]am or H[H]pm:

  • Hours MUST be in range 1-12
  • AM/PM indicator MUST be lowercase am or pm
  • Minutes MAY be omitted (defaults to :00)
  • Colon and minutes MAY be included (e.g., 3:30pm)

Valid examples: 1am, 12pm, 11pm, 9am, 3:30pm

Conversion rules:

  • 12am converts to 00:00 (midnight)
  • 12pm converts to 12:00 (noon)
  • 1am-11am converts to 01:00-11:00
  • 1pm-11pm converts to 13:00-23:00

An implementation MUST support the following time keywords:

  • midnight: Represents 00:00 (start of day)
  • noon: Represents 12:00 (middle of day)

Keywords MUST be case-insensitive.

When using around <time>, the implementation MUST use a ±60 minute window centered on the specified time.

The window MUST handle day boundaries correctly:

  • around 00:30 creates window: 23:30 (previous day) to 01:30
  • around 23:30 creates window: 22:30 to 00:30 (next day)

When using between <start> and <end>, the implementation MUST:

  1. Accept ranges within a single day (e.g., 9:00 to 17:00)
  2. Accept ranges crossing midnight (e.g., 22:00 to 02:00)
  3. Calculate range size correctly for midnight-crossing ranges
  4. Distribute scattered times uniformly within the range

For midnight-crossing ranges where start > end:

  • Range size = (24*60 - start_minutes) + end_minutes

Example:

between 22:00 and 02:00
# Range: 22:00, 22:01, ..., 23:59, 00:00, ..., 02:00
# Duration: 4 hours (240 minutes)

An implementation MUST support UTC offset specifications using the format:

utc-offset = "utc" ("+" / "-") offset-value
offset-value = hours / hours ":" minutes

Where:

  • hours MAY be 1 or 2 digits
  • minutes MUST be 2 digits when specified
  • Offset MUST be in range UTC-12:00 to UTC+14:00

Valid examples: utc+9, utc-5, utc+05:30, utc-08:00

When a UTC offset is specified, the implementation MUST:

  1. Parse the local time value
  2. Parse the UTC offset value (in minutes)
  3. Subtract the offset from the local time to get UTC time
  4. Handle day wrapping correctly

Formula: UTC_time = local_time - offset

Example:

local_time = 14:00 (2 PM)
offset = +9 hours (JST)
UTC_time = 14:00 - 9:00 = 05:00 (5 AM UTC)

The implementation MUST handle day boundaries when converting times:

  • Negative results MUST wrap to previous day (add 24 hours)
  • Results ≥24:00 MUST wrap to next day (subtract 24 hours)
  • Wrap operations MUST preserve minute precision

Example:

local_time = 02:00 (2 AM)
offset = +9 hours
UTC_time = 02:00 - 9:00 = -7:00 → 17:00 (previous day)

An implementation SHOULD recognize common timezone abbreviations:

AbbreviationUTC OffsetNotes
PSTUTC-8Pacific Standard Time
PDTUTC-7Pacific Daylight Time
ESTUTC-5Eastern Standard Time
EDTUTC-4Eastern Daylight Time
JSTUTC+9Japan Standard Time
ISTUTC+5:30India Standard Time

Implementations MAY issue warnings for ambiguous abbreviations (e.g., “PT” could be PST or PDT).


The scattering algorithm MUST provide:

  1. Determinism: Same workflow identifier produces same scattered time
  2. Distribution: Scattered times distribute evenly across the allowed range
  3. Stability: Scattered times remain constant across recompilations
  4. Uniqueness: Different workflow identifiers produce different scattered times

An implementation MUST use a hash function that satisfies the following requirements:

  1. Determinism: The hash function MUST produce the same output for the same input across all platforms and executions
  2. Distribution: The hash function SHOULD produce uniformly distributed outputs across the hash space
  3. Stability: The hash function MUST NOT change behavior across different versions of the implementation
  4. Integer output: The hash function MUST produce an integer output suitable for modulo operations

An implementation SHOULD use the FNV-1a (Fowler-Noll-Vo) 32-bit hash algorithm as a reference implementation:

hash = FNV_offset_basis
for each byte in input:
hash = hash XOR byte
hash = hash * FNV_prime
return hash
Where:
FNV_offset_basis = 2166136261 (0x811c9dc5)
FNV_prime = 16777619 (0x01000193)

Other suitable hash functions MAY be used, such as MurmurHash, xxHash, or CityHash, provided they meet the above requirements.

The workflow identifier used for hashing MUST be constructed as:

workflow_identifier = repository_slug + "/" + workflow_file_path

Where:

  • repository_slug is the format owner/repo
  • workflow_file_path is the relative path from repository root

Example: github/gh-aw/.github/workflows/daily-report.md

This format ensures workflows with the same filename in different repositories receive different execution times.

For FUZZY:DAILY * * *:

  1. Calculate hash modulo 1440 (24 hours * 60 minutes)
  2. Convert result to hour and minute components
  3. Generate cron: <minute> <hour> * * *

Example:

hash("github/gh-aw/workflow.md") % 1440 = 343
hour = 343 / 60 = 5
minute = 343 % 60 = 43
cron = "43 5 * * *" (5:43 AM)

For FUZZY:DAILY_AROUND:HH:MM * * *:

  1. Calculate target time in minutes: target_minutes = HH * 60 + MM
  2. Define window: [-60, +59] minutes from target
  3. Calculate hash modulo 120 (window size)
  4. Calculate offset: offset = hash_result - 60
  5. Calculate scattered time: scattered_minutes = target_minutes + offset
  6. Handle day wrapping (keep within 0-1439)
  7. Convert to hour and minute

Example:

target = 14:00 (840 minutes)
hash % 120 = 73
offset = 73 - 60 = 13
scattered = 840 + 13 = 853 minutes
hour = 853 / 60 = 14
minute = 853 % 60 = 13
cron = "13 14 * * *" (2:13 PM, within 13:00-15:00 window)

For FUZZY:DAILY_BETWEEN:START_H:START_M:END_H:END_M * * *:

  1. Calculate start and end times in minutes
  2. Calculate range size (handling midnight crossing)
  3. Calculate hash modulo range_size
  4. Add hash_result to start_minutes
  5. Handle day wrapping
  6. Convert to hour and minute

For midnight-crossing ranges (start > end):

range_size = (24 * 60 - start_minutes) + end_minutes

Example:

range = 9:00 to 17:00
start_minutes = 540, end_minutes = 1020
range_size = 1020 - 540 = 480 minutes (8 hours)
hash % 480 = 217
scattered = 540 + 217 = 757 minutes
hour = 757 / 60 = 12
minute = 757 % 60 = 37
cron = "37 12 * * *" (12:37 PM)

For FUZZY:HOURLY * * *:

  1. Calculate hash modulo 60
  2. Use result as minute offset
  3. Generate cron: <minute> * * * *

Example:

hash % 60 = 43
cron = "43 * * * *" (runs at minute 43 every hour)

For FUZZY:HOURLY:N * * *:

  1. Calculate hash modulo 60
  2. Use result as minute offset
  3. Generate cron: <minute> */N * * *

Example:

interval = 2 hours
hash % 60 = 53
cron = "53 */2 * * *" (runs at minute 53 every 2 hours)

For FUZZY:WEEKLY * * *:

  1. Calculate hash modulo (7 * 24 * 60) = 10080 (week in minutes)
  2. Extract day-of-week: day = (hash_result / 1440) % 7
  3. Extract time: time_in_minutes = hash_result % 1440
  4. Convert time to hour and minute
  5. Generate cron: <minute> <hour> * * <day>

For FUZZY:WEEKLY:DOW * * DOW:

  1. Day is fixed from expression
  2. Calculate hash modulo 1440 (day in minutes)
  3. Convert to hour and minute
  4. Generate cron: <minute> <hour> * * <day>

Example:

weekly on monday
day = 1 (Monday)
hash % 1440 = 343
hour = 5, minute = 43
cron = "43 5 * * 1" (Monday 5:43 AM)

For FUZZY:BI-WEEKLY * * *:

  1. Calculate hash modulo 1440
  2. Convert to hour and minute
  3. Generate cron: <minute> <hour> */14 * *

For FUZZY:TRI-WEEKLY * * *:

  1. Calculate hash modulo 1440
  2. Convert to hour and minute
  3. Generate cron: <minute> <hour> */21 * *

An implementation MUST ensure:

  1. Hash function produces same output for same input across platforms
  2. Modulo operations use consistent integer division
  3. Day wrapping uses consistent addition/subtraction rules
  4. Minute and hour extraction uses consistent division and modulo operations

An implementation MUST generate fuzzy cron placeholders that can be resolved later by the scattering algorithm. Placeholders MUST use the format:

FUZZY:<TYPE>[:<PARAMS>] <cron-fields>

Where:

  • <TYPE> identifies the schedule type
  • <PARAMS> provides optional parameters (time, day, range)
  • <cron-fields> includes remaining cron fields (typically * * *)
Schedule TypePlaceholder Format
DailyFUZZY:DAILY * * *
Daily aroundFUZZY:DAILY_AROUND:HH:MM * * *
Daily betweenFUZZY:DAILY_BETWEEN:SH:SM:EH:EM * * *
HourlyFUZZY:HOURLY * * *
Hour intervalFUZZY:HOURLY:N * * *
WeeklyFUZZY:WEEKLY * * *
Weekly with dayFUZZY:WEEKLY:DOW * * DOW
Weekly day aroundFUZZY:WEEKLY:DOW:AROUND:HH:MM * * DOW
Weekly day betweenFUZZY:WEEKLY:DOW:BETWEEN:SH:SM:EH:EM * * DOW
Bi-weeklyFUZZY:BI-WEEKLY * * *
Tri-weeklyFUZZY:TRI-WEEKLY * * *

An implementation MUST provide a mechanism to resolve fuzzy placeholders to concrete cron expressions using the scattering algorithm and workflow identifier.

The resolution process MUST:

  1. Detect fuzzy placeholder format
  2. Extract schedule type and parameters
  3. Apply appropriate scattering algorithm
  4. Generate valid 5-field cron expression
  5. Validate resulting cron expression

Generated cron expressions MUST conform to GitHub Actions cron syntax:

  • 5 fields: minute hour day-of-month month day-of-week
  • Minutes: 0-59 or * or */N
  • Hours: 0-23 or * or */N
  • Day-of-month: 1-31 or * or */N
  • Month: 1-12 or * or */N
  • Day-of-week: 0-6 (Sunday=0) or *

An implementation MUST reject invalid expressions with clear error messages:

Error: Unknown schedule type 'monthly'
Valid types: daily, weekly, hourly, bi-weekly, tri-weekly, every
Error: Invalid time format '25:00' in 'daily around 25:00'
Time must be in 24-hour format (HH:MM, 0-23 hours) or 12-hour format with am/pm
Error: Unknown weekday 'mondey' in 'weekly on mondey'
Valid weekdays: sunday, monday, tuesday, wednesday, thursday, friday, saturday
Error: Invalid interval '5' in 'every 5h'
Valid hour intervals: 1h, 2h, 3h, 4h, 6h, 8h, 12h
Error: 'around' requires a time specification
Example: daily around 14:00
Error: 'daily at <time>' syntax is not supported
Use 'daily around <time>' for fuzzy scheduling within ±1 hour window

An implementation SHOULD issue warnings for valid but suboptimal patterns:

Warning: Consider using 'every 2h' instead of fixed interval
Fixed intervals create load spikes when many workflows run simultaneously

An implementation SHOULD NOT attempt to correct syntax errors automatically. All errors MUST be reported to the user with actionable correction guidance.


A conforming implementation MUST pass all Level 1 tests. Implementations claiming Level 2 or Level 3 conformance MUST pass all tests for their claimed level and all lower levels.

  • T-SYNTAX-001: Parse daily to FUZZY:DAILY * * *
  • T-SYNTAX-002: Parse weekly to FUZZY:WEEKLY * * *
  • T-SYNTAX-003: Parse weekly on monday to FUZZY:WEEKLY:1 * * 1
  • T-SYNTAX-004: Parse all weekday names correctly
  • T-SYNTAX-005: Reject invalid schedule types
  • T-SYNTAX-006: Reject invalid weekday names
  • T-SYNTAX-007: Parse case-insensitive tokens
  • T-TIME-001: Parse 24-hour format 14:00
  • T-TIME-002: Parse 12-hour format 3pm
  • T-TIME-003: Parse 12-hour format 11am
  • T-TIME-004: Parse keyword midnight as 00:00
  • T-TIME-005: Parse keyword noon as 12:00
  • T-TIME-006: Convert 12am to 00:00 (midnight)
  • T-TIME-007: Convert 12pm to 12:00 (noon)
  • T-TIME-008: Reject invalid hours (>23 or <0)
  • T-TIME-009: Reject invalid minutes (>59 or <0)
  • T-TIME-010: Handle missing leading zeros (e.g., 9:30)
  • T-CONSTRAINT-001: Parse daily around 14:00
  • T-CONSTRAINT-002: Parse daily between 9:00 and 17:00
  • T-CONSTRAINT-003: Parse weekly on friday around 17:00
  • T-CONSTRAINT-004: Handle midnight-crossing ranges (22:00 and 02:00)
  • T-CONSTRAINT-005: Reject around without time specification
  • T-CONSTRAINT-006: Reject between with only one time
  • T-CONSTRAINT-007: Reject daily at <time> syntax
  • T-TZ-001: Parse utc+9 offset
  • T-TZ-002: Parse utc-5 offset
  • T-TZ-003: Parse utc+05:30 offset format
  • T-TZ-004: Convert 14:00 utc+9 to 05:00 UTC
  • T-TZ-005: Convert 3pm utc-5 to 20:00 UTC
  • T-TZ-006: Handle negative UTC conversion (wrap to previous day)
  • T-TZ-007: Handle >24:00 UTC conversion (wrap to next day)
  • T-TZ-008: Reject invalid offsets (e.g., utc+25)

9.2.5 Hourly and Interval Tests (Level 2/3)

Section titled “9.2.5 Hourly and Interval Tests (Level 2/3)”
  • T-HOURLY-001: Parse hourly to FUZZY:HOURLY * * *
  • T-HOURLY-002: Parse every 2h to FUZZY:HOURLY:2 * * *
  • T-HOURLY-003: Parse every 6 hours to FUZZY:HOURLY:6 * * *
  • T-INTERVAL-001: Parse every 5 minutes to */5 * * * *
  • T-INTERVAL-002: Parse every 2 days to 0 0 */2 * *
  • T-INTERVAL-003: Reject every 3 minutes (below 5-minute minimum)
  • T-INTERVAL-004: Parse bi-weekly to FUZZY:BI-WEEKLY * * *
  • T-INTERVAL-005: Parse tri-weekly to FUZZY:TRI-WEEKLY * * *

9.2.6 Scattering Algorithm Tests (Level 1-3)

Section titled “9.2.6 Scattering Algorithm Tests (Level 1-3)”
  • T-SCATTER-001: Hash produces same output for same input
  • T-SCATTER-002: Different inputs produce different outputs
  • T-SCATTER-003: Hash value is within modulo range (0 to modulo-1)
  • T-SCATTER-004: Daily schedule scatters across full 24-hour period
  • T-SCATTER-005: Around schedule stays within ±60 minute window
  • T-SCATTER-006: Between schedule stays within specified range
  • T-SCATTER-007: Midnight-crossing range handles day wrap correctly
  • T-SCATTER-008: Hourly schedule produces minute 0-59
  • T-SCATTER-009: Weekly schedule selects valid day 0-6
  • T-SCATTER-010: Same workflow gets same time across compilations
  • T-CRON-001: Generated cron has exactly 5 fields
  • T-CRON-002: Minute field is in range 0-59
  • T-CRON-003: Hour field is in range 0-23
  • T-CRON-004: Day-of-week field is in range 0-6 or *
  • T-CRON-005: Month and day-of-month are valid
  • T-CRON-006: Interval expressions use valid */N syntax
RequirementTest IDLevelStatus
Parse basic dailyT-SYNTAX-0011Required
Parse basic weeklyT-SYNTAX-0021Required
Parse weekday specificationT-SYNTAX-0031Required
Parse all weekday namesT-SYNTAX-0041Required
Reject invalid typesT-SYNTAX-0051Required
Case-insensitive parsingT-SYNTAX-0071Required
Parse 24-hour formatT-TIME-0012Required
Parse 12-hour formatT-TIME-002, 0032Required
Parse time keywordsT-TIME-004, 0052Required
Handle 12am/12pm correctlyT-TIME-006, 0072Required
Validate time rangesT-TIME-008, 0092Required
Parse around constraintsT-CONSTRAINT-0012Required
Parse between constraintsT-CONSTRAINT-0022Required
Handle midnight crossingT-CONSTRAINT-0042Required
Parse UTC offsetsT-TZ-001, 002, 0033Required
Convert timezones correctlyT-TZ-004, 0053Required
Handle timezone day wrapT-TZ-006, 0073Required
Parse hourly schedulesT-HOURLY-001, 002, 0032Required
Parse interval schedulesT-INTERVAL-001, 0023Required
Hash determinismT-SCATTER-001, 0021Required
Scattering distributionT-SCATTER-004-0091-3Required
Generate valid cronT-CRON-001-0061-3Required

Implementations SHOULD provide:

  1. Automated test suite covering all compliance tests
  2. Test report indicating pass/fail status for each test
  3. Conformance level declaration (Level 1, 2, or 3)

# Basic daily (scattered across full day)
schedule: daily
# Fuzzy: FUZZY:DAILY * * *
# Might generate: 43 5 * * * (5:43 AM)
# Daily around specific time
schedule: daily around 14:00
# Fuzzy: FUZZY:DAILY_AROUND:14:0 * * *
# Might generate: 13 14 * * * (2:13 PM, within 1-3 PM window)
# Daily during business hours
schedule: daily between 9:00 and 17:00
# Fuzzy: FUZZY:DAILY_BETWEEN:9:0:17:0 * * *
# Might generate: 37 12 * * * (12:37 PM, within 9 AM-5 PM)
# Daily with timezone conversion (JST to UTC)
schedule: daily around 14:00 utc+9
# Fuzzy: FUZZY:DAILY_AROUND:5:0 * * *
# Converts to 5:00 AM UTC, scatters in window 4-6 AM UTC
# Basic weekly (any day, any time)
schedule: weekly
# Fuzzy: FUZZY:WEEKLY * * *
# Might generate: 43 5 * * 1 (Monday 5:43 AM)
# Weekly on specific day
schedule: weekly on monday
# Fuzzy: FUZZY:WEEKLY:1 * * 1
# Might generate: 18 14 * * 1 (Monday 2:18 PM)
# Weekly with time constraint
schedule: weekly on friday around 17:00
# Fuzzy: FUZZY:WEEKLY:5:AROUND:17:0 * * 5
# Might generate: 42 16 * * 5 (Friday 4:42 PM, within 4-6 PM)
# Every hour with scattered minute
schedule: hourly
# Fuzzy: FUZZY:HOURLY * * *
# Might generate: 43 * * * * (every hour at minute 43)
# Every 2 hours
schedule: every 2h
# Fuzzy: FUZZY:HOURLY:2 * * *
# Might generate: 53 */2 * * * (every 2 hours at minute 53)
# Every 5 minutes (fixed, not fuzzy)
schedule: every 5 minutes
# Generates: */5 * * * * (fixed interval)
# Bi-weekly
schedule: bi-weekly
# Fuzzy: FUZZY:BI-WEEKLY * * *
# Might generate: 43 5 */14 * * (every 14 days at 5:43 AM)
# JST (UTC+9) business hours to UTC
schedule: daily between 9am utc+9 and 5pm utc+9
# Converts to: daily between 0:00 and 8:00 (UTC)
# Fuzzy: FUZZY:DAILY_BETWEEN:0:0:8:0 * * *
# EST (UTC-5) afternoon meeting
schedule: weekly on monday around 3pm utc-5
# Converts to: weekly on monday around 20:00 (UTC)
# Fuzzy: FUZZY:WEEKLY:1:AROUND:20:0 * * 1
# IST (UTC+5:30) morning standup
schedule: daily around 9:30am utc+05:30
# Converts to: daily around 4:00 (UTC)
# Fuzzy: FUZZY:DAILY_AROUND:4:0 * * *
Error CodeDescriptionExample
ERR-SYNTAX-001Unknown schedule typemonthly (not supported)
ERR-SYNTAX-002Invalid time format25:00 (hour out of range)
ERR-SYNTAX-003Invalid weekdaymondey (typo)
ERR-SYNTAX-004Missing required componentdaily around (no time)
ERR-SYNTAX-005Unsupported syntax patterndaily at 14:00 (use around)
ERR-TIME-001Hour out of range25 (>23)
ERR-TIME-002Minute out of range60 (>59)
ERR-TIME-003Invalid 12-hour format13pm (hour >12)
ERR-TZ-001Invalid UTC offsetutc+25 (>14)
ERR-TZ-002Malformed offset syntaxutc9 (missing +/-)
ERR-INTERVAL-001Invalid interval valueevery 0h (must be >0)
ERR-INTERVAL-002Unsupported intervalevery 5h (not factor of 24)

The FNV-1a 32-bit hash provides adequate collision resistance for workflow scattering purposes. The birthday paradox suggests approximately 77,000 workflows are needed for a 50% collision probability. For organizations with fewer workflows, collisions are unlikely.

If collision occurs (two workflows receive identical execution times), this does not create a security vulnerability but reduces the effectiveness of load distribution.

The deterministic nature of the scattering algorithm means execution times are predictable given the workflow identifier. This is intentional for consistency but means:

  • Attackers cannot cause DOS by triggering simultaneous execution
  • Execution times cannot be used as secrets
  • Load distribution is transparent and auditable

Implementations MUST handle timezone offsets with integer arithmetic to prevent floating-point rounding errors that could cause inconsistent execution times.

Implementations SHOULD validate UTC offsets are within reasonable bounds (UTC-12 to UTC+14) to prevent overflow in time calculations.

Implementations MUST validate all user inputs before processing:

  • Schedule type MUST be from allowed set
  • Time values MUST be within valid ranges
  • Interval values MUST be positive integers
  • All string inputs MUST be sanitized to prevent injection attacks


  • Changed: Hash function requirement relaxed from MUST to SHOULD for FNV-1a
  • Added: General hash function requirements (determinism, distribution, stability, integer output)
  • Added: Support for alternative hash functions (MurmurHash, xxHash, CityHash)
  • Changed: Moved FNV reference from normative to informative references
  • Initial specification release
  • Defined core fuzzy schedule syntax grammar
  • Specified scattering algorithm using FNV-1a hash
  • Added timezone conversion support
  • Defined three conformance levels (Basic, Standard, Complete)
  • Included comprehensive test suite with 50+ test cases
  • Added examples for all schedule types
  • Defined error codes and handling requirements

Copyright © 2024 GitHub. All rights reserved.