Merge PR #1444
This commit is contained in:
commit
d4f127d336
2 changed files with 52 additions and 0 deletions
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -286,6 +287,14 @@ func (cs *CronService) computeNextRun(schedule *CronSchedule, nowMS int64) *int6
|
||||||
|
|
||||||
// Use gronx to calculate next run time
|
// Use gronx to calculate next run time
|
||||||
now := time.UnixMilli(nowMS)
|
now := time.UnixMilli(nowMS)
|
||||||
|
if tz := strings.TrimSpace(schedule.TZ); tz != "" {
|
||||||
|
loc, err := time.LoadLocation(tz)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[cron] failed to load timezone %q: %v", tz, err)
|
||||||
|
} else {
|
||||||
|
now = now.In(loc)
|
||||||
|
}
|
||||||
|
}
|
||||||
nextTime, err := gronx.NextTickAfter(schedule.Expr, now, false)
|
nextTime, err := gronx.NextTickAfter(schedule.Expr, now, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[cron] failed to compute next run for expr '%s': %v", schedule.Expr, err)
|
log.Printf("[cron] failed to compute next run for expr '%s': %v", schedule.Expr, err)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSaveStore_FilePermissions(t *testing.T) {
|
func TestSaveStore_FilePermissions(t *testing.T) {
|
||||||
|
|
@ -33,6 +34,48 @@ func TestSaveStore_FilePermissions(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestComputeNextRun_UsesScheduleTimeZone(t *testing.T) {
|
||||||
|
cs := NewCronService(filepath.Join(t.TempDir(), "cron", "jobs.json"), nil)
|
||||||
|
now := time.Date(2026, time.March, 13, 12, 30, 0, 0, time.UTC).UnixMilli()
|
||||||
|
baseline := cs.computeNextRun(&CronSchedule{Kind: "cron", Expr: "0 9 * * *"}, now)
|
||||||
|
if baseline == nil {
|
||||||
|
t.Fatal("baseline computeNextRun() returned nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("uses explicit timezone", func(t *testing.T) {
|
||||||
|
next := cs.computeNextRun(&CronSchedule{
|
||||||
|
Kind: "cron",
|
||||||
|
Expr: "0 9 * * *",
|
||||||
|
TZ: "America/New_York",
|
||||||
|
}, now)
|
||||||
|
if next == nil {
|
||||||
|
t.Fatal("computeNextRun() returned nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
wantNext := time.Date(2026, time.March, 13, 13, 0, 0, 0, time.UTC).UnixMilli()
|
||||||
|
if *next != wantNext {
|
||||||
|
t.Fatalf("computeNextRun() = %d, want %d", *next, wantNext)
|
||||||
|
}
|
||||||
|
if *next == *baseline {
|
||||||
|
t.Fatal("explicit timezone should change the computed next run for this fixture")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("falls back to baseline on invalid timezone", func(t *testing.T) {
|
||||||
|
next := cs.computeNextRun(&CronSchedule{
|
||||||
|
Kind: "cron",
|
||||||
|
Expr: "0 9 * * *",
|
||||||
|
TZ: "Mars/OlympusMons",
|
||||||
|
}, now)
|
||||||
|
if next == nil {
|
||||||
|
t.Fatal("computeNextRun() returned nil")
|
||||||
|
}
|
||||||
|
if *next != *baseline {
|
||||||
|
t.Fatalf("computeNextRun() = %d, want baseline %d", *next, *baseline)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func int64Ptr(v int64) *int64 {
|
func int64Ptr(v int64) *int64 {
|
||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue