Skip to content
shellmap

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.

How to convert a timestamp between timezones in each shell

Bashunix
TZ=Asia/Tokyo date -d "2026-05-17 15:00 America/New_York"

`TZ=NAME COMMAND` shifts JUST that command's timezone — the env var is one-shot, your shell's timezone is unchanged. Combined with `date -d "STAMP TZ"` (GNU parses the trailing TZ name and treats input as that zone), you get a clean "input in NYC, output in Tokyo" pipe. IANA timezone names like `Asia/Tokyo`, `America/New_York`, `Europe/London`, `UTC` — see `timedatectl list-timezones` or `ls /usr/share/zoneinfo/`.

Zshunix
TZ=Asia/Tokyo date -d "2026-05-17 15:00 America/New_York"
Fishunix
env TZ=Asia/Tokyo date -d "2026-05-17 15:00 America/New_York"

Fish does NOT honour `VAR=value command` inline assignment — must use `env VAR=value command` or `set -lx TZ Asia/Tokyo; date ...; set -e TZ`. This is a common bash → fish porting trip-up.

PowerShellwindows
[TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date "2026-05-17 15:00"), "Eastern Standard Time", "Tokyo Standard Time")

pwsh 7+ accepts both Windows zone IDs (`"Eastern Standard Time"`) AND IANA names (`"America/New_York"`) on Linux/macOS — but on Windows pwsh, only Windows IDs work unless tzdata is installed. `[TimeZoneInfo]::FindSystemTimeZoneById("America/New_York")` throws on stock Windows. For cross-platform scripts: pin to IANA on Linux/macOS, Windows IDs on Windows, OR use the .NET 8 `TimeZoneInfo.TryConvertIanaIdToWindowsId()` bridge (pwsh 7.4+).

cmd.exewindows
powershell -NoProfile -Command "[TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date '2026-05-17 15:00'), 'Eastern Standard Time', 'Tokyo Standard Time')"

cmd `tzutil /g` shows the current system timezone; `tzutil /l` lists all available Windows timezone IDs. cmd has no native conversion verb — shelling to pwsh is standard. `w32tm /tz` returns current TZ in a different format (used for time-sync diagnostics).

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

Gotchas & notes

  • **IANA names vs Windows IDs — the #1 cross-platform timezone trap**. IANA (also called "tz database" or "zoneinfo") uses location-based names: `America/New_York`, `Europe/Paris`, `Asia/Tokyo`. Windows uses "display IDs": `Eastern Standard Time` (covers BOTH EST and EDT despite the misleading name), `Romance Standard Time` (France/Spain/Belgium), `Tokyo Standard Time`. They are NOT one-to-one — Windows has ~140 zones, IANA has ~600 (IANA splits when a region's history diverges, e.g. `America/Indiana/Indianapolis` vs `America/Indiana/Vincennes` for the Indiana counties that ran on different offsets). For cross-platform pipelines, IANA is the standard. Windows 10 1809+ optionally accepts IANA names if `Microsoft.Windows.TZData` package is installed; pwsh 7 on Linux/macOS speaks IANA natively. Conversion tables: `[TimeZoneInfo]::TryConvertIanaIdToWindowsId()` (pwsh 7.4+ / .NET 8+), or `windowsZones.xml` from CLDR.
  • **Daylight saving — "EST" is not "EDT" and the name lies**. `Eastern Standard Time` on Windows is actually "the zone of NYC", which means it AUTOMATICALLY switches between EST (UTC-5) in winter and EDT (UTC-4) in summer — the name is historical and misleading. Same trap: `Pacific Standard Time` ≡ `America/Los_Angeles` (auto DST), `Romance Standard Time` ≡ `Europe/Paris` (auto DST). For ALWAYS-STANDARD-TIME (no DST): there is no Windows ID; on IANA use `Etc/GMT+5` (note the SIGN IS FLIPPED — `Etc/GMT+5` means UTC-5, per POSIX historical convention). For UTC always: `UTC` IANA or `UTC` Windows. NEVER hardcode an offset (`+0500`) for a region that observes DST — your script will be one hour off for half the year.
  • **System-wide vs per-command timezone change**: `TZ=Asia/Tokyo date` shifts ONLY that command. To shift your whole shell session: `export TZ=Asia/Tokyo` (lasts until logout). To shift the SYSTEM permanently: `sudo timedatectl set-timezone Asia/Tokyo` (Linux systemd), `sudo systemsetup -settimezone Asia/Tokyo` (macOS), `tzutil /s "Tokyo Standard Time"` (Windows). The SHELL-level shift is what scripts want — never modify system TZ unless you're intentionally redating the host. `timedatectl list-timezones | grep -i tokyo` to discover the right IANA name; `tzutil /l | findstr /i tokyo` on Windows for the matching Windows ID.
  • **Logging in UTC, displaying in local — the production pattern**: store / log timestamps in UTC (ISO 8601 with `Z` suffix: `2026-05-17T15:00:00Z`), convert at PRESENTATION time only. This avoids DST gaps (the 23-hour day each spring) and timezone surprises across replicated regions. systemd journal records in UTC by default; can display in local with `journalctl --output-fields=... --utc` or `TZ=Asia/Tokyo journalctl`. PostgreSQL: `TIMESTAMPTZ` stores UTC, applies `SESSION TIMEZONE` on display. The anti-pattern: `Asia/Tokyo` displayed-string stored as `VARCHAR` in a DB, then parsed back without TZ — irreversible information loss as soon as the user's session TZ differs.
  • **Half-hour, 45-minute, and rolled-back zones — "all timezones are integer offsets" is a myth**. India: UTC+5:30 (one of several `:30` zones), Nepal: UTC+5:45 (a `:45`!), Newfoundland: UTC-3:30 (StA). Iran: UTC+3:30 in winter, +4:30 in summer. Lord Howe Island, Australia: UTC+10:30 in winter, +11 (full hour shift on DST!). North Korea reverted from UTC+8:30 back to UTC+9 in 2018 — meaning `date -d "2017-04-01 00:00 Asia/Pyongyang"` and `date -d "2019-04-01 00:00 Asia/Pyongyang"` produce different absolute UTC times despite the same local clock reading. ALWAYS use IANA tzdata, NEVER hardcode `(offset + 3600)` — the tzdata package gets updated continuously (last 12 months: Lebanon, Greenland, Mexico all had changes) and your scripts inherit the fixes if you stay on `Asia/Pyongyang` strings.

Related commands

Related tasks