Skip to content
FreeAIDevTools

Epoch Converter in Go

Convert Unix timestamps to dates and back in Go: the idiomatic code, the gotchas, and a live converter.

How do you convert a Unix timestamp to a time.Time in Go? Call time.Unix(sec, 0) to build a time.Time from epoch seconds, and t.Unix() or time.Now().Unix() to go back. Since Go 1.17 there are also UnixMilli and UnixMicro variants, alongside the long-standing UnixNano; mixing them up shifts your dates by factors of a thousand, so match the method to the digit count.

Epoch to date (Go)
package main

import (
	"fmt"
	"time"
)

func main() {
	ts := int64(1777010400)
	t := time.Unix(ts, 0).UTC()
	fmt.Println(t) // 2026-04-24 06:00:00 +0000 UTC
}
Date to epoch (Go)
package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()
	fmt.Println(now.Unix())      // seconds
	fmt.Println(now.UnixMilli()) // milliseconds
}
Now: …
Open the full Epoch Converter →

The Inference Report · Every Tuesday

Know when AI prices change.

One short email every Tuesday: new models, price moves and free tiers that were cut or added. Five minutes, no fluff.

No spam. Unsubscribe anytime.

Four precisions, one type

Go's native epoch convention is seconds via t.Unix(), matching the POSIX world it grew up in, but time.Time exposes the whole precision ladder: UnixMilli, UnixMicro, and UnixNano, with time.UnixMilli and time.UnixMicro constructors added in Go 1.17 (for nanoseconds use time.Unix(0, ns)). All of them return int64, so the compiler cannot catch a seconds value flowing into a milliseconds field. The failure mode is a date a thousand times too early or too late, and the fix is a convention: decide the unit at your service boundary, document it in the field name (created_at_ms beats created_at), and convert exactly once.

Locations, comparisons, and why 2038 is not Go's problem

time.Unix returns a Time in the local Location, which makes fmt.Println output differ between your laptop and a UTC container. Chain .UTC() when the output should be stable, and note that the underlying instant is identical either way; only the rendering changes. When comparing timestamps, prefer t.Equal(other) over ==, because == also compares the Location and the monotonic clock reading that time.Now() embeds. On range: Go's int64 seconds and its internal representation put the overflow horizon billions of years out, so the 2038 problem lives in 32-bit C code and old MySQL columns, not in your Go services.

Frequently asked

How do I get the current Unix timestamp in Go?

time.Now().Unix() for seconds, time.Now().UnixMilli() for milliseconds, and UnixNano() for nanoseconds. All return int64. Pick the unit your consumers expect and name the field so the unit is obvious, because the type system cannot tell them apart.

Why does time.Unix print a different timezone than I expect?

time.Unix returns the instant in the process's local Location, so output depends on the machine's TZ setting. Append .UTC(), as in time.Unix(ts, 0).UTC(), for stable output. The instant itself is unchanged; only the wall-clock rendering moves.

Is Go affected by the year 2038 problem?

No. Go stores epoch seconds as int64, which does not overflow until long after the sun burns out. The 2038 cliff applies to 32-bit time_t in C, older embedded systems, and MySQL TIMESTAMP columns, so watch your storage layer rather than your Go code.

More in this series