How to parse unix timestamp to time.Time
Asked Answered
M

7

217

I'm trying to parse an Unix timestamp but I get out of range error. That doesn't really makes sense to me, because the layout is correct (as in the Go docs):

package main

import "fmt"
import "time"

func main() {
    tm, err := time.Parse("1136239445", "1405544146")
    if err != nil{
        panic(err)
    }

    fmt.Println(tm)
}

Playground

Moreland answered 28/7, 2014 at 0:45 Comment(0)
A
404

The time.Parse function does not do Unix timestamps. Instead you can use strconv.ParseInt to parse the string to int64 and create the timestamp with time.Unix:

package main

import (
    "fmt"
    "time"
    "strconv"
)

func main() {
    i, err := strconv.ParseInt("1405544146", 10, 64)
    if err != nil {
        panic(err)
    }
    tm := time.Unix(i, 0)
    fmt.Println(tm)
}

Output:

2014-07-16 20:55:46 +0000 UTC

Playground: http://play.golang.org/p/v_j6UIro7a

Edit:

Changed from strconv.Atoi to strconv.ParseInt to avoid int overflows on 32 bit systems.

Arrowworm answered 28/7, 2014 at 1:2 Comment(5)
Any idea why there is no such reference in the docs? They even give the unix timestap layout as a layout example.Moreland
I guess it is because a unix timestamp isn't requiring parsing as it is not a text representation, but rather an integer representation of time. You just happened to have a string representation of an integer value. And the mentioning of 1136239445 in the docs is probably just to clarify what exact timestamp is to be used as reference time, not that it is to be used as layout.Arrowworm
Wouldn't it be better to use strconv.ParseUint instead as negative numbers don't make sense anyway?Paolapaolina
@Atmocreations: func Unix(sec int64, nsec int64) Time receives int64 values. Also, negative numbers for sec makes perfect sense - they describe dates prior to 1970! :) As for nsec, negative values means to remove that many nanoseconds from the seconds.Arrowworm
I want only the date and time as " 2014-07-16 20:55:46" how could be it achieved ?Renovate
B
34

You can directly use time.Unix function of time which converts the unix time stamp to UTC

package main

import (
  "fmt"
  "time"
)


func main() {
    unixTimeUTC:=time.Unix(1405544146, 0) //gives unix time stamp in utc 

    unitTimeInRFC3339 :=unixTimeUTC.Format(time.RFC3339) // converts utc time to RFC3339 format

    fmt.Println("unix time stamp in UTC :--->",unixTimeUTC)
    fmt.Println("unix time stamp in unitTimeInRFC3339 format :->",unitTimeInRFC3339)
}

Output

unix time stamp in UTC :---> 2014-07-16 20:55:46 +0000 UTC
unix time stamp in unitTimeInRFC3339 format :----> 2014-07-16T20:55:46Z

Check in Go Playground: https://play.golang.org/p/5FtRdnkxAd

Birth answered 6/12, 2017 at 8:59 Comment(2)
time.Unix() is documented to return the local time. Therefore, the unixTimeUTC in this answer is not always providing the time in the UTC timezone. Only when the local time zone corresponds to UTC.Appalling
@Dr.Jan-PhilipGehrcke: I wonder whether it ultimately matters. time.Unix() will parse the time into a time in some timezone (with the timezone information). It can then be reused anywhere (for instance converting to a given TZ). True, the variable name may not be fortunate in that case.Dimissory
G
6

Sharing a few functions which I created for dates:

Please note that I wanted to get time for a particular location (not just UTC time). If you want UTC time, just remove loc variable and .In(loc) function call.

func GetTimeStamp() string {
     loc, _ := time.LoadLocation("America/Los_Angeles")
     t := time.Now().In(loc)
     return t.Format("20060102150405")
}
func GetTodaysDate() string {
    loc, _ := time.LoadLocation("America/Los_Angeles")
    current_time := time.Now().In(loc)
    return current_time.Format("2006-01-02")
}

func GetTodaysDateTime() string {
    loc, _ := time.LoadLocation("America/Los_Angeles")
    current_time := time.Now().In(loc)
    return current_time.Format("2006-01-02 15:04:05")
}

func GetTodaysDateTimeFormatted() string {
    loc, _ := time.LoadLocation("America/Los_Angeles")
    current_time := time.Now().In(loc)
    return current_time.Format("Jan 2, 2006 at 3:04 PM")
}

func GetTimeStampFromDate(dtformat string) string {
    form := "Jan 2, 2006 at 3:04 PM"
    t2, _ := time.Parse(form, dtformat)
    return t2.Format("20060102150405")
}
Garver answered 14/12, 2017 at 3:47 Comment(1)
Removing .In(loc) gave me time in -0400 EDT. Replacing it with .In(time.UTC) gave me time in UTC.Lyontine
T
5

This is an old question but I noticed that a practical answer is missing.

For example, we were working with the MavLink protocol and we need to process a message with a structure defined here.

If we have this data structure:

Field Name Type Units Description
time_boot_ms uint64_t ms Timestamp (time since system boot).
press_abs float hPa Absolute pressure
press_diff float hPa Differential pressure 1
temperature int16_t cdegC Absolute pressure temperature
temperature_press_diff ** int16_t cdegC Differential pressure temperature (0, if not available). Report values of 0 (or 1) as 1 cdegC.

So, we receive constant updates that we need to process using the time_boot_ms as reference to insert them on the database and synchronize them with other messages.

What can we do?

As we noticed, the time is in milliseconds and everyone, that has some experience with Go, knows that for some unknown reason it's just way too complex to convert a millisecond resolution Unix timestamp to time.Time. The built-in time.Unix() function only supports second and nanosecond precision.

How we can get millisecond precision?

Well, we might wait until they release the version 1.7 of Go or we either have to multiply the milliseconds to nanoseconds or split them into seconds and nanoseconds.

Lets implement the second idea, spit the into seconds and nanoseconds:

unixUTCtime := time.Unix(ms/int64(1000), (ms%int64(1000))*int64(1000000))

Now we can encapsulate it in a func and use it in our main like this:

package main

import (
    "fmt"
    "time"
)

const msInSecond int64 = 1e3
const nsInMillisecond int64 = 1e6

// UnixToMS Converts Unix Epoch from milliseconds to time.Time
func UnixToMS (ms int64) time.Time {
    return time.Unix(ms/msInSecond, (ms%msInSecond)*nsInMillisecond)
}


func main() {
    unixTimes := [...]int64{758991688, 758992188, 758992690, 758993186}
    var unixUTCTimes []time.Time
    for index, unixTime := range unixTimes {
        unixUTCTimes = append(unixUTCTimes, UnixToMS(unixTime))
        if index > 0 {
            timeDifference := unixUTCTimes[index].Sub(unixUTCTimes[index-1])
            fmt.Println("Time difference in ms :--->", timeDifference)
        }
    }
}

The output will be:

Time difference in ms :---> 500ms
Time difference in ms :---> 502ms
Time difference in ms :---> 496ms

Check in Go Playground

Update

From version 1.7, go now provides millisecond resolution either to convert a unix time represented as a int64 number into a Time type (nanosecond precision) using time.UnixMilli function or from Time into millisecond precision using UnixMilli function. This is their implementation:

func Unix(sec int64, nsec int64) Time {
    if nsec < 0 || nsec >= 1e9 {
        n := nsec / 1e9
        sec += n
        nsec -= n * 1e9
        if nsec < 0 {
            nsec += 1e9
            sec--
        }
    }
    return unixTime(sec, int32(nsec))
}


func UnixMilli(msec int64) Time {
    return Unix(msec/1e3, (msec%1e3)*1e6)
}

func (t Time) UnixMilli() int64 {
    return t.unixSec()*1e3 + int64(t.nsec())/1e6
}

How to use this Teo?

Very simple just modify this line from the previous implementation of our example:

unixUTCTimes = append(unixUTCTimes, UnixToMS(unixTime))

with this code:

unixUTCTimes = append(unixUTCTimes, time.UnixMilli(unixTime))

No need of other functions just call time.UnixMilli(unixTime). Check the playground here.

Touter answered 10/8, 2021 at 5:29 Comment(0)
I
5

for millis unix timestamp precision, in go1.18

    i, err := strconv.ParseInt("1652084489543", 10, 64)
    if err != nil {
        panic(err)
    }
    tm := time.UnixMilli(i)
    fmt.Println(tm)

Indentation answered 9/5, 2022 at 9:3 Comment(0)
P
3

I do a lot of logging where the timestamps are float64 and use this function to get the timestamps as string:

func dateFormat(layout string, d float64) string{
    intTime := int64(d)
    t := time.Unix(intTime, 0)
    if layout == "" {
        layout = "2006-01-02 15:04:05"
    }
    return t.Format(layout)
}
Pointsman answered 23/7, 2020 at 17:45 Comment(0)
C
2

According to the go documentation, Unix returns a local time.

Unix returns the local Time corresponding to the given Unix time

This means the output would depend on the machine your code runs on, which, most often is what you need, but sometimes, you may want to have the value in UTC.

To do so, I adapted the snippet to make it return a time in UTC:

i, err := strconv.ParseInt("1405544146", 10, 64)
if err != nil {
    panic(err)
}
tm := time.Unix(i, 0)
fmt.Println(tm.UTC())

This prints on my machine (in CEST)

2014-07-16 20:55:46 +0000 UTC
Carmody answered 24/9, 2018 at 20:57 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.