77 "time"
88
99 "github.com/rilldata/rill/runtime/metricsview"
10- "github.com/rilldata/rill/runtime/pkg/duration"
1110 "github.com/rilldata/rill/runtime/pkg/rilltime"
1211 "github.com/rilldata/rill/runtime/pkg/timeutil"
1312)
@@ -113,9 +112,12 @@ func (e *Executor) resolveTimeRange(ctx context.Context, tr *metricsview.TimeRan
113112
114113// resolveISOTimeRange resolves the given time range where either only start/end is specified along with ISO duration/offset, ensuring only its Start and End properties are populated.
115114func (e * Executor ) resolveISOTimeRange (ctx context.Context , tr * metricsview.TimeRange , tz * time.Location , executionTime * time.Time ) error {
115+ var ts metricsview.TimestampsResult
116+ var err error
117+
116118 if tr .Start .IsZero () && tr .End .IsZero () {
117119 if executionTime == nil {
118- ts , err : = e .Timestamps (ctx , tr .TimeDimension )
120+ ts , err = e .Timestamps (ctx , tr .TimeDimension )
119121 if err != nil {
120122 return fmt .Errorf ("failed to fetch timestamps: %w" , err )
121123 }
@@ -125,65 +127,30 @@ func (e *Executor) resolveISOTimeRange(ctx context.Context, tr *metricsview.Time
125127 tr .End = * executionTime
126128 }
127129
128- var isISO bool
129130 if tr .IsoDuration != "" {
130- d , err := duration .ParseISO8601 (tr .IsoDuration )
131- if err != nil {
132- return fmt .Errorf ("invalid iso_duration %q: %w" , tr .IsoDuration , err )
133- }
134-
135- if ! tr .Start .IsZero () && ! tr .End .IsZero () {
136- return errors .New (`cannot resolve "iso_duration" for a time range with fixed "start" and "end" timestamps` )
137- } else if ! tr .Start .IsZero () {
138- tr .End = d .Add (tr .Start )
139- } else if ! tr .End .IsZero () {
140- tr .Start = d .Sub (tr .End )
141- } else {
142- // In practice, this shouldn't happen since we resolve a time anchor dynamically if both start and end are zero.
143- return errors .New (`cannot resolve "iso_duration" for a time range without "start" and "end" timestamps` )
144- }
145-
146- isISO = true
147- }
148-
149- if tr .IsoOffset != "" {
150- d , err := duration .ParseISO8601 (tr .IsoOffset )
131+ rt , err := rilltime .ParseLegacy (tr .IsoDuration , tr .IsoOffset , tr .RoundToGrain .ToTimeutil (), rilltime.ParseOptions {
132+ DefaultTimeZone : tz ,
133+ SmallestGrain : timeutil .TimeGrainFromAPI (e .metricsView .SmallestTimeGrain ),
134+ })
151135 if err != nil {
152- return fmt .Errorf ("invalid iso_offset %q: %w" , tr .IsoOffset , err )
153- }
154-
155- if ! tr .Start .IsZero () {
156- tr .Start = d .Sub (tr .Start )
136+ return err
157137 }
158- if ! tr .End .IsZero () {
159- tr .End = d .Sub (tr .End )
160- }
161-
162- isISO = true
163- }
164138
165- // Only modify the start and end if ISO duration or offset was sent.
166- // This is to maintain backwards compatibility for calls from the UI.
167- if isISO {
168- fdow := int (e .metricsView .FirstDayOfWeek )
169- if fdow > 7 || fdow <= 0 {
170- fdow = 1
171- }
172- fmoy := int (e .metricsView .FirstMonthOfYear )
173- if fmoy > 12 || fmoy <= 0 {
174- fmoy = 1
175- }
176- if ! tr .RoundToGrain .Valid () {
177- return fmt .Errorf ("invalid time grain %q" , tr .RoundToGrain )
178- }
179- if tr .RoundToGrain != metricsview .TimeGrainUnspecified {
180- if ! tr .Start .IsZero () {
181- tr .Start = timeutil .TruncateTime (tr .Start , tr .RoundToGrain .ToTimeutil (), tz , fdow , fmoy )
182- }
183- if ! tr .End .IsZero () {
184- tr .End = timeutil .TruncateTime (tr .End , tr .RoundToGrain .ToTimeutil (), tz , fdow , fmoy )
139+ if ts .Now .IsZero () {
140+ ts , err = e .Timestamps (ctx , tr .TimeDimension )
141+ if err != nil {
142+ return fmt .Errorf ("failed to fetch timestamps: %w" , err )
185143 }
186144 }
145+
146+ tr .Start , tr .End , _ = rt .Eval (rilltime.EvalOptions {
147+ Now : ts .Now ,
148+ MinTime : ts .Min ,
149+ MaxTime : ts .Max ,
150+ Watermark : tr .End ,
151+ FirstDay : int (e .metricsView .FirstDayOfWeek ),
152+ FirstMonth : int (e .metricsView .FirstMonthOfYear ),
153+ })
187154 }
188155
189156 // Clear all other fields than Start and End
0 commit comments