AgentSkillsCN

cron-expressions

从经过验证的 TypeScript 参考中,生成原生的 Cron 表达式解析、匹配与调度功能——包括周期性时间模式、Crontab 语义,以及下次发生时间的计算——

SKILL.md
--- frontmatter
name: cron-expressions
description: Generate native cron expression parsing, matching, and scheduling — recurring time patterns, crontab semantics, next-occurrence calculation — from a verified TypeScript reference
argument-hint: "<nodes> [--lang <language>] or 'help' — specify nodes to generate, target language, or get guidance"
allowed-tools: ["Bash", "Read", "Write", "Edit", "Glob", "Grep"]

cron-expressions

Parse, validate, match, and iterate over standard cron expressions as pure functions. Supports 5-field cron format with Vixie extensions (L, W, #) and correct semantics for every edge case that libraries disagree on.

Design principles

  • Pure functions only — every function takes explicit inputs; no global state.
  • UTC throughout — all datetime math uses UTC. No timezone handling.
  • Vixie cron semantics — follows Vixie cron 4.1 conventions, documented with provenance for every design decision.
  • Clarity over performance — reference code prioritizes readability. Minute-scanning is used for next-occurrence rather than optimized field-walking.

Input

$ARGUMENTS accepts:

  • help: Interactive guide to choosing the right nodes and language for your use case
  • Nodes: space-separated node names to generate (or all for the full library)
  • --lang <language>: target language (default: typescript). Supported: python, rust, go, typescript

Examples:

  • help — walk through choosing which nodes you need
  • matcher — generate matcher + dependencies in TypeScript
  • next-occurrence --lang python — generate next-occurrence + dependencies in Python
  • all --lang rust — generate the full library in Rust

Handling help

When $ARGUMENTS is help, read HELP.md and use it to guide the user through node and language selection. The help guide contains a decision tree and common use-case recipes. Walk through it interactively, asking the user about their requirements, then recommend specific nodes and a target language.

Node Graph

code
cron-types ────────────────┬──► tokenizer ──► parser ──┐
  (leaf)                   │       (leaf)    (internal) │
                           │                           │
field-range ───────────────┤──────────────► matcher ────┤
  (leaf)                   │               (internal)   │
                           │                   │        │
                           │          next-occurrence ──┤
                           │             (internal)     │
                           │                   │        │
                           │              iterator ─────┤
                           │             (internal)     │
                           │                            │
                           └───────────► cron-schedule ─┘
                                           (root)

Nodes

NodeTypeDepends OnDescription
cron-typesleafCronFieldEntry, CronField, CronExpression type definitions and factories
field-rangeleafValid ranges per field, month/day-of-week aliases, last-day-of-month calculation
tokenizerleafSplits cron string into 5 field strings
parserinternalcron-types, field-range, tokenizerParses field strings into CronExpression AST
matcherinternalcron-types, field-rangeTests whether a UTC datetime matches a CronExpression
next-occurrenceinternalcron-types, matcherFinds next/previous datetime matching a CronExpression
iteratorinternalcron-types, next-occurrenceLazy iteration over matching datetimes; nextN convenience
cron-schedulerootcron-types, parser, matcher, next-occurrence, iteratorPublic API: parse, match, next, prev, nextN, iterate

Subset Extraction

  • Parse only: cron-types + field-range + tokenizer + parser
  • Match a datetime: cron-types + field-range + matcher (+ parser if starting from string)
  • Find next occurrence: add next-occurrence to the match subset
  • Iterate over occurrences: add iterator to the next-occurrence subset
  • Full library: all 8 nodes via cron-schedule

Key Design Decisions

Day-of-month / day-of-week interaction (THE critical decision)

@provenance Vixie cron 4.1, crontab(5) man page

When both day-of-month and day-of-week are restricted (not wildcard), the match uses union (OR) — matching either field is sufficient. This is the Vixie cron convention, which differs from what most people expect (intersection/AND).

ExpressionMatchesRule
0 0 15 * 515th of any month OR any FridayUnion (both restricted)
0 0 15 * *15th of any monthOnly DoM restricted
0 0 * * 5Every FridayOnly DoW restricted

Sunday representation

@provenance POSIX.1-2017 crontab(5), Vixie cron 4.1

InputNormalizedNotes
00 (Sunday)POSIX standard
70 (Sunday)Vixie extension — both 0 and 7 mean Sunday
SUN0 (Sunday)Case-insensitive alias

Field modifiers

ModifierValid InMeaningSource
LdayOfMonthLast day of monthQuartz, spring-cron
nLdayOfWeekLast nth-day of month (e.g., 5L = last Friday)Quartz
n#ndayOfWeekNth weekday of month (e.g., 5#3 = third Friday)Quartz
nWdayOfMonthNearest weekday to nth day (never crosses month boundary)Quartz

Nearest weekday (W) boundary rules

@provenance Quartz scheduler W modifier semantics

ScenarioResolution
Target is a weekdayUse target as-is
Target is Saturday, not 1stUse Friday (target - 1)
1st is SaturdayUse Monday the 3rd (can't go to previous month)
Target is Sunday, not last dayUse Monday (target + 1)
Last day is SundayUse Friday (target - 2, can't go to next month)

Process

  1. If $ARGUMENTS is help, read HELP.md and guide the user interactively
  2. Read this file for the node graph and design decisions
  3. For each requested node (in dependency order), read nodes/<name>/spec.md
  4. Read nodes/<name>/to-<lang>.md for target-language translation hints
  5. Generate implementation + tests
  6. If the spec is ambiguous, consult reference/src/<name>.ts (track what you consulted and why)
  7. Run tests — all must pass before proceeding to the next node

Error Handling

  • tokenize throws on empty/whitespace input or wrong field count (not 5)
  • parseCron throws on: out-of-range values, invalid step values (0 or negative), unrecognized tokens, invalid nth values (#0 or #6+)
  • matchesCron is a total function (no error cases)
  • nextOccurrence / prevOccurrence return null if no match within ~1 year
  • cronSchedule throws on invalid expressions (delegates to parseCron)

Reference

The TypeScript reference implementation is in reference/src/. It is the authoritative source — consult it when specs are ambiguous, but prefer the spec and translation hints as primary sources.

All reference code has 100% line and function coverage via bun test --coverage.