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
echo $(( ($(date -d "2026-05-17" +%s) - $(date -d "2026-04-01" +%s)) / 86400 )) daysGNU `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).
echo $(( ($(date -d "2026-05-17" +%s) - $(date -d "2026-04-01" +%s)) / 86400 )) daysmath (date -d "2026-05-17" +%s) - (date -d "2026-04-01" +%s) / 86400(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.
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
- Get the day of the week for a date— Print which weekday a given date falls on — for backup-window scripts ("only run on Sunday"), log rotation, conditional CI gates ("skip the weekly job on Friday"), or `cron` replacements that need day-of-week introspection.
- Get the ISO week number of the year— Print which calendar week a date falls into — for sprint planning ("we are in W20"), retention dashboards (weekly bucketing), payroll periods, and any time-series workflow that wants "year-week" as a stable key.
- Parse a relative date like "next Friday" or "2 weeks ago"— Convert a human-readable relative-time expression ("3 days ago", "next Monday", "last quarter end") into an absolute date — for log filters, backfill ranges, scheduling, or any script that wants to accept user input the same way GitHub Actions cron does.
- Convert a timestamp between timezones— Take a date / time in one timezone and print its equivalent in another — for "what time is the 3pm Tokyo meeting in New York?", server-log normalization, and any cross-region scheduling task.