Timestamp Converter — Go source
Convert Unix epoch timestamps to human-readable dates and back. See seconds, milliseconds, ISO 8601, UTC, local and relative time at once.
This is the Go implementation — the same logic the interactive tool runs, in a shareable, citable form.
// Unix epoch (seconds & milliseconds) <-> human forms: ISO 8601, UTC
// string, local date string, and relative time ("3 hr ago" / "in 2 day").
//
// Language: Go
// CosmoDev polyglot showcase port of the `timestamp` tool.
// Ported from src/tools/TimestampConverter.tsx — display source, part of
// CosmoDev's polyglot tool pages.
//
// Every form derives from a single epoch-seconds value via the standard
// time package. relativeTime() buckets |now - t| into sec/min/hr/day/
// month/yr using the same 60s / 60m / 24h / 30d / 365d thresholds and
// signs the phrase. JS toUTCString emits "GMT" for the zone; Go's
// RFC1123Z yields "+0000", which we swap to "GMT" for byte-parity.
package main
import (
"fmt"
"strconv"
"strings"
"time"
)
const invalid = "—"
// relParts is the (count, unit) pair every language computes identically.
type relParts struct {
n int64
unit string
}
// relativeBuckets maps an absolute millisecond distance to its bucket.
// Exported as the headline pure transform so tests can pin each edge.
func relativeBuckets(absMs int64) relParts {
const (
minMs = 60_000
hrMs = 3_600_000
dayMs = 86_400_000
monMs = dayMs * 30
yearMs = dayMs * 365
)
switch {
case absMs < minMs:
return relParts{(absMs + 500) / 1000, "sec"}
case absMs < hrMs:
return relParts{(absMs + minMs/2) / minMs, "min"}
case absMs < dayMs:
return relParts{(absMs + hrMs/2) / hrMs, "hr"}
case absMs < monMs:
return relParts{(absMs + dayMs/2) / dayMs, "day"}
case absMs < yearMs:
return relParts{(absMs + monMs/2) / monMs, "month"}
default:
return relParts{(absMs + yearMs/2) / yearMs, "yr"}
}
}
// RelativeTime returns "3 hr ago" / "in 2 day" etc., mirroring the island.
// nowMs is a parameter so the result is deterministic and testable.
func RelativeTime(ms, nowMs int64) string {
diff := ms - nowMs
abs := diff
if abs < 0 {
abs = -abs
}
p := relativeBuckets(abs)
s := fmt.Sprintf("%d %s", p.n, p.unit)
if diff < 0 {
return s + " ago"
}
return "in " + s
}
// FormatTimestamp renders every form the tool exposes from epoch seconds.
// Invalid instants render an em dash, matching the live UI.
func FormatTimestamp(secs int64, nowMs int64) map[string]string {
t := time.Unix(secs, 0)
utc := t.UTC()
// "Z07:00" prints "Z" for UTC; ".000" matches Date.toISOString ms.
iso := utc.Format("2006-01-02T15:04:05.000Z07:00")
// RFC1123Z gives "Wed, 14 Jun 2017 07:00:00 +0000"; JS gives "… GMT".
utcStr := strings.Replace(utc.Format(time.RFC1123Z), "+0000", "GMT", 1)
// toLocaleString is locale-dependent; this is the local-zone form.
local := t.Format("2006-01-02 15:04:05 MST")
return map[string]string{
"Epoch (s)": strconv.FormatInt(secs, 10),
"Epoch (ms)": strconv.FormatInt(secs*1000, 10),
"ISO 8601": iso,
"UTC": utcStr,
"Local": local,
"Relative": RelativeTime(secs*1000, nowMs),
}
}
// FromISO parses an ISO 8601 / datetime-local ("YYYY-MM-DDTHH:mm") string
// into epoch seconds in the host's local zone — the same path the island's
// datetime-local input takes. Returns ok=false for unparseable input.
func FromISO(iso string) (secs int64, ok bool) {
layouts := []string{
"2006-01-02T15:04:05",
"2006-01-02T15:04",
time.RFC3339,
"2006-01-02 15:04:05",
}
for _, l := range layouts {
if t, err := time.ParseInLocation(l, iso, time.Local); err == nil {
return t.Unix(), true
}
}
return 0, false
}
func main() {
now := time.Now().UnixMilli()
for k, v := range FormatTimestamp(time.Now().Unix(), now) {
fmt.Printf("%-10s %s\n", k+":", v)
}
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →