From d0b46beeec3d87a5943820238c263746eb73ceb9 Mon Sep 17 00:00:00 2001 From: Joakim Date: Mon, 5 Jan 2026 10:36:21 +0100 Subject: [PATCH] Add support for daily, weekly, monthly, yearly recurrence patterns Previously, only numeric forms (1d, 1w, 1m, 1y) and plural word forms (days, weeks, months, years) were supported for recurrence patterns. The common adverbial forms (daily, weekly, monthly, yearly) would fail with 'invalid recurrence pattern' error. Now users can use natural language recurrence patterns: - recur:daily -> 1 day interval - recur:weekly -> 7 day interval - recur:monthly -> 30 day interval - recur:yearly -> 365 day interval Added test coverage for all four new patterns. --- opal-task/internal/engine/recurrence.go | 9 +++++---- opal-task/internal/engine/recurrence_test.go | 5 +++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/opal-task/internal/engine/recurrence.go b/opal-task/internal/engine/recurrence.go index d799636..4fb7bd2 100644 --- a/opal-task/internal/engine/recurrence.go +++ b/opal-task/internal/engine/recurrence.go @@ -11,6 +11,7 @@ import ( // ParseRecurrencePattern converts duration strings to time.Duration // Supports: 1d, 2w, 3m, 1y, 5min, 5hrs, 30sec // Also supports: days, weeks, months, years, minutes, hours, seconds +// And common forms: daily, weekly, monthly, yearly func ParseRecurrencePattern(pattern string) (time.Duration, error) { if len(pattern) == 0 { return 0, fmt.Errorf("empty duration pattern") @@ -21,10 +22,10 @@ func ParseRecurrencePattern(pattern string) (time.Duration, error) { "second": time.Second, "seconds": time.Second, "sec": time.Second, "minute": time.Minute, "minutes": time.Minute, "min": time.Minute, "hour": time.Hour, "hours": time.Hour, "hrs": time.Hour, "hr": time.Hour, - "day": 24 * time.Hour, "days": 24 * time.Hour, - "week": 7 * 24 * time.Hour, "weeks": 7 * 24 * time.Hour, - "month": 30 * 24 * time.Hour, "months": 30 * 24 * time.Hour, - "year": 365 * 24 * time.Hour, "years": 365 * 24 * time.Hour, + "day": 24 * time.Hour, "days": 24 * time.Hour, "daily": 24 * time.Hour, + "week": 7 * 24 * time.Hour, "weeks": 7 * 24 * time.Hour, "weekly": 7 * 24 * time.Hour, + "month": 30 * 24 * time.Hour, "months": 30 * 24 * time.Hour, "monthly": 30 * 24 * time.Hour, + "year": 365 * 24 * time.Hour, "years": 365 * 24 * time.Hour, "yearly": 365 * 24 * time.Hour, } if duration, ok := wordDurations[pattern]; ok { diff --git a/opal-task/internal/engine/recurrence_test.go b/opal-task/internal/engine/recurrence_test.go index ab04f24..551eac0 100644 --- a/opal-task/internal/engine/recurrence_test.go +++ b/opal-task/internal/engine/recurrence_test.go @@ -18,6 +18,11 @@ func TestParseRecurrencePattern(t *testing.T) { {"2w", 14 * 24 * time.Hour}, {"1m", 30 * 24 * time.Hour}, {"1y", 365 * 24 * time.Hour}, + // Test word forms + {"daily", 24 * time.Hour}, + {"weekly", 7 * 24 * time.Hour}, + {"monthly", 30 * 24 * time.Hour}, + {"yearly", 365 * 24 * time.Hour}, } for _, tt := range tests {