expression: "*/5 * * * *",
},
{
- name: "weekdays at 8",
+ name: "accepts a weekday schedule at 8",
expression: "0 8 * * 1-5",
},
{
- name: "lists and ranges in office hours",
+ name: "accepts lists and ranges in office hours",
expression: "0,30 9-17 * * 1-5",
},
{
- name: "a range with a step",
+ name: "accepts a stepped range",
expression: "0 0 1-31/10 * *",
},
{
- name: "February 29 of the leap years",
+ name: "accepts a leap-day schedule",
expression: "0 12 29 2 *",
},
{
- name: "5 minutes across the end of an hour",
+ name: "accepts five-minute spacing across an hour",
expression: "0,55 * * * *",
},
}
message string
}{
{
- name: "four fields",
+ name: "rejects four fields",
expression: "* * * *",
message: "has 4 fields, not 5",
},
{
- name: "a seconds field",
+ name: "rejects a seconds field",
expression: "0 0 8 * * *",
message: "has 6 fields, not 5",
},
{
- name: "a macro",
+ name: "rejects a macro",
expression: "@daily",
message: "has 1 fields, not 5",
},
{
- name: "a day name",
+ name: "rejects a day name",
expression: "0 8 * * MON",
- message: `the day of week field of "0 8 * * MON": "MON" is not a number from 0 to 7`,
+ message: `the day of week field of "0 8 * * MON": parse cron field value: "MON" is not a number from 0 to 7`,
},
{
- name: "a month name",
+ name: "rejects a month name",
expression: "0 8 * JAN *",
message: `"JAN" is not a number from 1 to 12`,
},
{
- name: "a question mark",
+ name: "rejects a question mark",
expression: "0 8 ? * *",
message: `"?" is not a number from 1 to 31`,
},
{
- name: "the last day",
+ name: "rejects the last day",
expression: "0 8 L * *",
message: `"L" is not a number`,
},
{
- name: "the nearest weekday",
+ name: "rejects the nearest weekday",
expression: "0 8 15W * *",
message: `"15W" is not a number`,
},
{
- name: "the nth weekday",
+ name: "rejects the nth weekday",
expression: "0 8 * * 1#2",
message: `"1#2" is not a number`,
},
{
- name: "a step after a single value",
+ name: "rejects a step after a single value",
expression: "5/10 * * * *",
message: "has a step after a single value",
},
{
- name: "a minute out of range",
+ name: "rejects a minute out of range",
expression: "60 * * * *",
message: `"60" is not a number from 0 to 59`,
},
{
- name: "an hour out of range",
+ name: "rejects an hour out of range",
expression: "0 24 * * *",
message: `"24" is not a number from 0 to 23`,
},
{
- name: "day 0",
+ name: "rejects day 0",
expression: "0 8 0 * *",
message: `"0" is not a number from 1 to 31`,
},
{
- name: "month 13",
+ name: "rejects month 13",
expression: "0 8 * 13 *",
message: `"13" is not a number from 1 to 12`,
},
{
- name: "weekday 8",
+ name: "rejects weekday 8",
expression: "0 8 * * 8",
message: `"8" is not a number from 0 to 7`,
},
{
- name: "a negative number",
+ name: "rejects a negative number",
expression: "0 8 * * -1",
message: `the range "-1"`,
},
{
- name: "a range with its start after its end",
+ name: "rejects a range with its start after its end",
expression: "0 10-5 * * *",
message: "the start is after the end",
},
{
- name: "a step of 0",
+ name: "rejects a step of 0",
expression: "0 */0 * * *",
message: `the step of "*/0"`,
},
{
- name: "an empty item",
+ name: "rejects an empty item",
expression: "0,,30 * * * *",
message: `"" is not a number`,
},
{
- name: "a day that never comes",
+ name: "rejects a day that never comes",
expression: "0 0 30 2 *",
message: "matches no day in 8 years",
},
{
- name: "every minute",
+ name: "rejects every minute",
expression: "* * * * *",
message: "the runs of a schedule must be at least 5 minutes apart",
},
{
- name: "every 2 minutes",
+ name: "rejects every 2 minutes",
expression: "*/2 * * * *",
message: "the runs of a schedule must be at least 5 minutes apart",
},
{
- name: "two runs in one minute of the hour",
+ name: "rejects two runs in one minute of the hour",
expression: "58,59 * * * *",
message: "the runs of a schedule must be at least 5 minutes apart",
},
{
- name: "two runs across the end of an hour",
+ name: "rejects two runs across the end of an hour",
expression: "0,59 * * * *",
message: "the runs of a schedule must be at least 5 minutes apart",
},
{
- name: "two runs across midnight",
+ name: "rejects two runs across midnight",
expression: "0,59 0,23 * * *",
message: "the runs of a schedule must be at least 5 minutes apart",
},
next: time.Date(2026, time.November, 7, 8, 0, 0, 0, time.UTC),
},
{
- name: "every 5 minutes",
+ name: "advances to the next five-minute boundary",
expression: "*/5 * * * *",
after: time.Date(2026, time.November, 6, 10, 3, 0, 0, time.UTC),
next: time.Date(2026, time.November, 6, 10, 5, 0, 0, time.UTC),
next: time.Date(2026, time.December, 31, 0, 0, 0, 0, time.UTC),
},
{
- name: "the first day after the end of a year",
+ name: "advances to the first day of the next year",
expression: "0 9 1 * *",
after: time.Date(2026, time.December, 31, 10, 0, 0, 0, time.UTC),
next: time.Date(2027, time.January, 1, 9, 0, 0, 0, time.UTC),
time time.Time
}{
{
- name: "a normal wall time",
+ name: "keeps a normal wall time unchanged",
hour: 9,
day: 1,
time: time.Date(2026, time.November, 1, 14, 0, 0, 0, time.UTC),