Question
I am trying to convert a Unix timestamp into a time.Time value in Go, but I get an "out of range" error. This is confusing because I thought the layout I used was valid according to the Go documentation.
Here is the code:
package main
import (
"fmt"
"time"
)
func main() {
tm, err := time.Parse("1136239445", "1405544146")
if err != nil {
panic(err)
}
fmt.Println(tm)
}
Why does this fail, and what is the correct way to convert a Unix timestamp to time.Time in Go?
Short Answer
By the end of this page, you will understand why time.Parse() does not work for Unix timestamps in Go, how Go's time layout system actually works, and how to correctly convert Unix seconds into a time.Time using time.Unix(). You will also learn common mistakes, practical usage patterns, and how this appears in real Go codebases.
Concept
In Go, time.Parse() is used for parsing formatted date/time strings, not raw Unix timestamps.
A Unix timestamp is typically a number representing the number of seconds since:
1970-01-01 00:00:00 UTC
For example:
1405544146means a specific moment in time measured as elapsed seconds since the Unix epoch.
Why time.Parse() fails
The first argument to time.Parse() is not a pattern like YYYY-MM-DD and it is not an example of your input format in a generic sense. In Go, the layout must use the special reference date:
Mon Jan 2 15:04:05 MST 2006
or pieces of it, such as:
2006-01-02
15:04:05
When you write:
time.Parse(, )
Mental Model
Think of Go time handling like having two different doors:
time.Parse()is the door for reading a clock/calendar string such as"2024-06-10 14:30:00"time.Unix()is the door for reading a stopwatch counter such as1405544146
A formatted date string says:
- "Here is the date written in human-readable form."
A Unix timestamp says:
- "Here is the number of seconds since a fixed starting point."
If you try to send a stopwatch number through the calendar-string door, it will not fit. That is exactly what happened in the original code.
Syntax and Examples
Core syntax
Parsing a formatted date string
parsedTime, err := time.Parse("2006-01-02 15:04:05", "2024-06-10 12:30:00")
Use this when your input is a human-readable date/time string.
Converting a Unix timestamp
t := time.Unix(1405544146, 0)
Use this when your input is seconds since the Unix epoch.
Beginner-friendly example
package main
import (
"fmt"
"time"
)
func main() {
timestamp := int64(1405544146)
tm := time.Unix(timestamp, 0)
fmt.Println(tm)
fmt.Println(tm.UTC())
}
Explanation
timestampis stored asint64, which matches whattime.Unix()expects.time.Unix(timestamp, 0)means:- first argument = seconds
Step by Step Execution
Consider this example:
package main
import (
"fmt"
"time"
)
func main() {
ts := int64(1405544146)
tm := time.Unix(ts, 0)
fmt.Println(tm.UTC())
}
Step by step
1. Create a timestamp value
ts := int64(1405544146)
tsstores the Unix timestamp.- It is an
int64, which is the expected type fortime.Unix().
2. Convert it to time.Time
tm := time.Unix(ts, 0)
tsis treated as seconds since1970-01-01 00:00:00 UTC.0means there are no extra nanoseconds.- Go creates a
time.Timevalue representing that exact instant.
Real World Use Cases
Unix timestamps are extremely common in real software.
APIs
Many APIs send timestamps like:
{"created_at": 1718012000}
In Go, you convert them with time.Unix() before displaying or comparing dates.
Logging systems
Log entries may store event times as Unix seconds or milliseconds. Converting them to time.Time makes them easier to format and analyze.
Databases
Some databases or legacy systems store timestamps as integers instead of full datetime values. Go applications often convert those integers into time.Time when reading records.
Expiration and scheduling
Applications frequently check whether a timestamp is before or after the current time:
expiresAt := time.Unix(expirySeconds, 0)
if time.Now().After(expiresAt) {
fmt.Println("expired")
}
Data processing scripts
CSV, JSON, or event-stream data often contains epoch-based timestamps. Converting them lets you group, sort, and filter records by time.
Real Codebase Usage
In real Go codebases, developers usually do more than a simple conversion.
Parse, validate, convert
If a timestamp comes in as a string, a common pattern is:
func parseUnixTimestamp(raw string) (time.Time, error) {
seconds, err := strconv.ParseInt(raw, 10, 64)
if err != nil {
return time.Time{}, fmt.Errorf("invalid unix timestamp: %w", err)
}
return time.Unix(seconds, 0), nil
}
This pattern keeps parsing logic reusable.
Guard clauses
Developers often reject invalid input early:
func process(raw string) error {
if raw == "" {
return fmt.Errorf("timestamp is required")
}
seconds, err := strconv.ParseInt(raw, 10, 64)
if err != nil {
return fmt.Errorf("bad timestamp: %w", err)
}
tm := time.Unix(seconds, )
fmt.Println(tm)
}
Common Mistakes
1. Using time.Parse() for Unix timestamps
Broken code:
tm, err := time.Parse("1136239445", "1405544146")
Why it is wrong:
time.Parse()expects a layout based on Go's reference date.- A Unix timestamp is not a formatted date string.
Fix:
tm := time.Unix(1405544146, 0)
2. Forgetting to convert a string to an integer first
Broken code:
raw := "1405544146"
tm := time.Unix(raw, 0)
Why it is wrong:
time.Unix()expects integer values, not strings.
Fix:
seconds, err := strconv.ParseInt(raw, 10, 64)
if err != nil {
panic(err)
}
tm := time.Unix(seconds, 0)
3. Confusing seconds with milliseconds
Comparisons
| Task | Correct Go Tool | Example |
|---|---|---|
| Parse a formatted date string | time.Parse() | time.Parse("2006-01-02", "2024-06-10") |
Convert Unix seconds to time.Time | time.Unix() | time.Unix(1405544146, 0) |
Convert Unix milliseconds to time.Time | time.UnixMilli() | time.UnixMilli(1405544146000) |
Convert Unix nanoseconds to time.Time | time.Unix(0, ns) or time.UnixNano patterns |
Cheat Sheet
// Formatted date string -> time.Time
t, err := time.Parse("2006-01-02 15:04:05", "2024-06-10 12:30:00")
// Unix seconds -> time.Time
t := time.Unix(1405544146, 0)
// Unix milliseconds -> time.Time
t := time.UnixMilli(1405544146000)
// String timestamp -> int64 -> time.Time
s := "1405544146"
seconds, err := strconv.ParseInt(s, 10, 64)
t := time.Unix(seconds, 0)
// Show in UTC
fmt.Println(t.UTC())
Rules to remember
time.Parse()is for formatted date strings.time.Unix()is for Unix timestamps in seconds.- Use
strconv.ParseInt()if the timestamp starts as a string. - Watch out for milliseconds vs seconds.
- Use
.UTC()when you want consistent output.
Common layouts in Go
"2006-01-02"
"15:04:05"
"2006-01-02 15:04:05"
These are based on Go's reference time, not custom placeholders like YYYY or MM.
FAQ
Why does time.Parse() not work with Unix timestamps in Go?
time.Parse() expects a formatted date string and a Go layout based on the reference date. A Unix timestamp is just a number of seconds since the epoch, so time.Unix() is the correct function.
How do I convert a Unix timestamp string to time.Time in Go?
First convert the string to int64 with strconv.ParseInt(), then pass it to time.Unix().
seconds, err := strconv.ParseInt("1405544146", 10, 64)
t := time.Unix(seconds, 0)
What is the difference between time.Unix() and time.UnixMilli()?
time.Unix()expects seconds.time.UnixMilli()expects milliseconds.
Use the one that matches your input data.
Why does the printed time look different from what I expected?
Go may print the time in your local time zone. Try using .UTC() to see the timestamp in UTC.
Mini Project
Description
Build a small Go program that reads Unix timestamps from strings, converts them into time.Time, and prints both local time and UTC time. This demonstrates the full workflow you will often use in APIs, scripts, or data import tools.
Goal
Create a program that safely converts string-based Unix timestamps into readable Go time.Time values.
Requirements
- Accept at least three timestamp strings in a slice.
- Convert each string to an integer using proper error handling.
- Convert valid timestamps to
time.Timeusingtime.Unix(). - Print both the local time and UTC version for each valid timestamp.
- Skip invalid values without crashing the whole program.
Keep learning
Related questions
Automatic Build Versioning in Go: Embed Incrementing Build Numbers
Learn how to add automatic build versioning in Go using linker flags, build metadata, CI counters, and Git-based version values.
Blank Identifier Imports in Go: What `_` Means in an Import Statement
Learn what `_` means in a Go import, why blank identifier imports run package init code, and when to use them safely.
Calling Functions Across Files in the Same Go Package
Learn how Go uses packages across multiple files, why functions may appear undefined, and how to organize code correctly.