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 UnixNano variants; mixing them up shifts your dates by factors of a thousand, so match the method to the digit count.
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
}package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println(now.Unix()) // seconds
fmt.Println(now.UnixMilli()) // milliseconds
}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 matching constructors since Go 1.17. 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
// The subscription desk
The Inference Report
The weekly briefing for AI engineers: model releases, pricing moves, benchmarks, and the news that changes what you should build with and what it costs. Every Tuesday, 5-minute read. No fluff.
Join AI engineers who stopped overpaying for tokens. Unsubscribe anytime.