tzselect-rs 0.1.0

Rust port of upstream tzselect.ksh — the interactive tzdb timezone selector
Documentation
# tzselect-rs

A faithful, memory-safe Rust port of upstream **`tzselect.ksh`** from the
[IANA time zone database](https://www.iana.org/time-zones) — the interactive
program that helps a user pick a `TZ` value by continent → country → region, by
geographic coordinates (`-c`), by a proleptic POSIX `TZ` string, or by current
local time.

```
TZDIR=/usr/share/zoneinfo tzselect-rs          # interactive (stderr/stdin); TZ on stdout
echo -e '8\n3\n1' | tzselect-rs                # scriptable, like upstream tzselect
tzselect-rs -c +4852+00220                     # nearest zones to a coordinate
tzselect-rs --help / --version
```

Upstream `tzselect.ksh` is an interactive Korn/Bash script wrapping several
POSIX-awk programs. tzselect-rs ports all of it to native Rust — the menu
`select` loop, the country/region/`TZ` derivation, the great-circle coordinate
distance ranking, and the POSIX-`TZ`-string grammar (hand-parsed, so there are
**no runtime dependencies**). Like the upstream it shells out to `date` for the
current-time displays.

## Claim boundary

tzselect-rs **does not define timezone policy or choose a timezone for the
user.** It ports the interactive selection behaviour of upstream `tzselect.ksh`
into Rust, using the same tzdb table surfaces (`iso3166.tab`, `zone1970.tab`),
and verifies representative prompt/output paths against the upstream shell
oracle. It is the user-selection layer of the Rust tzdb toolchain, beside
[`zic-rs`](https://github.com/infinityabundance/zic-rs) and the producer/QA
crates ([ziguard-rs](https://github.com/infinityabundance/ziguard-rs),
[zishrink-rs](https://github.com/infinityabundance/zishrink-rs),
[checktab-rs](https://github.com/infinityabundance/checktab-rs),
[checklinks-rs](https://github.com/infinityabundance/checklinks-rs),
[checknow-rs](https://github.com/infinityabundance/checknow-rs),
[leapseconds-rs](https://github.com/infinityabundance/leapseconds-rs)); it does
**not** enter libc `localtime`/`strftime` runtime territory.

## Parity contract

`tzselect.ksh` is interactive, so the oracle is a *driven shell process* and the
claim is **prompt/output-sequence parity**. The deterministic oracle is
`LC_ALL=C.UTF-8 COLUMNS=1 tzselect` — single-column `select`, raw-UTF-8 country
names, bytewise sort. Against it, tzselect-rs is **byte-identical** on stderr
(the prompts/menus), stdout (the chosen `TZ`), and exit status.

**Classified (not byte-compared), exactly as upstream allows:**

- the two live-clock lines `Selected time is now:` / `Universal Time is now:`
  and the interactive `time`/`now` local-time menus — **time-dependent**;
- the `read tz` EOF case — upstream `tzselect.ksh` **infinite-loops** on EOF
  during `TZ`-string entry (a shell `while … read` with no `|| exit`);
  tzselect-rs exits cleanly (a deliberate, classified safer divergence);
- wide-terminal multi-column `select` layout and non-UTF-8-locale `iconv`
  transliteration — shell/terminal/locale rendering details.

## Evidence

- **Exhaustive enumeration:** **all 525** continent → country → region leaf
  paths (every menu choice in `zone1970.tab`) are **byte-identical** to the
  oracle (stderr + stdout + exit).
- **Differential sweep:** **1402 / 0** random scripted navigation paths match
  (continent/country/region, coord, `TZ`-string, bad-input re-prompts, EOF), with
  85 time-dependent and 38 read-EOF-hang cases cleanly classified. Receipt:
  `reports/oracle/`.
- **Kani:** the menu-index guard is proven sound (`items[n-1]` always in bounds).
- **Fuzz:** `cargo +nightly fuzz``posix_tz` 31M execs, `driver` 574k execs,
  **0 crashes**. Receipt: `reports/fuzz/`.

## Build & test

```
cargo build --release
cargo test                                  # mock-host golden regression + posix_tz
cargo clippy --all-targets -- -D warnings
cargo kani --harness menu_index_guard_is_sound
bash lab/oracle/sweep.py 1000               # the oracle differential sweep (needs the 2026b lab)
```

## License

Apache-2.0. The upstream `tzselect.ksh` and the tzdb tables are public domain;
this Rust port is an independent reimplementation.