gpanda
gpanda

Reputation: 875

Golang time.Parse() Behavior - Dropping Precision when 000

In Go, I am confused as to the behavior of time.Parse() I observe when parsing date strings to time.Time.

In the event that a given time string's milliseconds are equal to exactly "000", e.g. "2017-01-02T01:02:03.000Z", time.Parse() will truncate the "000".

It would seem preferable to include, as opposed to omit this for consistency in logging and other use cases.

Is this the expected behavior? If so, why?

Bonus: How do we retain the "000"?

Playground

package main

import (
    "log"
    "time"
)

func main() {

    const (
        ISO_8601 = "2006-01-02T15:04:05.999Z"
    )

    tMap := map[string]string{
        "t00": "2017-01-02T01:02:03.000Z",
        "t01": "2017-01-02T01:02:03.000Z",
        "t02": "2017-01-02T01:02:03.456Z",
        "t03": "2017-01-03T01:02:03.123Z",
        "t04": "2013-10-04T01:02:03.456Z",
        "t05": "2012-02-02T01:02:03.321Z",
        "t06": "2011-03-07T01:02:03.849Z",
    }

    for _, v := range tMap {
        t, err := time.Parse(ISO_8601, v)
        logFatal("0H N03Z!!1", err)

        // Dude where's my 000?
        log.Printf("Key: %s | lenTimeString: %d | Val: %s \n", t.String(), len(t.String()), t)
    }
}

func logFatal(hint string, e error) {
    if e != nil {
        log.Fatal(hint, e)
    }
}

Output:

2009/11/10 23:00:00 Key: t05 | lenTimeString: 33 | timeString: 2012-02-02 01:02:03.321 +0000 UTC 
2009/11/10 23:00:00 Key: t06 | lenTimeString: 33 | timeString: 2011-03-07 01:02:03.849 +0000 UTC 
2009/11/10 23:00:00 Key: t00 | lenTimeString: 29 | timeString: 2017-01-02 01:02:03 +0000 UTC 
2009/11/10 23:00:00 Key: t01 | lenTimeString: 29 | timeString: 2017-01-02 01:02:03 +0000 UTC 
2009/11/10 23:00:00 Key: t02 | lenTimeString: 33 | timeString: 2017-01-02 01:02:03.456 +0000 UTC 
2009/11/10 23:00:00 Key: t03 | lenTimeString: 33 | timeString: 2017-01-03 01:02:03.123 +0000 UTC 
2009/11/10 23:00:00 Key: t04 | lenTimeString: 33 | timeString: 2013-10-04 01:02:03.456 +0000 UTC 

Edit: Here's a simplified solution with the kind help of @zerkms

Play

package main

import (
    "fmt"
    "time"
)

func main() {

    p := fmt.Println

    const (
        ISO_8601           = "2006-01-02T15:04:05.000Z"
        ISO_8601_dropmilli = "2006-01-02T15:04:05.999Z"
    )

    t := time.Date(2017, time.October, 31, 15, 16, 17, 000000000, time.Local)

    p(t.Format(ISO_8601))
    p(t.Format(ISO_8601_dropmilli))
}

Output:

2017-10-31T15:16:17.000Z
2017-10-31T15:16:17Z

Upvotes: 1

Views: 1029

Answers (1)

zerkms
zerkms

Reputation: 255155

time.String uses the 2006-01-02 15:04:05.999999999 -0700 MST format.

To keep the zeroes use 0 instead of 9: 2006-01-02 15:04:05.000000000 -0700 MST

t.Format("2006-01-02 15:04:05.000 -0700 MST")

Upvotes: 1

Related Questions