Desktop alarms, timers, world clock, and scheduling. Python 3.12+ / PySide6.
  • Python 99.8%
  • Shell 0.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
dev 1992b3d151
Some checks failed
ci / quality (push) Successful in 4m42s
ci / build-linux (push) Failing after 11m32s
ci / build-macos (push) Has been skipped
ci / build-windows (push) Has been skipped
fix(ci): preserve published assets and add release verification
Keep existing release assets and upload only missing files. Leave published
release metadata untouched and finalize a draft only after its assets exist.

Add a manual metadata-only check for an existing release tag. Require the
expected assets, stable release and asset timestamps, and an unchanged tag
without rebuilding or downloading binaries.

Validation: fresh and repeated publishing, incomplete releases, API failures,
old-code regression, 25 verifier cases per repository, and read-only checks
of the current published releases.
2026-10-17 11:18:02 -04:00
.forgejo/workflows fix(ci): preserve published assets and add release verification 2026-10-17 11:18:02 -04:00
app fix: harden services and refresh clock UI data 2026-10-02 15:24:33 -04:00
docs fix: harden services and refresh clock UI data 2026-10-02 15:24:33 -04:00
scripts fix: harden services and refresh clock UI data 2026-10-02 15:24:33 -04:00
tests fix: harden services and refresh clock UI data 2026-10-02 15:24:33 -04:00
.git-allowed-signers Initial commit 2026-08-14 03:18:38 -04:00
.gitignore Initial commit 2026-08-14 03:18:38 -04:00
AGENTS.md fix: harden services and refresh clock UI data 2026-10-02 15:24:33 -04:00
icu-clock.spec Initial commit 2026-08-14 03:18:38 -04:00
LICENSE Initial commit 2026-08-14 03:18:38 -04:00
minisign.pub Initial commit 2026-08-14 03:18:38 -04:00
pyproject.toml fix: harden services and refresh clock UI data 2026-10-02 15:24:33 -04:00
README.md fix: harden services and refresh clock UI data 2026-10-02 15:24:33 -04:00
run.py Initial commit 2026-08-14 03:18:38 -04:00
uv.lock Initial commit 2026-08-14 03:18:38 -04:00

ICU Clock

A desktop companion for alarms, timers, world clocks, market hours and economic events — built with Python and Qt (PySide6).

ICU Clock — Alarms view

Features

  • Alarms — one-shot and recurring (RFC 5545-style: daily/weekly/monthly/yearly, intervals, weekday/month-day selection, EXDATE/RDATE, leap-day policies), sub-repetitions (repeat N times within a window), cancel-if-late, per-alarm timezone, rich message styling
  • World Clock — multiple cities with live local time, daylight progress, weather (Open-Meteo / MET Norway) with hourly and daily forecasts
  • Economic Calendar — scraped high-impact event schedules (forex, crypto, metals, energy) with per-event details, historical graphs, and event alarms
  • Market Hours — exchange trading-hours tracker with phase indicators
  • Stopwatch / Timers / Pomodoro — the classics, with tray integration
  • Integrations — alarm delivery via Telegram, Discord, Gotify, Email; CalDAV calendar sync
  • Theming & i18n — multiple themes with live switching, JSON translation catalogs
  • Sidebar modules can be popped out into separate windows; keyboard shortcuts Ctrl+1–Ctrl+9

Screenshots

World Clock — cities with live local time and daylight progress

ICU Clock — World Clock

Economic Calendar — high-impact events (forex, crypto, metals, energy) with impact colouring

ICU Clock — Economic Calendar

Market Hours — exchange/trading-hours tracker with live phase bars

ICU Clock — Market Hours

Pomodoro — work/break cycles with tray feedback

ICU Clock — Pomodoro

Timers — countdown timers with reusable presets

ICU Clock — Timers

Settings — everything configurable, with multiple themes

ICU Clock — Settings

Installation

Requires Python 3.12+.

git clone https://git.gui.icu/dev/icu-clock.git
cd icu-clock
bash scripts/install_uv.sh
.ci-bin/uv sync --frozen

Running

.venv/bin/python -m app

In-app documentation is available under Help → Documentation (or press F1):

ICU Clock — built-in documentation

Building standalone binaries

ICU Clock is cross-platform (Linux, Windows, macOS). Each build script produces a single self-contained binary with PyInstaller — no Python installation needed on the target machine. Build on the OS you are targeting (PyInstaller does not cross-compile).

All platforms, first:

git clone https://git.gui.icu/dev/icu-clock.git && cd icu-clock
bash scripts/install_uv.sh
export UV="$PWD/.ci-bin/uv"

Linux

./scripts/build_linux.sh          # -> dist/icu-clock (single file)

Install for the current user:

install -Dm755 dist/icu-clock ~/.local/bin/icu-clock
cat > ~/.local/share/applications/icu-clock.desktop <<EOF
[Desktop Entry]
Type=Application
Name=ICU Clock
Exec=$HOME/.local/bin/icu-clock
Categories=Utility;Clock;
EOF

Windows

powershell -File .\scripts\install_uv.ps1
set UV=%CD%\.ci-bin\uv.exe
scripts\build_win.bat            &rem -> dist\icu-clock.exe (single file)

Copy dist\icu-clock.exe anywhere (e.g. %LOCALAPPDATA%\Programs\icu-clock\) and create a Start-menu/desktop shortcut to it. The build is windowed — no console window appears.

macOS

./scripts/build_macos.sh          # -> dist/icu-clock (single file)

Move the binary into /Applications (or wrap it in an .app bundle via the generated icu-clock.spec if you prefer a standard bundle). Unsigned builds require right-click → Open on first launch (Gatekeeper).

First launch of a single-file build is a little slower than subsequent ones — the binary unpacks itself to a temp dir at startup.

Data & configuration

User data lives in the platform config directory (~/.config/icu-clock on Linux, %APPDATA%\icu-clock on Windows, ~/Library/Application Support/icu-clock on macOS):

  • settings.json — application settings (human-readable)
  • clock.db — alarms, world clocks, market-hours entries (SQLite)
  • cache.db — weather and economic-calendar caches (SQLite; safe to delete)

Security constraints

Imports reject script-capable alarms and invalid bundles before changing data. Create script alarms locally. Import files and network responses are limited to 16 MiB; alarm bundles are limited to 10,000 entries.

CalDAV and notification credentials require HTTPS; SMTP login requires STARTTLS or SSL/TLS. CalDAV and Gotify accounts can explicitly allow unencrypted HTTP for loopback or private LAN servers. Local HTTP exceptions require a direct connection and are reset when importing settings. HTTPS certificate verification remains enabled. Authenticated requests and redirects stay on the configured server origin.

Development

.ci-bin/uv sync --frozen --group dev
.venv/bin/pytest
.venv/bin/ruff check app tests
.venv/bin/ruff format app tests
.venv/bin/mypy
.venv/bin/vulture app

Architecture in one line: a flat app/ package split into app/core/ (headless business logic — storage, scheduler, recurrence engine, services; never imports Qt) and app/gui/ (all PySide6 code — views, widgets, services, themes, i18n). That split is a hard invariant, enforced in CI:

grep -rln "PySide6\|qt_compat\|app\.gui" app/core --include='*.py'   # must be empty

Verifying a download

Release binaries are signed with minisign. Every release carries detached .minisig signatures plus a signed SHA256SUMS manifest. Each release includes complete Linux, macOS, and Windows amd64 binaries. The project's public key is committed here as minisign.pub:

RWSwrmo0LtNQHL0QCMsdY3aCpAR328SjFskp4Nni5VhLElrcq6dA2ZlS

Verify a single binary:

minisign -Vm icu-clock-linux-x86_64 -P RWSwrmo0LtNQHL0QCMsdY3aCpAR328SjFskp4Nni5VhLElrcq6dA2ZlS

Or check the whole manifest at once:

minisign -Vm SHA256SUMS -P RWSwrmo0LtNQHL0QCMsdY3aCpAR328SjFskp4Nni5VhLElrcq6dA2ZlS && sha256sum -c SHA256SUMS

Note there is no OS code signing (no Apple notarization, no Windows Authenticode), so macOS and Windows still show the usual unsigned-app prompt on first launch. The signatures above prove the binary is authentic and unmodified; they do not register the app with the OS trust store.

License

MIT — see LICENSE.