Skip to content

Commit

Permalink
Optimize Date/Date32 scan (#1374)
Browse files Browse the repository at this point in the history
  • Loading branch information
ShoshinNikita authored Aug 19, 2024
1 parent 79d6313 commit dc05f5e
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 13 deletions.
8 changes: 3 additions & 5 deletions lib/column/date.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,7 @@ func parseDate(value string, minDate time.Time, maxDate time.Time, location *tim
return tv, nil
}
if tv, err = time.Parse(defaultDateFormatNoZone, value); err == nil {
return time.Date(
tv.Year(), tv.Month(), tv.Day(), tv.Hour(), tv.Minute(), tv.Second(), tv.Nanosecond(), location,
), nil
return getTimeWithDifferentLocation(tv, location), nil
}
return time.Time{}, err
}
Expand All @@ -272,10 +270,10 @@ func (col *Date) Encode(buffer *proto.Buffer) {
func (col *Date) row(i int) time.Time {
t := col.col.Row(i)

if col.location != nil {
if col.location != nil && col.location != time.UTC {
// proto.Date is normalized as time.Time with UTC timezone.
// We make sure Date return from ClickHouse matches server timezone or user defined location.
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), col.location)
t = getTimeWithDifferentLocation(t, col.location)
}
return t
}
Expand Down
4 changes: 2 additions & 2 deletions lib/column/date32.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,10 +247,10 @@ func (col *Date32) Encode(buffer *proto.Buffer) {
func (col *Date32) row(i int) time.Time {
t := col.col.Row(i)

if col.location != nil {
if col.location != nil && col.location != time.UTC {
// proto.Date is normalized as time.Time with UTC timezone.
// We make sure Date return from ClickHouse matches server timezone or user defined location.
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), col.location)
t = getTimeWithDifferentLocation(t, col.location)
}
return t
}
Expand Down
4 changes: 1 addition & 3 deletions lib/column/datetime.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,7 @@ func (col *DateTime) parseDateTime(value string) (tv time.Time, err error) {
return tv, nil
}
if tv, err = time.Parse(defaultDateTimeFormatNoZone, value); err == nil {
return time.Date(
tv.Year(), tv.Month(), tv.Day(), tv.Hour(), tv.Minute(), tv.Second(), tv.Nanosecond(), time.Local,
), nil
return getTimeWithDifferentLocation(tv, time.Local), nil
}
return time.Time{}, err
}
Expand Down
4 changes: 1 addition & 3 deletions lib/column/datetime64.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,7 @@ func (col *DateTime64) parseDateTime(value string) (tv time.Time, err error) {
return tv, nil
}
if tv, err = time.Parse(defaultDateTime64FormatNoZone, value); err == nil {
return time.Date(
tv.Year(), tv.Month(), tv.Day(), tv.Hour(), tv.Minute(), tv.Second(), tv.Nanosecond(), time.Local,
), nil
return getTimeWithDifferentLocation(tv, time.Local), nil
}
return time.Time{}, err
}
Expand Down
29 changes: 29 additions & 0 deletions lib/column/time_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Licensed to ClickHouse, Inc. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. ClickHouse, Inc. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package column

import "time"

// getTimeWithDifferentLocation returns the same time but with different location, e.g.
// "2024-08-15 13:22:34 -03:00" will become "2024-08-15 13:22:34 +04:00".
func getTimeWithDifferentLocation(t time.Time, loc *time.Location) time.Time {
year, month, day := t.Date()
hour, minute, sec := t.Clock()

return time.Date(year, month, day, hour, minute, sec, t.Nanosecond(), loc)
}
76 changes: 76 additions & 0 deletions lib/column/time_helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Licensed to ClickHouse, Inc. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. ClickHouse, Inc. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package column

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestGetTimeWithDifferentLocation(t *testing.T) {
tests := []struct {
in string
loc *time.Location
want string
}{
{
in: "2023-02-15 14:02:12.321 +00:00",
loc: time.FixedZone("", 60*60),
want: "2023-02-15 14:02:12.321 +01:00",
},
{
in: "2023-02-15 14:02:12.321 +03:00",
loc: time.FixedZone("", -4*60*60),
want: "2023-02-15 14:02:12.321 -04:00",
},
{
in: "2024-02-29 02:01:12 -06:00",
loc: time.FixedZone("", -4*60*60),
want: "2024-02-29 02:01:12 -04:00",
},
{
in: "2023-02-15 04:02:12.321 +02:00",
loc: time.UTC,
want: "2023-02-15 04:02:12.321 +00:00",
},
{
in: "2023-02-15 04:02:12.321 +00:00",
loc: time.UTC,
want: "2023-02-15 04:02:12.321 +00:00",
},
}
for _, tt := range tests {
in, _ := time.Parse(defaultDateTime64FormatWithZone, tt.in)
got := getTimeWithDifferentLocation(in, tt.loc)
assert.Equal(t, tt.want, got.Format(defaultDateTime64FormatWithZone))
}
}

var benchmarkResultTime time.Time

func BenchmarkGetTimeWithDifferentLocation(b *testing.B) {
t := time.Date(2023, time.April, 12, 1, 12, 33, 0, time.UTC)
loc := time.FixedZone("", 4*60*60)

b.ResetTimer()
for i := 0; i < b.N; i++ {
benchmarkResultTime = getTimeWithDifferentLocation(t, loc)
}
}

0 comments on commit dc05f5e

Please sign in to comment.