Best way of parsing date and time in golang

date, go, parsing, performance, time

Solution

I would expect to make your entire program much faster. For example, `ParseDate3`,

func ParseDate3(date []byte) (time.Time, error) {
    year := (((int(date[0])-'0')*10+int(date[1])-'0')*10+int(date[2])-'0')*10 + int(date[3]) - '0'
    month := time.Month((int(date[5])-'0')*10 + int(date[6]) - '0')
    day := (int(date[8])-'0')*10 + int(date[9]) - '0'
    hour := (int(date[11])-'0')*10 + int(date[12]) - '0'
    minute := (int(date[14])-'0')*10 + int(date[15]) - '0'
    second := (int(date[17])-'0')*10 + int(date[18]) - '0'
    return time.Date(year, month, day, hour, minute, second, 0, time.UTC), nil
}

Benchmarks:

$ go test -bench=.
testing: warning: no tests to run
PASS
BenchmarkParseDate1  5000000           308 ns/op
BenchmarkParseDate2 10000000           225 ns/op
BenchmarkParseDate3 30000000            44.9 ns/op
ok      so/test 5.741s
$ go test -bench=.
testing: warning: no tests to run
PASS
BenchmarkParseDate1  5000000           308 ns/op
BenchmarkParseDate2 10000000           226 ns/op
BenchmarkParseDate3 30000000            45.4 ns/op
ok      so/test 5.757s
$ go test -bench=.
testing: warning: no tests to run
PASS
BenchmarkParseDate1  5000000           312 ns/op
BenchmarkParseDate2 10000000           225 ns/op
BenchmarkParseDate3 30000000            45.0 ns/op
ok      so/test 5.761s
$ 

Reference:

Profiling Go Programs

If you insist on using `date string`, use `ParseDate4`,

func ParseDate4(date string) (time.Time, error) {
    year := (((int(date[0])-'0')*10+int(date[1])-'0')*10+int(date[2])-'0')*10 + int(date[3]) - '0'
    month := time.Month((int(date[5])-'0')*10 + int(date[6]) - '0')
    day := (int(date[8])-'0')*10 + int(date[9]) - '0'
    hour := (int(date[11])-'0')*10 + int(date[12]) - '0'
    minute := (int(date[14])-'0')*10 + int(date[15]) - '0'
    second := (int(date[17])-'0')*10 + int(date[18]) - '0'
    return time.Date(year, month, day, hour, minute, second, 0, time.UTC), nil
}

Problem

I have a lot of datetime values incoming as string into my golang program. The format is fixed in number of digit: ``` 2006/01/02 15:04:05 ``` I started to parse these dates with the time.Parse function ``` const dtFormat = "2006/01/02 15:04:05" func ParseDate1(strdate string) (time.Time, error) { return time.Parse(dtFormat, strdate) } ``` but I had some performances issue with my program. Thus I tried to tune it by writting my own parsing function, taking into account that my format is kind of fixed: ``` func ParseDate2(strdate string) (time.Time, error) { year, _ := strconv.Atoi(strdate[:4]) month, _ := strconv.Atoi(strdate[5:7]) day, _ := strconv.Atoi(strdate[8:10]) hour, _ := strconv.Atoi(strdate[11:13]) minute, _ := strconv.Atoi(strdate[14:16]) second, _ := strconv.Atoi(strdate[17:19]) return time.Date(year, time.Month(month), day, hour, minute, second, 0, time.UTC), nil } ``` finally I did a benchmark on top of these 2 functions and got the following result: ``` BenchmarkParseDate1 5000000 343 ns/op BenchmarkParseDate2 10000000 248 ns/op ``` This is a performance improvement by 27%. Is there a better way in terms of performances that could improve such datetime parsing ?

Original source