Functional Weave
Code in Python

dates.day-of-week

The ISO 8601 day of the week for a date: 1 is Monday through 7 is Sunday.

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

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

What it does

ISO numbering, 1 = Monday to 7 = Sunday. The alternatives are all off by something: JavaScript's getDay() is 0 = Sunday, Python's weekday() is 0 = Monday and isoweekday() is 1 = Monday. Fixing one convention across the three languages is the point, and it makes a weekend test read as day >= 6 everywhere.

It depends on dates.add-days rather than re-deriving days-from-civil: the calendar kernel has one home in the registry, so a fix to it is a fix everywhere.

For example

  • day_of_week(1970-01-01) → 4 the epoch itself, 1 January 1970, was a Thursday
  • day_of_week(2026-09-16) → 3 an ordinary Wednesday
  • day_of_week(2026-09-19) → 6 Saturday is 6

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 day_of_week(iso: str) -> int
isodateISO date, YYYY-MM-DD
returnsint1 = Monday ... 7 = Sunday

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

from fune.dates.day_of_week import day_of_week  # dates.day-of-week@^1
impl/python.py · 43 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

DAY_NAMES = (
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
    "Sunday",
)


def day_of_week(iso: str) -> int:
    """The ISO 8601 day of the week: 1 = Monday through 7 = Sunday.

    ISO numbering rather than the 0 = Monday that Python's own weekday() uses
    or the 0 = Sunday that JavaScript uses, because ISO is what the rest of the
    business world means by "day 1" and because a weekend test becomes
    ``day >= 6`` in every language.
    """
    # 1970-01-01, epoch day 0, was a Thursday. Shifting by 3 moves the origin of
    # the cycle to Monday so that the remainder is already ISO numbering.
    return (epoch_day_from_iso(iso) + 3) % 7 + 1


def is_weekend(iso: str) -> bool:
    """True for Saturday and Sunday."""
    return day_of_week(iso) >= 6


def is_weekday(iso: str) -> bool:
    """True for Monday to Friday. Says nothing about public holidays."""
    return day_of_week(iso) <= 5


def day_name(iso: str) -> str:
    """The English name, for logs and labels.

    Not localised, deliberately: a capability that needed locale data would need
    a locale argument and a data file to pin it.
    """
    return DAY_NAMES[day_of_week(iso) - 1]

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 dates.day-of-week
Download for Python dates.day-of-week-1.0.0-python.fune · 5,781 bytes sha256 a62b11d2d6b5f0f21e0d95e12a7bd34d651b0f1b66fb0655bf7975e2989475a8

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

The whole function, every language, is one file too: dates.day-of-week-1.0.0.fune, 8,714 bytes, sha256 976f7dbb98c070afdfb65de0f361d7b00c14159b37a0ee2615f23fc535081d4a. 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 dates.day-of-week

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

# fune: after dates.day-of-week

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 dates.day-of-week

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 dates.day-of-week --steps.

# fune: step dates.day-of-week 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
the epoch itself, 1 January 1970, was a Thursday 1970-01-01 → 4
an ordinary Wednesday 2026-09-16 → 3
Saturday is 6 2026-09-19 → 6
Sunday is 7, not 0 2026-09-20 → 7
Monday is 1 2026-09-21 → 1
1 January 2000 was a Saturday 2000-01-01 → 6
31 December 1999 was a Friday 1999-12-31 → 5
1 January 1900 was a Monday, well before the epoch 1900-01-01 → 1
the 2024 leap day was a Thursday 2024-02-29 → 4
1 March 1900 was a Thursday because 1900 had no leap day 1900-03-01 → 4
Show the other 10 tests
CaseArgumentsExpected
1 March 2000 was a Wednesday because 2000 did have one 2000-03-01 → 3
the first supported date, 1 January 0001, is a Monday 0001-01-01 → 1
the last supported date, 31 December 9999, is a Friday 9999-12-31 → 5
a slash-separated date is an error, not a guess 16/09/2026 → error: is not an ISO date
an unpadded month is an error 2026-9-16 → error: is not an ISO date
an empty string is an error → error: is not an ISO date
30 February is not a real date 2026-02-30 → error: is not a real calendar date
29 February in a non-leap year is rejected 2026-02-29 → error: is not a real calendar date
month 00 is rejected 2026-00-10 → error: is not a real calendar date
day 00 is rejected 2026-09-00 → error: is not a real calendar date

More from the author

The day number comes from the epoch day, not from a table, so it is correct for dates before 1970 (where the day number is negative) as well as after. Getting the sign right matters: a plain remainder in Rust or TypeScript keeps the sign of the dividend and would return a negative weekday for 1900 dates, so both use a floored remainder.

It says nothing about public holidays. Working days are dates.business-days-between, which takes the holiday list as an argument because no library knows your company's.

Files

PathBytes
README.md995
impl/python.py1,264
impl/rust.rs1,493
impl/typescript.ts1,293
vectors.json1,977