A colorful TUI world clock with an interactive 24-hour timeline, fuzzy timezone search, and in-app zone management. Built with Bubble Tea and Lip Gloss in Go.
See at a glance who's asleep, who's at lunch, and who's about to log off — without doing the math. Designed for remote teams, distributed engineering, on-call rotations, and anyone who lives across timezones.
Keywords: world clock, timezone, time zone, TUI, terminal UI, CLI, remote work, distributed teams, cross-timezone, Bubble Tea, Lip Gloss, Go, golang, IANA, tzdata.
- Designed for the terminal — no Electron, no browser, ~5 MB single binary. Launches in milliseconds.
- Visual at a glance — color-coded hour bands let you parse "is 9am in Tokyo a good time to ping?" in one second.
- Searchable — fuzzy-find timezones by country (
china), city (shanghai), code (jp), or IANA path. - No mouse needed — fully keyboard-driven, vim-style bindings.
- Themeable — every hour band's foreground/background is a hex color in your config.
- 24-hour color-coded timeline per timezone, themed by hour bands (night / morning / midday / afternoon / early-evening / evening / late-evening).
- Time-travel cursor —
←/→to scrub by hour,Shift+←/→for ±24h. Wall-clock "now" stays highlighted in amber regardless of where the cursor is. - Fuzzy search (
/) — filter zones by alias; home and pinned zones always remain visible. - In-app add / remove / reorder / rename of zones. The add flow autocompletes against the full IANA database (~418 zones) by country, city, or path.
- Synthetic "Local" row when your system timezone differs from your home zone, so you always know what time it is for you.
- Pin / unpin zones to keep them visible during search.
- Toggleable columns: IANA path, friendly name ("Pacific", "Eastern", "Israel"…), short abbreviation ("PDT", "EDT", "IDT"…).
- Clipboard copy of the focused time.
- Persistent state — pins, column toggles, and aliases survive restarts.
Requires Go 1.23+.
git clone https://github.com/udiNur/tzy.git
cd tzy
make installThis builds ./tzy, symlinks /opt/homebrew/bin/tz → ./tzy, and seeds ~/.config/tzy/config.toml with the example config. From any shell:
tzBecause it's a symlink, every go build (or make build) in the project directory immediately updates the system-wide tz command — no re-install step needed.
make install PREFIX=/usr/local # symlinks /usr/local/bin/tz
make install PREFIX="$HOME/.local" # symlinks ~/.local/bin/tzmake uninstall # removes the symlink; your config is left at ~/.config/tzy/go build -o tzy .
./tzy --config config.tomltz # launches with config from --config / ./config.toml / $XDG_CONFIG_HOME/tzy/ / ~/.config/tzy/
tz --config path.toml # override config path
| Keys | Action |
|---|---|
← → / h l |
Move cursor ±1 hour |
Shift+← Shift+→ / H L |
Move cursor ±24 hours |
t / 0 |
Jump cursor back to current hour |
c / Enter |
Copy focused time to clipboard |
↑ ↓ / j k |
Select row |
K J (shift+k / shift+j) |
Move selected zone up / down |
p |
Pin / unpin selected zone |
e |
Edit alias of selected zone |
a |
Add new zone (with country/city autocomplete) |
d |
Delete selected zone (asks y/n) |
/ |
Fuzzy-search by alias |
n |
Toggle IANA path column |
N (shift+n) |
Toggle friendly-name column |
Ctrl+N |
Toggle short-abbreviation portion of the name column |
q / Esc / Ctrl+C |
Quit (esc clears active filter first) |
Press a, then type freely — the catalog searches across country name, country code (e.g. jp), IANA city, and full path. Use ↑/↓ to highlight a suggestion, Enter to commit.
tzy reads a TOML config from (in order): --config <path>, ./config.toml, $XDG_CONFIG_HOME/tzy/config.toml, ~/.config/tzy/config.toml.
# Your zones. First entry is "home" (★) — by convention your primary timezone.
[[timezones]]
tz = "Asia/Jerusalem"
alias = "Jerusalem"
[[timezones]]
tz = "America/New_York"
alias = "New York"
[[timezones]]
tz = "Europe/Lisbon"
alias = "Lisbon"
# Color bands. Each block covers [start_hour, end_hour); first match wins.
[[blocks]]
name = "night"
start_hour = 0
end_hour = 8
bg = "#1E1E1E"
fg = "#A9A9A9"
[[blocks]]
name = "morning"
start_hour = 8
end_hour = 11
bg = "#1B5E20"
fg = "#FFFFFF"
[[blocks]]
name = "midday"
start_hour = 11
end_hour = 15
bg = "#2E7D32"
fg = "#FFFFFF"
[[blocks]]
name = "evening"
start_hour = 18
end_hour = 22
bg = "#1565C0"
fg = "#E0E0E0"Any change you make through the TUI (a/d/K/J/e) writes back to this file via atomic temp-file rename. Comments and original formatting are not preserved on rewrite.
Pin list, column-toggle preferences, and similar UI state live separately in ~/.config/tzy/state.toml (or $XDG_CONFIG_HOME/tzy/state.toml). You usually don't need to edit this by hand.
- Home is positional: it's always the first entry in your
[[timezones]]list, marked with ★. If you reorder, the new first entry becomes home. - Local is detected from
$TZand/etc/localtime. If your system zone differs from home, a syntheticL Local · <City>row is prepended automatically. It's not in your config — it disappears if you set your system zone to match home.
make build # go build -o tzy .
make run # build + run
go vet ./...
go test ./...Architecture notes for contributors are in CLAUDE.md.
MIT.

