Get how long a process has been running
Find the wall-clock age of a process — how long ago it started — for debugging stuck daemons, validating a recent restart, or pinning a leak to "this process has been up for 47 days".
How to get how long a process has been running in each shell
ps -o etime= -p 12345`-o etime=` outputs ELAPSED time in `[[DD-]hh:]mm:ss` format (trailing `=` suppresses the header). Example: `47-13:22:08` = 47 days 13h 22m 8s. For RAW SECONDS (easier to script): `ps -o etimes= -p 12345` (note the trailing `s`) — Linux-only. macOS BSD `ps` has `etime` but not `etimes`; compute seconds with `date +%s -d "$(ps -o lstart= -p 12345)"` differential math.
ps -o etime= -p 12345ps -o etime= -p 12345(New-TimeSpan -Start (Get-Process -Id 12345).StartTime).ToString()`(Get-Process -Id PID).StartTime` returns a `[datetime]` (when the process STARTED), NOT a duration. Compute the elapsed `TimeSpan` with `New-TimeSpan -Start $proc.StartTime` (defaults `-End` to now). Format: `.ToString("dd\.hh\:mm\:ss")` or `.TotalSeconds` for raw seconds. SYSTEM and idle processes return `$null` StartTime — null-check before subtracting.
wmic process where ProcessId=12345 get CreationDate`CreationDate` is in WMI datetime format `YYYYMMDDHHMMSS.ffffff+TZN` — opaque. Parse: `for /f "tokens=2 delims==" %A in ('wmic process where ProcessId^=12345 get CreationDate /value') do @echo %A`. Practically: shell to pwsh `(New-TimeSpan -Start (Get-Process -Id 12345).StartTime)` for the formatted answer; `wmic` is deprecated since Win10 21H1 anyway.
Equivalents listed for Bash, Zsh, Fish, PowerShell, cmd.exe.
Gotchas & notes
- **`etime` HH:MM:SS vs `etimes` raw seconds — pick the right one for the job**: humans want `etime` (`02-04:13:22` is "2 days 4 hours…"), scripts want `etimes` (raw seconds — directly comparable, no parsing). For uptime ALERTS (`alert if etime > 7 days`): `[[ $(ps -o etimes= -p $PID) -gt 604800 ]]` — clean integer compare, no string parsing. For HUMAN-FACING display in a status dashboard: `etime` prints natively. `etimes` is GNU ps (Linux) only — macOS/BSD does not have it. Portable fallback: parse `etime` field with `awk -F: '{ s = $NF; m = $(NF-1); …}'` (ugly), or shell out to `python -c "import psutil; print(time.time() - psutil.Process(pid).create_time())"`.
- **Linux `/proc/PID/stat` field 22 is `starttime` in JIFFIES SINCE BOOT** — not a Unix timestamp. Conversion: `start_unix = boot_time + starttime / HZ` where `HZ` is `getconf CLK_TCK` (almost always 100 on Linux). Boot time: `cat /proc/stat | grep btime` (Unix epoch). Practical script: `awk 'NR==1{btime=$1}' /proc/stat | … cat /proc/$PID/stat | awk '{print $22}'` then `(starttime / 100) + btime`. `ps` does this conversion for you — only reach for `/proc` directly when `ps` is missing (busybox-stripped containers, forensic images). macOS has no `/proc`; everything goes through `ps` or `sysctl kern.proc.pid.PID` (binary).
- **Container uptime ≠ host uptime**: inside a Docker container, `ps -o etime` for PID 1 returns the elapsed time SINCE THE CONTAINER STARTED, not since the host booted. This is correct (container PID namespace), but trips people up — "the host has been up 200 days but my process says 4h" is not a bug; it's a restart of the container 4h ago. For container-level "when did THIS pod last restart": Kubernetes shows `kubectl get pod -o jsonpath='{.status.containerStatuses[0].state.running.startedAt}'` (Kubernetes-level timestamp, distinct from in-container `ps`). For Docker: `docker inspect --format '{{.State.StartedAt}}' CONTAINER`.
- **pwsh `StartTime` vs `StartInfo.StartTime` vs WMI `CreationDate`** — three timestamps for the same fact. `(Get-Process -Id PID).StartTime` is the standard answer (works pwsh 5.1+ Windows, pwsh 7+ cross-platform). For PID 0 (System Idle Process) and PID 4 (System) on Windows, `StartTime` throws "Access is denied" (kernel-owned) — wrap in try/catch. For *all* processes including the protected ones: `Get-CimInstance Win32_Process | Select ProcessId, CreationDate` — CIM uses WMI permissions which see more. The pwsh-friendly `[Management.ManagementDateTimeConverter]::ToDateTime($cim.CreationDate)` parses the WMI string back to a `[datetime]`.
- **Why "uptime of a process" matters for debugging**: long uptime can correlate with memory bloat (leaks compound), file-descriptor exhaustion (cumulative open()s without close()), TLS-certificate expiry (cert was valid at process start but expired since — common in long-lived API workers). Conversely, a process you EXPECT to be days old reporting "uptime 4 minutes" means it crash-restarted (check the supervisor log: `systemctl status` / `journalctl -u UNIT`). Pair `etime` with `Restart=on-failure` reporting: a process that's been up "47 seconds" 4 hours after deploy is probably crash-looping. Production runbooks should automate this pair: alert on (uptime < 5min AND age-since-deploy > 30min).
Related commands
Related tasks
- Find a process ID by name— Look up the PID(s) of a running process given its executable name — the lookup that precedes most kill / signal / inspect operations.
- Count the running processes— Report how many processes are alive — useful for load testing, capacity baselining, or detecting fork-bomb / runaway-parallelism conditions.
- Monitor CPU and memory live— Watch CPU and memory utilisation continuously from a shell — for triage, capacity planning, and detecting transient spikes that a one-shot ps would miss.
- Wait for a process to finish— Block until a given process exits — useful for sequencing, dependency-management scripts, and orchestrated shutdowns.