Functional Weave
Code in Python

time.minutes-between

Minutes from one local date and time to another, correct across midnight; wall-clock time, no time zones.

1.0.0 · published 2026-10-03 by charlie · Anterra

Pinned by 15 tests, run in TypeScript, Python and Rust.

What it does

The minutes from a start date and time to an end date and time. A night shift from 22:00 on 22 September to 06:00 on 23 September is 480 minutes. Taking the dates as well as the times is the point: with times alone, 22:00 to 06:00 is either -960 minutes or a guess that the end is "probably tomorrow", and a shift longer than 24 hours cannot be expressed at all.

The answer is signed like dates.days-between: an end before the start is negative, so swapped arguments are visible rather than silently becoming a next-day shift.

For example

  • minutes_between(2026-09-22, 09:00, 2026-09-22, 17:30) → 510 a day shift on one date
  • minutes_between(2026-09-22, 22:00, 2026-09-23, 06:00) → 480 a night shift across midnight is 480, not -960
  • minutes_between(2026-09-22, 12:00, 2026-09-22, 12:00) → 0 the same instant is zero

The function

The same function in TypeScript, Python and Rust, pinned by the same tests. Pick your language; the choice follows you around the registry.

def minutes_between(start_date: str, start_time: str, end_date: str, end_time: str) -> int
start_datedateISO date the period starts on
start_timestringHH:MM, 24-hour, 00:00 to 23:59
end_datedateISO date the period ends on
end_timestringHH:MM, 24-hour, 00:00 to 23:59
returnsintend minus start in minutes; negative when the end is earlier

Your code names it in one line, in the file that uses it

from fune.time.minutes_between import minutes_between  # time.minutes-between@^1
impl/python.py · 24 lines · open · raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

from .dates_add_days import epoch_day_from_iso  ← from dates.add-days ^1.0.0 · built alongside by fune


def _minute_of_day(time: str) -> int:
    ok = (
        isinstance(time, str)
        and len(time) == 5
        and time[2] == ":"
        and all("0" <= time[i] <= "9" for i in (0, 1, 3, 4))
    )
    hours = int(time[0:2]) if ok else -1
    minutes = int(time[3:5]) if ok else -1
    if not ok or hours > 23 or minutes > 59:
        raise ValueError('"%s" is not a time of day (HH:MM, 00:00 to 23:59)' % (time,))
    return hours * 60 + minutes


def minutes_between(start_date: str, start_time: str, end_date: str, end_time: str) -> int:
    """Minutes from one local date and time to another: the difference between
    two wall-clock readings. It knows nothing of time zones or daylight saving,
    so across a clock change it differs from real elapsed time by the change.
    """
    days = epoch_day_from_iso(end_date) - epoch_day_from_iso(start_date)
    return days * 1440 + _minute_of_day(end_time) - _minute_of_day(start_time)

Install

fune build

With that line in your source, in a Python project (language python in fune.project), fune build resolves it and its 1 dependency, pins them in fune.lock, downloads only the Python package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. Or pin a range in fune.project and build in one step:

fune add time.minutes-between
Download for Python time.minutes-between-1.0.0-python.fune · 6,416 bytes sha256 1294cc8ffc73e915195a54c9bd5e5276f35bd6584274682b1f7be3b3dbdc08e9

The manifest, vectors and README with only the Python implementation. Install it without the registry with fune add ./time.minutes-between-1.0.0-python.fune, or fetch it from a terminal with fune pull time.minutes-between@1.0.0:python.

The whole function, every language, is one file too: time.minutes-between-1.0.0.fune, 8,862 bytes, sha256 f28512233b8908b71542c3178abccb2281cb736b93ba1f13ac1eede9c71e9386. It installs into a project of any language.

Customise it in your app

The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.

before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.

# fune: before time.minutes-between

after — your function gets the result and the arguments, and returns the final result.

# fune: after time.minutes-between

replace — inside this capability’s code only, calls to a dependency go to your function, with the same signature. Other capabilities that use it are unaffected; write in * to replace it everywhere.

# fune: replace dates.add-days in time.minutes-between

step — your function runs at a numbered point inside the function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show time.minutes-between --steps.

# fune: step time.minutes-between after <n|label>

Tests

A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript, Python and Rust, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json.

CaseArgumentsExpected
a day shift on one date 2026-09-22, 09:00, 2026-09-22, 17:30 → 510
a night shift across midnight is 480, not -960 2026-09-22, 22:00, 2026-09-23, 06:00 → 480
the same instant is zero 2026-09-22, 12:00, 2026-09-22, 12:00 → 0
an end before the start is negative 2026-09-22, 12:30, 2026-09-22, 12:00 → -30
a whole day of minutes 2026-09-22, 00:00, 2026-09-22, 23:59 → 1,439
a shift longer than 24 hours 2026-09-22, 08:00, 2026-09-23, 20:00 → 2,160
across a year end 2026-12-31, 23:45, 2027-01-01, 00:15 → 30
across 29 February 2024-02-28, 12:00, 2024-03-01, 12:00 → 2,880
across the UK clocks going forward: wall-clock 180, though 120 real minutes passed 2026-03-29, 00:30, 2026-03-29, 03:30 → 180
across the UK clocks going back: wall-clock 180, though 240 real minutes passed 2026-10-25, 00:30, 2026-10-25, 03:30 → 180
Show the other 5 tests
CaseArgumentsExpected
24:00 is not a time of day; use 00:00 on the next date 2026-09-22, 20:00, 2026-09-22, 24:00 → error: "24:00" is not a time of day
an unpadded hour is rejected 2026-09-22, 9:00, 2026-09-22, 17:00 → error: "9:00" is not a time of day
minute 60 is rejected 2026-09-22, 12:60, 2026-09-22, 17:00 → error: "12:60" is not a time of day
a dotted time is rejected 2026-09-22, 12.30, 2026-09-22, 17:00 → error: "12.30" is not a time of day
an impossible date is rejected 2026-02-30, 12:00, 2026-03-01, 12:00 → error: is not a real calendar date

More from the author

**Local wall-clock time, no time zones.** Both times are read off the same clock on the wall, and the answer is the difference between those readings. It does not know about daylight saving: in the UK, 00:30 to 03:30 on 29 March 2026 is 180 minutes here though only 120 minutes passed, because the clocks went forward at 01:00; on 25 October 2026 the same readings are 180 here and 240 in reality. Payroll and time-and-attendance rules differ on which of those to pay, so this capability does not pick one silently: if real elapsed time matters, convert both instants to UTC with a time zone database first and subtract those.

Times are strictly HH:MM, 24-hour, 00:00 to 23:59. "24:00", "9:00" and "5pm" are errors rather than guesses; the end of a day is 00:00 on the next date.

Files

PathBytes
README.md1,334
impl/python.py989
impl/rust.rs1,312
impl/typescript.ts1,024
vectors.json2,035