Unix Timestamp in Go

Go's time.Time exposes every unit directly. UnixNano() is common in tracing and metrics, which is why 19-digit timestamps show up so often in Go stacks.

Need to convert one value rather than write code? Use the interactive converter — it handles every unit and time zone without leaving your browser.

Current Unix timestamp

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()
	fmt.Println(now.Unix())       // 1710050400      seconds
	fmt.Println(now.UnixMilli())  // 1710050400000   milliseconds
	fmt.Println(now.UnixMicro())
	fmt.Println(now.UnixNano())   // 1710050400000000000
}

Timestamp to date

ts := int64(1710050400)

utc := time.Unix(ts, 0).UTC()
fmt.Println(utc.Format(time.RFC3339))   // 2024-03-10T06:00:00Z

loc, _ := time.LoadLocation("Asia/Kolkata")
fmt.Println(time.Unix(ts, 0).In(loc).Format("2006-01-02 15:04:05 MST"))

// From milliseconds
fmt.Println(time.UnixMilli(1710050400000).UTC())

Date to timestamp

loc, _ := time.LoadLocation("Asia/Kolkata")
t := time.Date(2024, time.March, 10, 11, 30, 0, 0, loc)
fmt.Println(t.Unix())                   // 1710050400

parsed, err := time.Parse(time.RFC3339, "2024-03-10T06:00:00Z")
if err == nil {
	fmt.Println(parsed.Unix())
}

The reference-time layout

// Go formats by example, not by format codes. The reference instant is:
//     Mon Jan 2 15:04:05 MST 2006     (i.e. 01/02 03:04:05PM '06 -0700)
t.Format("2006-01-02")            // 2024-03-10
t.Format("15:04:05")              // 11:30:00
t.Format(time.RFC1123)

Pitfalls specific to Go

  • time.LoadLocation needs the tzdata on the machine. In a scratch Docker image there is none — import _ "time/tzdata" to embed it in the binary.
  • time.Unix(sec, nsec) takes two arguments; passing a millisecond value as sec lands you ~53,000 years out.
  • A zero time.Time is year 1, not 1970. t.IsZero() is the correct emptiness check, not t.Unix() == 0.

Rules that apply in every language

  1. Store UTC, display local. Keep the instant in UTC everywhere in your system and convert only at the point a human reads it.
  2. Name the unit in the identifier. expires_at_ms rather than expires_at costs nothing and prevents the single most common timestamp bug.
  3. Never trust a client clock. Stamp anything security-relevant on the server. See the note on clock skew.
  4. Use 64-bit time. Anything still storing seconds in a signed 32-bit field breaks in January 2038 — see the Year 2038 problem.

The same task in other languages

Frequently asked questions

How do I get the current Unix timestamp in Go?

Use the snippet in the "Current Unix timestamp" section above. Go works in integer seconds and nanoseconds natively, so converting to another unit is a multiplication or an integer division away.

How do I convert a Unix timestamp to a date in Go?

The "Timestamp to date" snippet above shows the idiomatic approach, including how to render the result in a specific time zone rather than whatever zone the machine happens to be set to.

Does Go handle time zones and daylight saving correctly?

Yes, provided you pass an explicit zone rather than relying on the system default. The gotchas listed on this page cover the specific ways Go makes that easy to get wrong.