Project

tztr

0.0
The project is in a healthy, maintained state
Convert timestamps between timezones. Reads from stdin or file, auto-detects timestamp formats, and preserves the original format by default.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

 Project Readme

tztr

Gem codecov

Timezone Translator - convert timestamps to local time.

Reads from stdin or file, auto-detects timestamp formats, and preserves the original format by default.

Install

brew install dpep/tools/tztr

Usage

echo '2026-04-03T12:00:00Z' | tztr -t America/Los_Angeles
# 2026-04-03T05:00:00-07:00

echo '15:30 UTC' | tztr -t America/New_York
# 11:30 EDT

tail -f app.log | tztr

Options

-f, --from TZ       Input timezone (default: auto-detect)
-t, --to TZ         Output timezone (default: $TZ, else UTC)
-F, --format FMT    Output format: iso, short, time (default: preserve input)
-d, --date DATE     Reference date for time-only inputs (resolves DST)
-l, --list          List timezone aliases
-i, --in-place      Edit file in place
-j, --json          Emit a JSON array of matches
-J, --ndjson        Emit newline-delimited JSON (one object per match)
    --detect        Report detected format/zone without converting
-v, --verbose       Print diagnostics to stderr
-V, --version       Show version
-h, --help          Show this help

Supported Formats

  • ISO 8601: 2026-04-03T12:00:00Z, 2026-04-03T12:00:00+05:30
  • Date + time: 2026-04-03 12:00:00 UTC
  • Time only: 15:30 UTC, 08:30:45 PDT
  • Fractional seconds: 2026-04-03T12:00:00.123Z

JSON output (for agents & scripts)

-j/--json emits a JSON array; -J/--ndjson emits one object per line, which streams (works with tail -f). Each match is an object:

echo 'meeting at 15:30 UTC' | tztr -t pst -j
# [
#   {
#     "original": "15:30 UTC",
#     "detected_format": "time",
#     "detected_tz": "UTC",
#     "translated": "08:30 PDT"
#   }
# ]

--detect reports what was found without translating (omits translated), and composes with -j/-J:

echo '2026-04-03T12:00:00Z' | tztr --detect -j
# [ { "original": "...", "detected_format": "iso", "detected_tz": "Z" } ]

Combine -h with -j/-J to get the help itself as JSON — the full option schema (flags, args, descriptions, examples), so an agent can read it instead of scraping the text:

tztr -h -j
# { "name": "tztr", "version": "...", "options": [ { "short": "-f", "long": "--from", ... } ], ... }

Environment

Set TZ to change the default timezone for input and output (overridden by -f / -t):

export TZ=America/Los_Angeles
echo '2026-04-03T12:00:00Z' | tztr
# 2026-04-03T05:00:00-07:00

Caveat: time-only inputs and DST

A time-only input carries no date, so a DST-observing zone can't tell whether it was standard or daylight time. When you pair a bare time with a named source zone, tztr resolves it against today's date — which can be off by an hour for a timestamp from the other side of a DST boundary:

echo '15:30' | tztr -f pacific -t utc
# 22:30 UTC   (today is summer, so pacific -> PDT, UTC-7)

Two ways to handle it:

# Supply the date the time belongs to (accepts flexible formats):
echo '15:30' | tztr -f pacific -t utc -d 2026-01-15
# 23:30 UTC   (January -> PST, UTC-8)
echo '15:30' | tztr -f pacific -t utc -d 'January 15, 2026'

# Or sidestep DST entirely with a fixed numeric offset instead of a named zone:
echo '15:30' | tztr -f -8 -t utc
# 23:30 UTC   (-8 -> Etc/GMT+8, never observes daylight time)

Inputs that already carry a date (2026-04-03 15:30) or a fixed offset are unaffected.

Library

tztr is also published as a Ruby gem and a Rust crate:

gem install tztr      # Ruby
cargo install tztr    # Rust

Use it from Ruby:

require "tztr"

Tztr.translate("log 2026-04-03T12:00:00Z event", to: "America/Los_Angeles")
# => "log 2026-04-03T05:00:00-07:00 event"

It ships two implementations kept functionally identical: the Ruby gem (reference) and a Rust crate — Homebrew installs the Rust binary. Same CLI, output, and behavior; see rust/REPORT.md for port notes and a perf comparison.