Skip to content

Commit

Permalink
stop rounding times (#1172)
Browse files Browse the repository at this point in the history
* stop rounding times

fixes #1121

* trim trailing zeros
  • Loading branch information
shogo82148 committed Feb 2, 2021
1 parent 4d5208a commit fe2230a
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 36 deletions.
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

0 comments on commit fe2230a

Please sign in to comment.