Skip to content
shellmap

Calculate days between two dates

Compute the integer number of days between two calendar dates — for SLA timers, log-window queries, license-expiry math, or backfill scripts that ask "how many days have passed since X?".

How to calculate days between two dates in each shell

Bashunix
echo $(( ($(date -d "2026-05-17" +%s) - $(date -d "2026-04-01" +%s)) / 86400 )) days

GNU `date -d "STRING" +%s` parses almost any human-readable date to a Unix epoch (seconds since 1970-01-01 UTC). Subtract two epochs, divide by 86400 (seconds-per-day). The `+%s` format is the portable trick — `date -d` itself is GNU-only, so this exact form works on Linux but FAILS on macOS / BSD (see the macOS-portable form below).

Zshunix
echo $(( ($(date -d "2026-05-17" +%s) - $(date -d "2026-04-01" +%s)) / 86400 )) days
Fishunix
math (date -d "2026-05-17" +%s) - (date -d "2026-04-01" +%s) / 86400
PowerShellwindows
(New-TimeSpan -Start "2026-04-01" -End "2026-05-17").Days

`New-TimeSpan` returns a `[TimeSpan]` object — `.Days` is the day component (integer), `.TotalDays` is the floating-point total (`46.5` for 46 days 12 hours). Use `.TotalDays` and cast to `[int]` if you want truncation-not-rounding. pwsh date parsing is culture-aware — `"04/01/2026"` is April-1 in US English but January-4 in many EU locales; ISO 8601 (`"2026-04-01"`) is unambiguous.

cmd.exewindows
powershell -NoProfile -Command "(New-TimeSpan -Start '2026-04-01' -End '2026-05-17').Days"

cmd has no native date-arithmetic verb. Shelling out to `powershell -NoProfile` is the practical answer — adding `-NoProfile` skips user/system profile loading (~3x faster cold start). Pure-cmd date math via parsing `%DATE%` token requires locale-specific format-string juggling (US `Sat 05/17/2026` vs UK `Sat 17/05/2026`) — error-prone and almost never the right tool.

Equivalents listed for Bash, Zsh, Fish, PowerShell, cmd.exe.

Gotchas & notes

  • **`date -d` is GNU-only — the #1 cross-platform portability trap**. macOS / FreeBSD / OpenBSD ship the BSD `date` which uses `-j -f INPUT_FMT INPUT +OUTPUT_FMT`: `date -j -f "%Y-%m-%d" "2026-05-17" +%s`. `-j` says "don't actually SET the system clock — just parse" (without `-j`, macOS `date` would interpret your input as a SET command and need root). The portable bash idiom uses a conditional: `if date --version >/dev/null 2>&1; then EPOCH=$(date -d "$DATE" +%s); else EPOCH=$(date -j -f "%Y-%m-%d" "$DATE" +%s); fi`. For scripts shipping to both, prefer Python: `python3 -c "from datetime import date; print((date(2026,5,17) - date(2026,4,1)).days)"` works identically everywhere Python 3 is installed.
  • **Leap seconds + DST + timezone math — the silent off-by-one factory**. Naive subtraction of epoch seconds divided by 86400 IGNORES leap seconds (10 of them since 1972, last one 2017) and DST transitions (spring-forward = 23-hour day in that zone, fall-back = 25-hour day). For calendar-DAY math (what most users want) this is fine — leap seconds shift "now" by < 30 sec total, well below day granularity. For HOUR-precise duration math across DST: parse both dates with timezone awareness and let the library handle it. pwsh `New-TimeSpan` does this correctly out of the box; bash epoch math does NOT — `date -d "2026-03-13 03:00 America/New_York"` minus `date -d "2026-03-12 03:00 America/New_York"` gives 82800 sec (23 hours, the spring-forward day) instead of 86400.
  • **Including-vs-excluding endpoints — "from Monday to Friday is how many days?"**: epoch subtraction `(Fri_epoch - Mon_epoch)/86400 = 4` — that's the standard "duration in days". But colloquially "Monday to Friday" can mean 5 (count both endpoints, like "the conference is Mon to Fri"). When precision matters in scripts, ADD ONE explicitly for inclusive counts: `((end - start) / 86400 + 1)`. Same for hourly logs: querying `--since "5 days ago"` returns about 5×24 hours of records — whether yesterday's log makes the cut depends on the exact second-of-day.
  • **Negative results and ordering — `(earlier - later)` returns negative**: GNU bash arithmetic `$(( ... ))` handles negative just fine; pwsh `New-TimeSpan -Start later -End earlier` returns negative `.Days` (`-46`). For "absolute days regardless of order": bash `abs=$(( a > b ? a-b : b-a ))`; pwsh `[Math]::Abs((New-TimeSpan ...).Days)`. Often the right pattern is just `sort` the two dates first: `read FIRST SECOND < <(printf "%s\n%s\n" "$A" "$B" | sort) && echo $(( $(date -d "$SECOND" +%s) - $(date -d "$FIRST" +%s) )) / 86400`. Or for ISO 8601 dates specifically: lexicographic sort works (`2026-04-01` < `2026-05-17` as strings).
  • **Business-day count (skip weekends/holidays) is fundamentally different math** — calendar-day subtraction can't express it directly. Quick-and-dirty: `python3 -c "import pandas; print(len(pandas.bdate_range('2026-04-01', '2026-05-17')))"` (pandas business-day range, exclusive of weekends). Without pandas: AWK loop calling `date -d "...+ $i days" +%u` (1=Mon..7=Sun) and counting those with `<6`. pwsh: `(0..(((Get-Date "2026-05-17") - (Get-Date "2026-04-01")).Days) | %% { (Get-Date "2026-04-01").AddDays($_).DayOfWeek } | ? { $_ -lt "Saturday" }).Count`. For holiday-aware: pull a holiday calendar (Python `holidays` package, JS `date-holidays`) — DIY date math gets very fiddly very fast.

Related commands

Related tasks