Files
galaxy-game/pkg/cronutil/cronutil.go
T
2026-05-03 07:59:03 +02:00

48 lines
1.7 KiB
Go

// Package cronutil provides a thin wrapper over github.com/robfig/cron/v3
// for parsing the five-field cron expressions used by Galaxy services to
// describe periodic schedules such as turn_schedule. It exposes only the
// parser and a Next computation; no scheduler runtime, no logging, and no
// concurrency primitives.
package cronutil
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
// fiveFieldParser parses standard five-field cron expressions
// (minute, hour, day-of-month, month, day-of-week). The grammar matches
// what Galaxy services accept for turn_schedule and is the only grammar
// supported by this package; six-field expressions with a seconds field
// are rejected.
var fiveFieldParser = cron.NewParser(
cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow,
)
// Schedule holds a parsed five-field cron expression and computes the
// next firing time after a given moment. The zero value is not usable;
// callers obtain a Schedule from Parse.
type Schedule struct {
inner cron.Schedule
}
// Parse parses expr as a five-field cron expression and returns the
// resulting Schedule. Parse returns an error if expr is empty, contains
// a seconds field, or is otherwise rejected by the underlying parser.
func Parse(expr string) (Schedule, error) {
inner, err := fiveFieldParser.Parse(expr)
if err != nil {
return Schedule{}, fmt.Errorf("cronutil: parse %q: %w", expr, err)
}
return Schedule{inner: inner}, nil
}
// Next returns the next firing time strictly after after. The returned
// time is always in UTC; callers passing UTC values therefore get UTC
// values back. Calling Next on a zero-value Schedule panics.
func (s Schedule) Next(after time.Time) time.Time {
return s.inner.Next(after.UTC()).UTC()
}