Functional Weave
Code in Rust

time.countdown@1.0.0

README.md

1,496 bytes · view raw

# time.countdown

How long is left until a moment, as a number and as the text a timer shows:

```
countdown(1790427600, 1790424000)   # {expired: false, seconds: 3600, text: "1:00:00"}
countdown(1000754, 1000000)         # {expired: false, seconds: 754,  text: "12:34"}
countdown(1790427600, 1790427600)   # {expired: true,  seconds: 0,    text: "0:00"}
```

Use it for an access token's remaining life (`until` is the token's `exp`),
for how long a locked-out login must wait (`until` is now plus Retry-After),
or for a cookie's `Max-Age` (`seconds`). The caller reads the clock and
passes `now`, so the function stays pure and a page can call it once a
second to tick.

**Reached means expired.** The moment is reached at `until` itself, not one
second later: RFC 7519 section 4.1.4 says a token MUST NOT be accepted "on or
after" its `exp`. So `now == until` is `expired: true` with `seconds: 0`, and
`expired` is exactly `seconds == 0`. A moment already past is also 0, never
negative, so a timer never shows "-0:05".

**Text.** `m:ss` under an hour (`0:59`, `12:34`), `h:mm:ss` from an hour up
(`1:00:00`). Hours are not wrapped at 24, because a wait is a length of time
and not a time of day: 25 hours and a bit is `25:01:01`.

**Whole seconds.** Both arguments are whole Unix seconds, as JWT `exp` and
`time.iso-to-unix` give them. A fraction (JavaScript's `Date.now() / 1000`
not floored) is refused: "until must be a whole number of seconds" or "now
must be a whole number of seconds".