Skip to main content

terrahour

tests

A world clock for the terminal, with a map that shows where it is daytime and a 24-hour timeline that shows when your cities are at work.

Main view: the day and night map above a timeline per city
terrahour main view
A quick tour: scrubbing time, exchanges, DST radar, ambient view
demo

What it does

  • Map with day and night. The world is drawn in braille dots, shaded by sunlight, and coloured by time zone. Every city you track gets a marker. Zoom with + - or the mouse wheel, drag to pan.
  • A timeline per city. Each row is a 24-hour bar with the working hours lit up. The overlap row at the bottom shows the window when everybody is at their desk.
  • Scrub through time. Arrow keys move in 15-minute steps, g jumps to any time ("15:30", "3pm", "+2h", "2026-10-05 09:00"), r snaps back to live.
  • DST radar. D lists the next clock change for every city and, more usefully, whether the gap between you and them is about to shift by an hour.
  • Stock exchanges. M swaps the city list for the ten biggest exchanges with their real trading sessions, lunch breaks included.
  • Alerts. A sets a daily reminder in another city's time, a ping when an office or exchange opens or closes, or a plain timer. They ring the bell and send a desktop notification while the app is open.
  • Weather, if you want it. W shows the current temperature next to each city (Open-Meteo, needs network, off by default).
  • Ambient view. V turns the whole terminal into a big clock over the map that cycles through your cities. Nice on a spare monitor.
  • Fits anywhere. Below about 76 columns it switches to a compact layout that works in a tmux split. --line prints a one-liner for a status bar.
  • Six themes (midnight, nord, dracula, light, mono, colorblind), 12 or 24 hour clock, mouse support, and about 6,000 cities built in with online lookup for the rest.
Exchanges Compact layout for a tmux split
markets view compact view
DST radar Adding a city
DST radar add city
Ambient view Light theme
ambient view light theme

Install

You need Python 3.9 or newer, a terminal with truecolor support (almost all of them these days) and a UTF-8 locale. Developed on Linux. macOS is covered by the automated tests, but I have not tried it by hand. On Windows use WSL, the app relies on a Unix terminal.

pipx install git+https://github.com/ACoci86/terrahour

Then run terrahour. If your shell cannot find the command, run pipx ensurepath once and open a new terminal.

or, without pipx, in a virtual environment (recent Debian and Ubuntu refuse a plain pip install outside one):

python3 -m venv .venv && . .venv/bin/activate
pip install git+https://github.com/ACoci86/terrahour
terrahour

The command is available whenever that environment is active.

or just clone it and run it in place, there is nothing to build:

git clone https://github.com/ACoci86/terrahour
cd terrahour
python -m terrahour

Usage

terrahour                                  # your saved cities (a sensible default set the first time)
terrahour Europe/Berlin "Home=America/Chicago" Naples   # a one-off set of zones or city names, not saved
terrahour --markets                        # start in the exchange view
terrahour --at 2026-10-05T09:00Z           # start frozen at a given time
terrahour --theme nord --12h
terrahour --ambient                        # straight into the screensaver view
terrahour --reset                          # forget saved cities and settings

Press ? inside the app for the full list of keys. The ones you will use most:

Key Action
← → scrub 15 minutes (Shift: 1 hour, PgUp/PgDn: 1 day)
g go to a time, r back to live
↑ ↓ j k select a city, Shift moves it up or down the list
a d add or remove a city
* mark the selected city as home (offsets are then relative to it)
Enter focus the selected city, dims the others
M D A W exchanges, DST radar, alerts, weather
+ - [ ] 0 zoom the map, zoom the timeline, reset
T t c V theme, 12/24h, compact layout, ambient view
q quit

Everything you change in the app (cities, theme, home, working hours, alerts) is saved to ~/.config/terrahour/config.json. Zones given on the command line are session-only and leave that file alone.

Status bars and scripts

$ terrahour --line
SF 07:30 · NY 10:30 · LON 14:30 · UTC 14:30 · DUB 18:30 · MUM 20:00 · SIN 22:30 · TOK 23:30 · SYD 01:30+1

$ terrahour --watch            # the same line, updating in place (good in a small tmux pane)
$ terrahour --tmux             # with tmux colour codes, for your status-right
$ terrahour --json --at 2026-03-18T14:30Z | jq '.cities[] | select(.open)'

The JSON includes local time, UTC offset, whether the city is inside working hours, minutes until that changes, and the next clock change. --once --size 120x40 prints a single frame of the full UI, which is how the screenshots above were made.

Network

Two features talk to the internet, and both are optional:

  • While you type in the "add city" box, names that are not in the built-in list are looked up through the Open-Meteo geocoding API.
  • Weather, when you turn it on with W, comes from the Open-Meteo forecast API.

Set TERRAHOUR_OFFLINE=1 to switch both off. Nothing else leaves your machine.

How it is put together

It is a single Python package with no third-party dependencies. The pieces:

Module What it does
cli.py argument parsing and the non-interactive modes
app.py the terminal loop: raw mode, input tokens, redraw only the lines that changed
keys.py every key and mouse event ends up here
compose.py, draw.py, overlays.py, ambient.py turn the state into a frame
canvas.py a character grid with colours that renders to ANSI escapes
clock.py offsets, formatting, open/closed status, DST transitions, overlap
astro.py sun position, sunrise and sunset
worldmap.py the land mask, braille rasterisation, zoom and pan
places.py, geocode.py the city database, search, and the online lookup
state.py the State object and the config file
alerts.py, weather.py what the names say
themes.py colours; every module reads them through the active theme object C
data/ the city list, the land mask and the exchange list, with their own README

The map is a 0.25 degree land mask folded into a summed-area table, so any zoom level can ask "how much of this box is land?" in constant time, and the braille cells come straight out of that. Sun position uses the usual NOAA approximation, good to a few minutes.

Development

python -m venv .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest

The tests do not need a terminal or the network: they compose frames in memory and drive the app through the same key handler the terminal loop uses. tools/screenshots.py regenerates everything in docs/ (it needs Pillow and the DejaVu fonts).

Data and credits

  • City list derived from GeoNames (CC BY 4.0).
  • Land mask rasterised from Natural Earth (public domain).
  • Geocoding and weather from Open-Meteo (CC BY 4.0).
  • Time zone rules come from your operating system's tz database through Python's zoneinfo.

License

MIT. See LICENSE.

Metadata

Release files for terrahour 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for terrahour 1.0.0
File Size Uploaded
terrahour-1.0.0.tar.gz 410.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for terrahour 1.0.0
File Interpreter ABI Platform
terrahour-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 809.0 kB

Release files / terrahour-1.0.0.tar.gz

Download URL terrahour-1.0.0.tar.gz
Size 410.1 kB
Tags Source
SHA-256 checksum
How to use checksums
acecd74dece978afb5a4e3696f2c9c2bd4b2c2be95028665e5ccc2873612342d
BLAKE2b-256 checksum
How to use checksums
a66d60a07895c4efe7913840349ee2c5fc51fbd5950cdfbe6d1d5a9d98b2b549
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release files / terrahour-1.0.0-py3-none-any.whl

Download URL terrahour-1.0.0-py3-none-any.whl
Size 398.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d47452e042bfc07aa0d6a816c2219d9178a2cb3a94f5bedfca29b60ec43467c9
BLAKE2b-256 checksum
How to use checksums
404ef6de3aa672fbfe30650a832b8456bd47dfbc4e740d94c2ede4fbf54e94c7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 1, 2026.

Transparency log

Release history Release notifications | RSS feed

1.0.8

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page