package main import ( "fmt" "time" "node-lookup/internal/puppet" ) // formatWhen renders the "last report" column for a node lookup result. It // handles the lookup error, the unknown-node, and the never-reported cases so // the output always has a value in every column. func formatWhen(node *puppet.Node, lookupErr error, relative bool, loc *time.Location, now time.Time) string { if lookupErr != nil { return "error: " + lookupErr.Error() } if node == nil { return "unknown node" } if node.ReportTimestamp == "" { return "no report" } ts, err := time.Parse(time.RFC3339Nano, node.ReportTimestamp) if err != nil { return node.ReportTimestamp // fall back to the raw value } if relative { return humanizeSince(now, ts) } return ts.In(loc).Format("2006-01-02 15:04:05 MST") } // humanizeSince renders the gap between now and ts as a coarse relative string // ("42s ago", "9m ago", "3h ago", "5d ago"). Future timestamps (clock skew) // render as "in ". func humanizeSince(now, ts time.Time) string { d := now.Sub(ts) suffix := "ago" if d < 0 { d = -d suffix = "from now" } switch { case d < time.Minute: return fmt.Sprintf("%ds %s", int(d.Seconds()), suffix) case d < time.Hour: return fmt.Sprintf("%dm %s", int(d.Minutes()), suffix) case d < 24*time.Hour: return fmt.Sprintf("%dh %s", int(d.Hours()), suffix) default: return fmt.Sprintf("%dd %s", int(d.Hours()/24), suffix) } }