Functional Weave
Code in Rust

dates.week-number

ISO 8601 week number and week-numbering year of a date: weeks start Monday, week 1 holds the first Thursday.

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

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

What it does

The ISO 8601 week of a date. Weeks run Monday to Sunday, and week 1 of a year is the week containing that year's first Thursday (equivalently, the week containing 4 January). A year has 52 or 53 weeks.

The trap is the year. Around 1 January a date can belong to the previous or the next ISO week-year: 1 January 2027 is in week 53 of 2026, and 30 December 2024 is in week 1 of 2025. So the result carries `weekYear` alongside `week`, and `label` ("2026-W53") is built from the week-year, never the calendar year. A report keyed on calendar year and ISO week puts 30 December 2024 in "2024 week 1", eleven months early.

For example

  • week_number(2026-09-23) → week year 2,026, week 39, label 2026-W39 an ordinary Wednesday in September
  • week_number(2026-01-01) → week year 2,026, week 1, label 2026-W01 1 January 2026 is a Thursday, so it is in week 1
  • week_number(2027-01-01) → week year 2,026, week 53, label 2026-W53 1 January 2027 is a Friday and belongs to week 53 of 2026, not week 1 of 2027

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.

pub fn week_number(iso: &str) -> IsoWeek
isodateany date
returnsIsoWeek

The type it declares, generated into your project

/// A date's ISO 8601 week.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IsoWeek {
    /// the ISO week-numbering year; differs from the calendar year for a few days around 1 January
    pub week_year: i64,
    /// 1 to 52 or 53
    pub week: i64,
    /// ISO week form, e.g. 2026-W39
    pub label: String,
}

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

fune!(dates.week-number@^1);  // then call week_number(…)
impl/rust.rs · 33 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.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::dates_add_days::{civil_from_days, days_from_civil, epoch_day_from_iso};  ← from dates.add-days ^1.0.0 · built alongside by fune
use super::dates_day_of_week::day_of_week;  ← from dates.day-of-week ^1.0.0 · built alongside by fune

/// The ISO 8601 week of a date. The Thursday of the date's Monday-to-Sunday
/// week decides everything: its calendar year is the week-year, and its day of
/// that year gives the week number.
///
/// # Panics
/// Panics if the date is malformed or impossible.
pub fn week_number(iso: &str) -> IsoWeek {
    let thursday = epoch_day_from_iso(iso) + (4 - day_of_week(iso));
    let week_year = civil_from_days(thursday).year;
    // Non-negative: the Thursday is never before 1 January of its own year.
    let week = (thursday - days_from_civil(week_year, 1, 1)) / 7 + 1;
    IsoWeek {
        week_year,
        week,
        label: format!("{:04}-W{:02}", week_year, week),
    }
}

pub fn iso_week_to_value(w: &IsoWeek) -> Value {
    Value::obj(vec![
        ("weekYear", Value::Int(w.week_year)),
        ("week", Value::Int(w.week)),
        ("label", Value::str(&w.label)),
    ])
}

pub fn fune_vector(args: &[Value]) -> Value {
    iso_week_to_value(&week_number(args[0].as_str()))
}

Install

fune build

With that line in your source, in a Rust project (language rust in fune.project), fune build resolves it and its 2 dependencies, pins them in fune.lock, downloads only the Rust 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. A crate’s build.rs runs it before every compile. Or pin a range in fune.project and build in one step:

fune add dates.week-number
Download for Rust dates.week-number-1.0.0-rust.fune · 7,003 bytes sha256 37f218791412f737dec187bdf0c9a4711cfc9123669aa1e59040f6dc6bf74602

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

The whole function, every language, is one file too: dates.week-number-1.0.0.fune, 8,545 bytes, sha256 57419625d710371dddc8e6db21a61c341ada81dd0670f975210cf019b72de781. 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.week-number

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

// fune: after dates.week-number

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.week-number
// fune: replace dates.day-of-week in dates.week-number

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.week-number --steps.

// fune: step dates.week-number 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
an ordinary Wednesday in September 2026-09-23 → week year 2,026, week 39, label 2026-W39
1 January 2026 is a Thursday, so it is in week 1 2026-01-01 → week year 2,026, week 1, label 2026-W01
1 January 2027 is a Friday and belongs to week 53 of 2026, not week 1 of 2027 2027-01-01 → week year 2,026, week 53, label 2026-W53
Sunday 3 January 2027 still ends week 53 of 2026 2027-01-03 → week year 2,026, week 53, label 2026-W53
Monday 4 January 2027 starts week 1 of 2027 2027-01-04 → week year 2,027, week 1, label 2027-W01
30 December 2024 is in week 1 of 2025: calendar year and week-year differ 2024-12-30 → week year 2,025, week 1, label 2025-W01
29 December 2008 is in week 1 of 2009 2008-12-29 → week year 2,009, week 1, label 2009-W01
2020 had 53 weeks: 31 December 2020 is in week 53 2020-12-31 → week year 2,020, week 53, label 2020-W53
3 January 2021 is still in week 53 of 2020 2021-01-03 → week year 2,020, week 53, label 2020-W53
2015 had 53 weeks 2015-12-31 → week year 2,015, week 53, label 2015-W53
Show the other 8 tests
CaseArgumentsExpected
31 December 2026 is in week 53 of 2026 2026-12-31 → week year 2,026, week 53, label 2026-W53
2004 was a leap year starting on Thursday, so it had 53 weeks 2004-12-31 → week year 2,004, week 53, label 2004-W53
3 January 2010 belongs to week 53 of 2009 2010-01-03 → week year 2,009, week 53, label 2009-W53
1 January 1900 was a Monday: week 1 1900-01-01 → week year 1,900, week 1, label 1900-W01
the first supported date was a Monday: 0001-W01 0001-01-01 → week year 1, week 1, label 0001-W01
the last supported date is in week 52 of 9999 9999-12-31 → week year 9,999, week 52, label 9999-W52
an impossible date is an error 2026-02-29 → error: is not a real calendar date
an ISO week string is not a date 2026-W39 → error: is not an ISO date

More from the author

This is the ISO scheme only. US-style week numbers (weeks starting Sunday, week 1 containing 1 January) and "week of the month" are different questions.

The week is found from the Thursday of the date's week, whose calendar year is by definition the week-year, using the dates.add-days kernel and dates.day-of-week, so it is exact for every date from 0001-01-01 to 9999-12-31.

Files

PathBytes
README.md1,020
impl/python.py687
impl/rust.rs1,149
impl/typescript.ts768
vectors.json2,600