A Chrome extension for developers who read timestamps from logs all day.
Click the toolbar icon and you get two things: live clocks across the timezones you care about, and a scratchpad for converting any moment in time across those same zones — paste an ISO string or a unix timestamp from a log and see what it means everywhere at once.
Live clocks — Local, UTC, and any IANA zones you add. Each row shows wall-clock time and ISO string with the zone's offset; Local and UTC also show unix milliseconds. Click any value to copy. Updates every second.
Smart-paste converter — One ISO input and one unix-timestamp input, both bound to the same instant. Pasting a number auto-detects seconds (10 digits), milliseconds (13), microseconds (16), or nanoseconds (19) by magnitude.
Per-zone editable rows — In the converter, every tracked zone has six editable fields (YYYY-MM-DD HH:MM:SS). Editing any field re-resolves the underlying instant in that zone's calendar, then re-renders every other row. Type 13 in the month and the year ticks up.
Calendar-aware adjustments — −1y −1mo −7d −1d / +1d +7d +1mo +1y buttons. Adjustments use the calendar of whichever row you last edited, so "+1 month" means "+1 month in Tokyo" if Tokyo is what you were tweaking. Powered by Temporal for correct DST and month-length behavior.
Zero clutter — Toolbar popup, no options page, no host permissions. Add and remove timezones inline. Tracked zones persist via chrome.storage.local; the converter resets to "now" each time you open the popup.
git clone https://github.com/Seitk/tminus.git
cd tminus
npm install
npm run buildThen in Chrome:
- Open
chrome://extensions. - Enable Developer mode (top right).
- Click Load unpacked and select the
dist/folder this build produced.
The T icon will appear in your toolbar. Pin it for one-click access.
npm run dev # rebuilds dist/ on save
npm run build # production build
npm run check # svelte-check + tsc on the Vite configAfter npm run dev, edits trigger a rebuild but Chrome doesn't auto-reload extensions. Click the reload icon next to tminus in chrome://extensions to pick up changes.
A new release is cut by pushing a v* tag. GitHub Actions builds the extension, zips dist/ as tminus-<tag>.zip, and attaches it to a GitHub release with auto-generated notes.
# bump the version in package.json first, then:
git tag v0.1.0
git push origin v0.1.0- TypeScript + Vite + Svelte 4
temporal-polyfillfor timezone-aware calendar math (millisecond precision)- Manifest V3,
storagepermission only — no service worker, no content scripts, no host access
popup.html # extension popup entry (project root, not src/)
src/
popup.ts # mounts <App />
App.svelte # popup root
app.css # design tokens + base styles
lib/
stores.ts # Svelte stores: liveNow, converterAt, lastEditedZone, userZones, parseError
storage.ts # chrome.storage.local wrappers
format.ts # wallClock / isoInZone / unixMs / offsetLabel / fields / instantFromFields
parse.ts # smart-paste parser (ISO + unix s/ms/μs/ns)
timezones.ts # IANA zone list + label helpers
components/
LiveClocks.svelte
LiveClockRow.svelte
Converter.svelte
ConverterRow.svelte
ZoneAdder.svelte
public/
manifest.json # MV3
icons/ # 16 / 48 / 128 px PNGs
The popup-as-its-own-build-input pattern means popup.html lives at the repo root rather than in src/ — that's what makes Vite emit dist/popup.html (which the manifest references) instead of dist/src/popup.html.
Issues and PRs welcome at https://github.com/Seitk/tminus.
