Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stop rounding times #1172

Merged
merged 4 commits into from Feb 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
43 changes: 26 additions & 17 deletions utils.go
Expand Up @@ -277,30 +277,24 @@ func parseBinaryDateTime(num uint64, data []byte, loc *time.Location) (driver.Va
}

func appendDateTime(buf []byte, t time.Time) ([]byte, error) {
nsec := t.Nanosecond()
// to round under microsecond
if nsec%1000 >= 500 { // save half of time.Time.Add calls
t = t.Add(500 * time.Nanosecond)
nsec = t.Nanosecond()
}
year, month, day := t.Date()
hour, min, sec := t.Clock()
micro := nsec / 1000
nsec := t.Nanosecond()

if year < 1 || year > 9999 {
return buf, errors.New("year is not in the range [1, 9999]: " + strconv.Itoa(year)) // use errors.New instead of fmt.Errorf to avoid year escape to heap
}
year100 := year / 100
year1 := year % 100

var localBuf [26]byte // does not escape
var localBuf [len("2006-01-02T15:04:05.999999999")]byte // does not escape
localBuf[0], localBuf[1], localBuf[2], localBuf[3] = digits10[year100], digits01[year100], digits10[year1], digits01[year1]
localBuf[4] = '-'
localBuf[5], localBuf[6] = digits10[month], digits01[month]
localBuf[7] = '-'
localBuf[8], localBuf[9] = digits10[day], digits01[day]

if hour == 0 && min == 0 && sec == 0 && micro == 0 {
if hour == 0 && min == 0 && sec == 0 && nsec == 0 {
return append(buf, localBuf[:10]...), nil
}

Expand All @@ -311,18 +305,33 @@ func appendDateTime(buf []byte, t time.Time) ([]byte, error) {
localBuf[16] = ':'
localBuf[17], localBuf[18] = digits10[sec], digits01[sec]

if micro == 0 {
if nsec == 0 {
return append(buf, localBuf[:19]...), nil
}

micro10000 := micro / 10000
micro100 := (micro / 100) % 100
micro1 := micro % 100
nsec100000000 := nsec / 100000000
nsec1000000 := (nsec / 1000000) % 100
nsec10000 := (nsec / 10000) % 100
nsec100 := (nsec / 100) % 100
nsec1 := nsec % 100
localBuf[19] = '.'
localBuf[20], localBuf[21], localBuf[22], localBuf[23], localBuf[24], localBuf[25] =
digits10[micro10000], digits01[micro10000], digits10[micro100], digits01[micro100], digits10[micro1], digits01[micro1]

return append(buf, localBuf[:]...), nil
// milli second
localBuf[20], localBuf[21], localBuf[22] =
digits01[nsec100000000], digits10[nsec1000000], digits01[nsec1000000]
// micro second
localBuf[23], localBuf[24], localBuf[25] =
digits10[nsec10000], digits01[nsec10000], digits10[nsec100]
// nano second
localBuf[26], localBuf[27], localBuf[28] =
digits01[nsec100], digits10[nsec1], digits01[nsec1]

// trim trailing zeros
n := len(localBuf)
for n > 0 && localBuf[n-1] == '0' {
n--
}

return append(buf, localBuf[:n]...), nil
}

// zeroDateTime is used in formatBinaryDateTime to avoid an allocation
Expand Down
37 changes: 18 additions & 19 deletions utils_test.go
Expand Up @@ -299,48 +299,47 @@ func TestAppendDateTime(t *testing.T) {
str string
}{
{
t: time.Date(2020, 05, 30, 0, 0, 0, 0, time.UTC),
str: "2020-05-30",
t: time.Date(1234, 5, 6, 0, 0, 0, 0, time.UTC),
str: "1234-05-06",
},
{
t: time.Date(2020, 05, 30, 22, 0, 0, 0, time.UTC),
str: "2020-05-30 22:00:00",
t: time.Date(4567, 12, 31, 12, 0, 0, 0, time.UTC),
str: "4567-12-31 12:00:00",
},
{
t: time.Date(2020, 05, 30, 22, 33, 0, 0, time.UTC),
str: "2020-05-30 22:33:00",
t: time.Date(2020, 5, 30, 12, 34, 0, 0, time.UTC),
str: "2020-05-30 12:34:00",
},
{
t: time.Date(2020, 05, 30, 22, 33, 44, 0, time.UTC),
str: "2020-05-30 22:33:44",
t: time.Date(2020, 5, 30, 12, 34, 56, 0, time.UTC),
str: "2020-05-30 12:34:56",
},
{
t: time.Date(2020, 05, 30, 22, 33, 44, 550000000, time.UTC),
str: "2020-05-30 22:33:44.550000",
t: time.Date(2020, 5, 30, 22, 33, 44, 123000000, time.UTC),
str: "2020-05-30 22:33:44.123",
},
{
t: time.Date(2020, 05, 30, 22, 33, 44, 550000499, time.UTC),
str: "2020-05-30 22:33:44.550000",
t: time.Date(2020, 5, 30, 22, 33, 44, 123456000, time.UTC),
str: "2020-05-30 22:33:44.123456",
},
{
t: time.Date(2020, 05, 30, 22, 33, 44, 550000500, time.UTC),
str: "2020-05-30 22:33:44.550001",
t: time.Date(2020, 5, 30, 22, 33, 44, 123456789, time.UTC),
str: "2020-05-30 22:33:44.123456789",
},
{
t: time.Date(2020, 05, 30, 22, 33, 44, 550000567, time.UTC),
str: "2020-05-30 22:33:44.550001",
t: time.Date(9999, 12, 31, 23, 59, 59, 999999999, time.UTC),
str: "9999-12-31 23:59:59.999999999",
},
{
t: time.Date(2020, 05, 30, 22, 33, 44, 999999567, time.UTC),
str: "2020-05-30 22:33:45",
t: time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC),
str: "0001-01-01",
},
}
for _, v := range tests {
buf := make([]byte, 0, 32)
buf, _ = appendDateTime(buf, v.t)
if str := string(buf); str != v.str {
t.Errorf("appendDateTime(%v), have: %s, want: %s", v.t, str, v.str)
return
}
}

Expand Down