diff --git a/CHANGELOG.md b/CHANGELOG.md index 362aee25f5a..60b668f4a45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - [#8569](https://github.com/influxdata/influxdb/issues/8569): Fix the cq start and end times to use unix timestamps. - [#8601](https://github.com/influxdata/influxdb/pull/8601): Fixed time boundaries for continuous queries with time zones. - [#8097](https://github.com/influxdata/influxdb/pull/8097): Return query parsing errors in CSV formats. +- [#8607](https://github.com/influxdata/influxdb/issues/8607): Fix time zone shifts when the shift happens on a time zone boundary. ## v1.3.1 [unreleased] diff --git a/influxql/iterator.gen.go b/influxql/iterator.gen.go index 5108b4dc7e3..8ed604215ec 100644 --- a/influxql/iterator.gen.go +++ b/influxql/iterator.gen.go @@ -726,7 +726,7 @@ func (itr *floatFillIterator) Next() (*FloatPoint, error) { // Check to see if we have passed over an offset change and adjust the time // to account for this new offset. if itr.opt.Location != nil { - if _, offset := itr.opt.Zone(itr.window.time); offset != itr.window.offset { + if _, offset := itr.opt.Zone(itr.window.time - 1); offset != itr.window.offset { diff := itr.window.offset - offset if abs(diff) < int64(itr.opt.Interval.Duration) { itr.window.time += diff @@ -4073,7 +4073,7 @@ func (itr *integerFillIterator) Next() (*IntegerPoint, error) { // Check to see if we have passed over an offset change and adjust the time // to account for this new offset. if itr.opt.Location != nil { - if _, offset := itr.opt.Zone(itr.window.time); offset != itr.window.offset { + if _, offset := itr.opt.Zone(itr.window.time - 1); offset != itr.window.offset { diff := itr.window.offset - offset if abs(diff) < int64(itr.opt.Interval.Duration) { itr.window.time += diff @@ -7403,7 +7403,7 @@ func (itr *unsignedFillIterator) Next() (*UnsignedPoint, error) { // Check to see if we have passed over an offset change and adjust the time // to account for this new offset. if itr.opt.Location != nil { - if _, offset := itr.opt.Zone(itr.window.time); offset != itr.window.offset { + if _, offset := itr.opt.Zone(itr.window.time - 1); offset != itr.window.offset { diff := itr.window.offset - offset if abs(diff) < int64(itr.opt.Interval.Duration) { itr.window.time += diff @@ -10733,7 +10733,7 @@ func (itr *stringFillIterator) Next() (*StringPoint, error) { // Check to see if we have passed over an offset change and adjust the time // to account for this new offset. if itr.opt.Location != nil { - if _, offset := itr.opt.Zone(itr.window.time); offset != itr.window.offset { + if _, offset := itr.opt.Zone(itr.window.time - 1); offset != itr.window.offset { diff := itr.window.offset - offset if abs(diff) < int64(itr.opt.Interval.Duration) { itr.window.time += diff @@ -14063,7 +14063,7 @@ func (itr *booleanFillIterator) Next() (*BooleanPoint, error) { // Check to see if we have passed over an offset change and adjust the time // to account for this new offset. if itr.opt.Location != nil { - if _, offset := itr.opt.Zone(itr.window.time); offset != itr.window.offset { + if _, offset := itr.opt.Zone(itr.window.time - 1); offset != itr.window.offset { diff := itr.window.offset - offset if abs(diff) < int64(itr.opt.Interval.Duration) { itr.window.time += diff diff --git a/influxql/iterator.gen.go.tmpl b/influxql/iterator.gen.go.tmpl index 3d401dda364..f0b0f59ddc3 100644 --- a/influxql/iterator.gen.go.tmpl +++ b/influxql/iterator.gen.go.tmpl @@ -727,7 +727,7 @@ func (itr *{{$k.name}}FillIterator) Next() (*{{$k.Name}}Point, error) { // Check to see if we have passed over an offset change and adjust the time // to account for this new offset. if itr.opt.Location != nil { - if _, offset := itr.opt.Zone(itr.window.time); offset != itr.window.offset { + if _, offset := itr.opt.Zone(itr.window.time - 1); offset != itr.window.offset { diff := itr.window.offset - offset if abs(diff) < int64(itr.opt.Interval.Duration) { itr.window.time += diff diff --git a/influxql/iterator.go b/influxql/iterator.go index d87fe031837..4d6af718899 100644 --- a/influxql/iterator.go +++ b/influxql/iterator.go @@ -849,14 +849,13 @@ func (opt IteratorOptions) Window(t int64) (start, end int64) { t -= int64(opt.Interval.Offset) // Retrieve the zone offset for the start time. - var startOffset int64 + var zone int64 if opt.Location != nil { - _, startOffset = opt.Zone(t) - t += startOffset + _, zone = opt.Zone(t) } // Truncate time by duration. - dt := t % int64(opt.Interval.Duration) + dt := (t + zone) % int64(opt.Interval.Duration) if dt < 0 { // Negative modulo rounds up instead of down, so offset // with the duration. @@ -874,14 +873,14 @@ func (opt IteratorOptions) Window(t int64) (start, end int64) { // after the offset switch. Now that we are at midnight in UTC, we can // lookup the zone offset again to get the real starting offset. if opt.Location != nil { - _, adjustedOffset := opt.Zone(start) + _, startOffset := opt.Zone(start) // Do not adjust the offset if the offset change is greater than or // equal to the duration. - if o := startOffset - adjustedOffset; o != 0 && abs(o) < int64(opt.Interval.Duration) { - startOffset = adjustedOffset + if o := zone - startOffset; o != 0 && abs(o) < int64(opt.Interval.Duration) { + start += o } } - start += int64(opt.Interval.Offset) - startOffset + start += int64(opt.Interval.Offset) // Find the end time. if dt := int64(opt.Interval.Duration) - dt; MaxTime-dt <= t { @@ -889,23 +888,33 @@ func (opt IteratorOptions) Window(t int64) (start, end int64) { } else { end = t + dt } - end += int64(opt.Interval.Offset) - startOffset // Retrieve the zone offset for the end time. if opt.Location != nil { _, endOffset := opt.Zone(end) // Adjust the end time if the offset is different from the start offset. - if startOffset != endOffset { - offset := startOffset - endOffset - - // Only apply the offset if it is smaller than the duration. - // This prevents going back in time and creating time windows - // that don't make any sense. - if abs(offset) < int64(opt.Interval.Duration) { - end += offset + // Only apply the offset if it is smaller than the duration. + // This prevents going back in time and creating time windows + // that don't make any sense. + if o := zone - endOffset; o != 0 && abs(o) < int64(opt.Interval.Duration) { + // If the offset is greater than 0, that means we are adding time. + // Added time goes into the previous interval because the clocks + // move backwards. If the offset is less than 0, then we are skipping + // time. Skipped time comes after the switch so if we have a time + // interval that lands on the switch, it comes from the next + // interval and not the current one. For this reason, we need to know + // when the actual switch happens by seeing if the time switch is within + // the current interval. We calculate the zone offset with the offset + // and see if the value is the same. If it is, we apply the + // offset. + if o > 0 { + end += o + } else if _, z := opt.Zone(end + o); z == endOffset { + end += o } } } + end += int64(opt.Interval.Offset) return } diff --git a/influxql/iterator_test.go b/influxql/iterator_test.go index 73d6bad5b6e..1ca4b7afaaa 100644 --- a/influxql/iterator_test.go +++ b/influxql/iterator_test.go @@ -705,235 +705,224 @@ func TestLimitIterator(t *testing.T) { } } -func TestFillIterator_DST_Start_GroupByDay_Ascending(t *testing.T) { - start := time.Date(2000, 4, 1, 0, 0, 0, 0, LosAngeles) - end := time.Date(2000, 4, 5, 0, 0, 0, 0, LosAngeles).Add(-time.Nanosecond) - itr := influxql.NewFillIterator( - &FloatIterator{Points: []influxql.FloatPoint{{Time: start.UnixNano(), Value: 0}}}, - nil, - influxql.IteratorOptions{ - StartTime: start.UnixNano(), - EndTime: end.UnixNano(), - Interval: influxql.Interval{ - Duration: 24 * time.Hour, +func TestFillIterator_DST(t *testing.T) { + for _, tt := range []struct { + name string + start, end time.Time + points []time.Duration + opt influxql.IteratorOptions + }{ + { + name: "Start_GroupByDay_Ascending", + start: mustParseTime("2000-04-01T00:00:00-08:00"), + end: mustParseTime("2000-04-05T00:00:00-07:00"), + points: []time.Duration{ + 24 * time.Hour, + 47 * time.Hour, + 71 * time.Hour, + }, + opt: influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 24 * time.Hour, + }, + Location: LosAngeles, + Ascending: true, }, - Location: LosAngeles, - Ascending: true, }, - ) - - if a, err := (Iterators{itr}).ReadAll(); err != nil { - t.Fatalf("unexpected error: %s", err) - } else if !deep.Equal(a, [][]influxql.Point{ - {&influxql.FloatPoint{Time: start.UnixNano(), Value: 0}}, - {&influxql.FloatPoint{Time: start.Add(24 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(47 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(71 * time.Hour).UnixNano(), Nil: true}}, - }) { - t.Fatalf("unexpected points: %s", spew.Sdump(a)) - } -} - -func TestFillIterator_DST_Start_GroupByDay_Descending(t *testing.T) { - start := time.Date(2000, 4, 1, 0, 0, 0, 0, LosAngeles) - end := time.Date(2000, 4, 5, 0, 0, 0, 0, LosAngeles).Add(-time.Nanosecond) - itr := influxql.NewFillIterator( - &FloatIterator{Points: []influxql.FloatPoint{{Time: start.UnixNano(), Value: 0}}}, - nil, - influxql.IteratorOptions{ - StartTime: start.UnixNano(), - EndTime: end.UnixNano(), - Interval: influxql.Interval{ - Duration: 24 * time.Hour, + { + name: "Start_GroupByDay_Descending", + start: mustParseTime("2000-04-01T00:00:00-08:00"), + end: mustParseTime("2000-04-05T00:00:00-07:00"), + points: []time.Duration{ + 71 * time.Hour, + 47 * time.Hour, + 24 * time.Hour, + }, + opt: influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 24 * time.Hour, + }, + Location: LosAngeles, + Ascending: false, }, - Location: LosAngeles, - Ascending: false, }, - ) - - if a, err := (Iterators{itr}).ReadAll(); err != nil { - t.Fatalf("unexpected error: %s", err) - } else if !deep.Equal(a, [][]influxql.Point{ - {&influxql.FloatPoint{Time: start.Add(71 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(47 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(24 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.UnixNano(), Value: 0}}, - }) { - t.Fatalf("unexpected points: %s", spew.Sdump(a)) - } -} - -func TestFillIterator_DST_Start_GroupByHour_Ascending(t *testing.T) { - start := time.Date(2000, 4, 2, 0, 0, 0, 0, LosAngeles) - end := start.Add(4*time.Hour - time.Nanosecond) - itr := influxql.NewFillIterator( - &FloatIterator{Points: []influxql.FloatPoint{{Time: start.UnixNano(), Value: 0}}}, - nil, - influxql.IteratorOptions{ - StartTime: start.UnixNano(), - EndTime: end.UnixNano(), - Interval: influxql.Interval{ - Duration: time.Hour, + { + name: "Start_GroupByHour_Ascending", + start: mustParseTime("2000-04-02T00:00:00-08:00"), + end: mustParseTime("2000-04-02T05:00:00-07:00"), + points: []time.Duration{ + 1 * time.Hour, + 2 * time.Hour, + 3 * time.Hour, + }, + opt: influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 1 * time.Hour, + }, + Location: LosAngeles, + Ascending: true, }, - Location: LosAngeles, - Ascending: true, }, - ) - - if a, err := (Iterators{itr}).ReadAll(); err != nil { - t.Fatalf("unexpected error: %s", err) - } else if !deep.Equal(a, [][]influxql.Point{ - {&influxql.FloatPoint{Time: start.UnixNano(), Value: 0}}, - {&influxql.FloatPoint{Time: start.Add(1 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(2 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(3 * time.Hour).UnixNano(), Nil: true}}, - }) { - t.Fatalf("unexpected points: %s", spew.Sdump(a)) - } -} - -func TestFillIterator_DST_Start_GroupByHour_Descending(t *testing.T) { - start := time.Date(2000, 4, 2, 0, 0, 0, 0, LosAngeles) - end := start.Add(4*time.Hour - time.Nanosecond) - itr := influxql.NewFillIterator( - &FloatIterator{Points: []influxql.FloatPoint{{Time: start.UnixNano(), Value: 0}}}, - nil, - influxql.IteratorOptions{ - StartTime: start.UnixNano(), - EndTime: end.UnixNano(), - Interval: influxql.Interval{ - Duration: time.Hour, + { + name: "Start_GroupByHour_Descending", + start: mustParseTime("2000-04-02T00:00:00-08:00"), + end: mustParseTime("2000-04-02T05:00:00-07:00"), + points: []time.Duration{ + 3 * time.Hour, + 2 * time.Hour, + 1 * time.Hour, + }, + opt: influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 1 * time.Hour, + }, + Location: LosAngeles, + Ascending: false, }, - Location: LosAngeles, - Ascending: false, }, - ) - - if a, err := (Iterators{itr}).ReadAll(); err != nil { - t.Fatalf("unexpected error: %s", err) - } else if !deep.Equal(a, [][]influxql.Point{ - {&influxql.FloatPoint{Time: start.Add(3 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(2 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(1 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.UnixNano(), Value: 0}}, - }) { - t.Fatalf("unexpected points: %s", spew.Sdump(a)) - } -} - -func TestFillIterator_DST_End_GroupByDay_Ascending(t *testing.T) { - start := time.Date(2000, 10, 28, 0, 0, 0, 0, LosAngeles) - end := time.Date(2000, 11, 1, 0, 0, 0, 0, LosAngeles).Add(-time.Nanosecond) - itr := influxql.NewFillIterator( - &FloatIterator{Points: []influxql.FloatPoint{{Time: start.UnixNano(), Value: 0}}}, - nil, - influxql.IteratorOptions{ - StartTime: start.UnixNano(), - EndTime: end.UnixNano(), - Interval: influxql.Interval{ - Duration: 24 * time.Hour, + { + name: "Start_GroupBy2Hour_Ascending", + start: mustParseTime("2000-04-02T00:00:00-08:00"), + end: mustParseTime("2000-04-02T07:00:00-07:00"), + points: []time.Duration{ + 2 * time.Hour, + 3 * time.Hour, + 5 * time.Hour, + }, + opt: influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 2 * time.Hour, + }, + Location: LosAngeles, + Ascending: true, }, - Location: LosAngeles, - Ascending: true, }, - ) - - if a, err := (Iterators{itr}).ReadAll(); err != nil { - t.Fatalf("unexpected error: %s", err) - } else if !deep.Equal(a, [][]influxql.Point{ - {&influxql.FloatPoint{Time: start.UnixNano(), Value: 0}}, - {&influxql.FloatPoint{Time: start.Add(24 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(49 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(73 * time.Hour).UnixNano(), Nil: true}}, - }) { - t.Fatalf("unexpected points: %s", spew.Sdump(a)) - } -} - -func TestFillIterator_DST_End_GroupByDay_Descending(t *testing.T) { - start := time.Date(2000, 10, 28, 0, 0, 0, 0, LosAngeles) - end := time.Date(2000, 11, 1, 0, 0, 0, 0, LosAngeles).Add(-time.Nanosecond) - itr := influxql.NewFillIterator( - &FloatIterator{Points: []influxql.FloatPoint{{Time: start.UnixNano(), Value: 0}}}, - nil, - influxql.IteratorOptions{ - StartTime: start.UnixNano(), - EndTime: end.UnixNano(), - Interval: influxql.Interval{ - Duration: 24 * time.Hour, + { + name: "Start_GroupBy2Hour_Descending", + start: mustParseTime("2000-04-02T00:00:00-08:00"), + end: mustParseTime("2000-04-02T07:00:00-07:00"), + points: []time.Duration{ + 5 * time.Hour, + 3 * time.Hour, + 2 * time.Hour, + }, + opt: influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 2 * time.Hour, + }, + Location: LosAngeles, + Ascending: false, }, - Location: LosAngeles, - Ascending: false, }, - ) - - if a, err := (Iterators{itr}).ReadAll(); err != nil { - t.Fatalf("unexpected error: %s", err) - } else if !deep.Equal(a, [][]influxql.Point{ - {&influxql.FloatPoint{Time: start.Add(73 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(49 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(24 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.UnixNano(), Value: 0}}, - }) { - t.Fatalf("unexpected points: %s", spew.Sdump(a)) - } -} - -func TestFillIterator_DST_End_GroupByHour_Ascending(t *testing.T) { - start := time.Date(2000, 10, 29, 0, 0, 0, 0, LosAngeles) - end := start.Add(4*time.Hour - time.Nanosecond) - itr := influxql.NewFillIterator( - &FloatIterator{Points: []influxql.FloatPoint{{Time: start.UnixNano(), Value: 0}}}, - nil, - influxql.IteratorOptions{ - StartTime: start.UnixNano(), - EndTime: end.UnixNano(), - Interval: influxql.Interval{ - Duration: time.Hour, + { + name: "End_GroupByDay_Ascending", + start: mustParseTime("2000-10-28T00:00:00-07:00"), + end: mustParseTime("2000-11-01T00:00:00-08:00"), + points: []time.Duration{ + 24 * time.Hour, + 49 * time.Hour, + 73 * time.Hour, + }, + opt: influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 24 * time.Hour, + }, + Location: LosAngeles, + Ascending: true, }, - Location: LosAngeles, - Ascending: true, }, - ) - - if a, err := (Iterators{itr}).ReadAll(); err != nil { - t.Fatalf("unexpected error: %s", err) - } else if !deep.Equal(a, [][]influxql.Point{ - {&influxql.FloatPoint{Time: start.UnixNano(), Value: 0}}, - {&influxql.FloatPoint{Time: start.Add(1 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(2 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(3 * time.Hour).UnixNano(), Nil: true}}, - }) { - t.Fatalf("unexpected points: %s", spew.Sdump(a)) - } -} - -func TestFillIterator_DST_End_GroupByHour_Descending(t *testing.T) { - start := time.Date(2000, 10, 29, 0, 0, 0, 0, LosAngeles) - end := start.Add(4*time.Hour - time.Nanosecond) - itr := influxql.NewFillIterator( - &FloatIterator{Points: []influxql.FloatPoint{{Time: start.UnixNano(), Value: 0}}}, - nil, - influxql.IteratorOptions{ - StartTime: start.UnixNano(), - EndTime: end.UnixNano(), - Interval: influxql.Interval{ - Duration: time.Hour, + { + name: "End_GroupByDay_Descending", + start: mustParseTime("2000-10-28T00:00:00-07:00"), + end: mustParseTime("2000-11-01T00:00:00-08:00"), + points: []time.Duration{ + 73 * time.Hour, + 49 * time.Hour, + 24 * time.Hour, + }, + opt: influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 24 * time.Hour, + }, + Location: LosAngeles, + Ascending: false, }, - Location: LosAngeles, - Ascending: false, }, - ) - - if a, err := (Iterators{itr}).ReadAll(); err != nil { - t.Fatalf("unexpected error: %s", err) - } else if !deep.Equal(a, [][]influxql.Point{ - {&influxql.FloatPoint{Time: start.Add(3 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(2 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.Add(1 * time.Hour).UnixNano(), Nil: true}}, - {&influxql.FloatPoint{Time: start.UnixNano(), Value: 0}}, - }) { - t.Fatalf("unexpected points: %s", spew.Sdump(a)) + { + name: "End_GroupByHour_Ascending", + start: mustParseTime("2000-10-29T00:00:00-07:00"), + end: mustParseTime("2000-10-29T03:00:00-08:00"), + points: []time.Duration{ + 1 * time.Hour, + 2 * time.Hour, + 3 * time.Hour, + }, + opt: influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 1 * time.Hour, + }, + Location: LosAngeles, + Ascending: true, + }, + }, + { + name: "End_GroupByHour_Descending", + start: mustParseTime("2000-10-29T00:00:00-07:00"), + end: mustParseTime("2000-10-29T03:00:00-08:00"), + points: []time.Duration{ + 3 * time.Hour, + 2 * time.Hour, + 1 * time.Hour, + }, + opt: influxql.IteratorOptions{ + Interval: influxql.Interval{ + Duration: 1 * time.Hour, + }, + Location: LosAngeles, + Ascending: false, + }, + }, + } { + t.Run(tt.name, func(t *testing.T) { + opt := tt.opt + opt.StartTime = tt.start.UnixNano() + opt.EndTime = tt.end.UnixNano() - 1 + + points := make([][]influxql.Point, 0, len(tt.points)+1) + if opt.Ascending { + points = append(points, []influxql.Point{ + &influxql.FloatPoint{ + Time: tt.start.UnixNano(), + }, + }) + } + for _, d := range tt.points { + points = append(points, []influxql.Point{ + &influxql.FloatPoint{ + Time: tt.start.Add(d).UnixNano(), + Nil: true, + }, + }) + } + if !opt.Ascending { + points = append(points, []influxql.Point{ + &influxql.FloatPoint{ + Time: tt.start.UnixNano(), + }, + }) + } + itr := influxql.NewFillIterator( + &FloatIterator{Points: []influxql.FloatPoint{{Time: tt.start.UnixNano(), Value: 0}}}, + nil, + opt, + ) + + if a, err := (Iterators{itr}).ReadAll(); err != nil { + t.Fatalf("unexpected error: %s", err) + } else if !deep.Equal(a, points) { + t.Fatalf("unexpected points: %s", spew.Sdump(a)) + } + }) } } @@ -1047,23 +1036,99 @@ func TestIteratorOptions_Window_Default(t *testing.T) { } func TestIteratorOptions_Window_Location(t *testing.T) { - now := time.Date(2000, 4, 2, 12, 14, 15, 0, LosAngeles) - opt := influxql.IteratorOptions{ - Location: LosAngeles, - Interval: influxql.Interval{ - Duration: 24 * time.Hour, + for _, tt := range []struct { + now time.Time + start, end time.Time + interval time.Duration + }{ + { + now: mustParseTime("2000-04-02T12:14:15-07:00"), + start: mustParseTime("2000-04-02T00:00:00-08:00"), + end: mustParseTime("2000-04-03T00:00:00-07:00"), + interval: 24 * time.Hour, }, - } - - start, end := opt.Window(now.UnixNano()) - if exp := time.Date(2000, 4, 2, 0, 0, 0, 0, LosAngeles).UnixNano(); start != exp { - t.Errorf("expected start to be %d, got %d", exp, start) - } - if exp := time.Date(2000, 4, 3, 0, 0, 0, 0, LosAngeles).UnixNano(); end != exp { - t.Errorf("expected end to be %d, got %d", exp, end) - } - if got, exp := time.Duration(end-start), 23*time.Hour; got != exp { - t.Errorf("expected duration to be %s, got %s", exp, got) + { + now: mustParseTime("2000-04-02T01:17:12-08:00"), + start: mustParseTime("2000-04-02T00:00:00-08:00"), + end: mustParseTime("2000-04-03T00:00:00-07:00"), + interval: 24 * time.Hour, + }, + { + now: mustParseTime("2000-04-02T01:14:15-08:00"), + start: mustParseTime("2000-04-02T00:00:00-08:00"), + end: mustParseTime("2000-04-02T03:00:00-07:00"), + interval: 2 * time.Hour, + }, + { + now: mustParseTime("2000-04-02T03:17:12-07:00"), + start: mustParseTime("2000-04-02T03:00:00-07:00"), + end: mustParseTime("2000-04-02T04:00:00-07:00"), + interval: 2 * time.Hour, + }, + { + now: mustParseTime("2000-04-02T01:14:15-08:00"), + start: mustParseTime("2000-04-02T01:00:00-08:00"), + end: mustParseTime("2000-04-02T03:00:00-07:00"), + interval: 1 * time.Hour, + }, + { + now: mustParseTime("2000-04-02T03:17:12-07:00"), + start: mustParseTime("2000-04-02T03:00:00-07:00"), + end: mustParseTime("2000-04-02T04:00:00-07:00"), + interval: 1 * time.Hour, + }, + { + now: mustParseTime("2000-10-29T12:14:15-08:00"), + start: mustParseTime("2000-10-29T00:00:00-07:00"), + end: mustParseTime("2000-10-30T00:00:00-08:00"), + interval: 24 * time.Hour, + }, + { + now: mustParseTime("2000-10-29T01:17:12-07:00"), + start: mustParseTime("2000-10-29T00:00:00-07:00"), + end: mustParseTime("2000-10-30T00:00:00-08:00"), + interval: 24 * time.Hour, + }, + { + now: mustParseTime("2000-10-29T01:14:15-07:00"), + start: mustParseTime("2000-10-29T00:00:00-07:00"), + end: mustParseTime("2000-10-29T02:00:00-08:00"), + interval: 2 * time.Hour, + }, + { + now: mustParseTime("2000-10-29T03:17:12-08:00"), + start: mustParseTime("2000-10-29T02:00:00-08:00"), + end: mustParseTime("2000-10-29T04:00:00-08:00"), + interval: 2 * time.Hour, + }, + { + now: mustParseTime("2000-10-29T01:14:15-07:00"), + start: mustParseTime("2000-10-29T01:00:00-07:00"), + end: mustParseTime("2000-10-29T01:00:00-08:00"), + interval: 1 * time.Hour, + }, + { + now: mustParseTime("2000-10-29T02:17:12-07:00"), + start: mustParseTime("2000-10-29T02:00:00-07:00"), + end: mustParseTime("2000-10-29T03:00:00-07:00"), + interval: 1 * time.Hour, + }, + } { + t.Run(fmt.Sprintf("%s/%s", tt.now, tt.interval), func(t *testing.T) { + opt := influxql.IteratorOptions{ + Location: LosAngeles, + Interval: influxql.Interval{ + Duration: tt.interval, + }, + } + start, end := opt.Window(tt.now.UnixNano()) + if have, want := time.Unix(0, start).In(LosAngeles), tt.start; !have.Equal(want) { + t.Errorf("unexpected start time: %s != %s", have, want) + } + if have, want := time.Unix(0, end).In(LosAngeles), tt.end; !have.Equal(want) { + t.Errorf("unexpected end time: %s != %s", have, want) + } + }) } }