Skip to content

Commit 8e6168e

Browse files
committed
fix: rill time ordinal snapping when anchored on smaller grain (#8812)
1 parent a226051 commit 8e6168e

File tree

2 files changed

+29
-10
lines changed

2 files changed

+29
-10
lines changed

runtime/pkg/rilltime/rilltime.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,8 @@ type EvalOptions struct {
259259
FirstDay int
260260
FirstMonth int
261261

262-
ref time.Time
263-
truncatedRef bool
262+
ref time.Time
263+
largestSnappedGrain timeutil.TimeGrain
264264
}
265265

266266
func Parse(from string, parseOpts ParseOptions) (*Expression, error) {
@@ -347,9 +347,7 @@ func (e *Expression) Eval(evalOpts EvalOptions) (time.Time, time.Time, timeutil.
347347
i := len(e.AnchorOverrides) - 1
348348
for i >= 0 {
349349
evalOpts.ref, _ = e.AnchorOverrides[i].eval(evalOpts, evalOpts.ref, e.tz)
350-
if e.AnchorOverrides[i].truncates() {
351-
evalOpts.truncatedRef = true
352-
}
350+
evalOpts.largestSnappedGrain = max(evalOpts.largestSnappedGrain, e.AnchorOverrides[i].largestSnappedGrain())
353351
i--
354352
}
355353

@@ -487,9 +485,10 @@ func (o *OrdinalInterval) eval(evalOpts EvalOptions, start time.Time, tz *time.L
487485
return start, end, tg
488486
}
489487

490-
if !evalOpts.truncatedRef {
491-
tg = grainMap[o.Ordinals[len(o.Ordinals)-1].Grain]
492-
start = truncateWithCorrection(start, higherOrderMap[tg], tz, evalOpts.FirstDay, evalOpts.FirstMonth)
488+
lastTg := grainMap[o.Ordinals[len(o.Ordinals)-1].Grain]
489+
if lastTg > evalOpts.largestSnappedGrain {
490+
tg = lastTg
491+
start = truncateWithCorrection(start, higherOrderMap[lastTg], tz, evalOpts.FirstDay, evalOpts.FirstMonth)
493492
}
494493

495494
i := len(o.Ordinals) - 1
@@ -577,8 +576,19 @@ func (p *PointInTime) eval(evalOpts EvalOptions, tm time.Time, tz *time.Location
577576
return tm, tg
578577
}
579578

580-
func (p *PointInTime) truncates() bool {
581-
return len(p.Points) > 0 && p.Points[len(p.Points)-1].Snap != nil
579+
func (p *PointInTime) largestSnappedGrain() timeutil.TimeGrain {
580+
largest := timeutil.TimeGrainUnspecified
581+
for _, point := range p.Points {
582+
if point.Snap == nil {
583+
continue
584+
}
585+
586+
tg := grainMap[*point.Snap]
587+
if tg > largest {
588+
largest = tg
589+
}
590+
}
591+
return largest
582592
}
583593

584594
func (p *PointInTimeWithSnap) parse() error {

runtime/pkg/rilltime/rilltime_test.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,15 @@ func TestEval_OrdinalVariations(t *testing.T) {
235235
{"W1", "2025-04-28T00:00:00Z", "2025-05-05T00:00:00Z", timeutil.TimeGrainDay, 1, 1},
236236
{"W1 as of -2M", "2025-03-03T00:00:00Z", "2025-03-10T00:00:00Z", timeutil.TimeGrainDay, 1, 1},
237237

238+
// Ordinals with lower order truncation
239+
{"M2 as of watermark/D", "2025-02-01T00:00:00Z", "2025-03-01T00:00:00Z", timeutil.TimeGrainDay, 1, 1},
240+
{"M7 as of watermark/D", "2025-07-01T00:00:00Z", "2025-08-01T00:00:00Z", timeutil.TimeGrainDay, 1, 1},
241+
{"D4 as of watermark/H", "2025-05-04T00:00:00Z", "2025-05-05T00:00:00Z", timeutil.TimeGrainHour, 1, 1},
242+
243+
// Ordinals with higher order truncation
244+
{"D6 as of watermark/M", "2025-05-06T00:00:00Z", "2025-05-07T00:00:00Z", timeutil.TimeGrainHour, 1, 1},
245+
{"D6 as of watermark/W", "2025-05-17T00:00:00Z", "2025-05-18T00:00:00Z", timeutil.TimeGrainHour, 1, 1},
246+
238247
// Ordinal chaining variations
239248
{"s57 of m4 of H2 of D4 as of -1M", "2025-04-04T01:03:56Z", "2025-04-04T01:03:57Z", timeutil.TimeGrainMillisecond, 1, 1},
240249
}

0 commit comments

Comments
 (0)