Functional Weave
Code in Rust

Suites · education

Education and training

Schools, colleges and training: academic years and terms, year groups, attendance, grades and weighted marks, GPA and degree classes, timetable clashes, fees and CPD.

34 capabilities (15 core, 19 optional) and 8 gaps, in build order. Put each line in the file that calls it, then fune build.

UK first: year groups, academic years, attendance thresholds and degree classification follow UK conventions; check your institution's own regulations.

1. Academic calendar

Put dates into academic years and terms, and pupils into year groups.

education.academic-year core
The academic year and term a date falls in, terms supplied by you.
The academic year and term a date falls in: 1 September to 31 August by default, terms from the caller.
fune!(education.academic-year@^1);  // then call academic_year(…)
education.school-year-group core
School year group from date of birth, by UK nation.
School year group from date of birth on a date, by UK nation: Reception to Year 13, P1 to S6, P1 to Year 14.
fune!(education.school-year-group@^1);  // then call school_year_group(…)
dates.age optional
Age in whole years on a date.
Age in whole years on a given date, with 29 February birthdays ageing on 1 March in other years.
fune!(dates.age@^1);  // then call age(…)

2. Attendance

Track attendance and spot persistent absence.

education.attendance-rate core
Attendance and absence rates with the DfE persistent and severe absence flags.
Pupil attendance and absence rates in basis points, with the DfE persistent and severe absence flags.
fune!(education.attendance-rate@^1);  // then call attendance_rate(…)
  • registers Taking registers (marks, codes per session) and storing them is yours.

3. Assessment and grades

Turn marks into grades and results.

education.grade-boundaries core
Grade for a mark from your boundary table.
Grade for a mark from the caller's boundary table: inclusive lower bounds, ungraded below the lowest.
fune!(education.grade-boundaries@^1);  // then call grade_for_mark(…)
education.weighted-grade core
Weighted percentage across coursework and exam components.
Weighted percentage across coursework and exam components, exact as a fraction, then rounded once.
fune!(education.weighted-grade@^1);  // then call weighted_grade(…)
education.gpa optional
GPA on a 4.0 scale from letter grades and credit hours.
Grade point average on a 4.0 scale from letter grades and credit hours, weighted by credits and rounded once.
fune!(education.gpa@^1);  // then call gpa(…)
education.degree-classification optional
UK honours degree class from module marks and credits, weighted by level.
UK honours degree class (First, 2:1, 2:2, Third) from module marks and credits, weighted by level.
fune!(education.degree-classification@^1);  // then call degree_classification(…)
stats.mean-median optional
Class averages and medians, exactly.
Mean, median and mode of a list of integers, with the mean and median as exact fractions.
fune!(stats.mean-median@^1);  // then call mean_median_mode(…)
  • exam-board-data Exam board results and boundaries (via A2C/EDI) are not in caps; you supply the tables.

4. Timetabling

Check a timetable for clashes.

education.timetable-clash core
Finds overlapping sessions that share a room, a teacher or a student group.
Find timetable clashes: overlapping sessions that share a room, a teacher or a student group, in a fixed order.
fune!(education.timetable-clash@^1);  // then call timetable_clashes(…)
  • timetable-generation Building a timetable (constraint solving) is not in caps; it only finds clashes.

5. Fees and finance

Bill fees in instalments.

education.fee-instalments optional
Tuition fee instalment schedule from a total, shares and due dates, to the penny.
Tuition fee instalment schedule from a total, shares and due dates, exact to the penny.
fune!(education.fee-instalments@^1);  // then call fee_instalments(…)
education.student-loan-repayment optional
A graduate's student loan repayment for a tax year.
A graduate's student or postgraduate loan repayment for a tax year, as Self Assessment works it out.
fune!(education.student-loan-repayment@^1);  // then call student_loan_repayment(…)
money.format optional
Shows fees with the currency's decimal places.
Render a monetary amount as text, using the currency's real minor-unit precision.
fune!(money.format@^1);  // then call format_money(…)

6. Professional development

Track CPD against a requirement.

education.cpd-hours optional
CPD minutes logged against a requirement for a period, shortfall and days left.
CPD logged against a requirement for a rolling or fixed period: minutes counted, shortfall and days left.
fune!(education.cpd-hours@^1);  // then call cpd_hours(…)

7. Calendar arithmetic from dates-basics

Move and measure ISO dates exactly, with no date library and no clock reads.

dates.add-days core
Shifts a date by whole days, for due dates and windows.
Shift an ISO date by a whole number of days, forwards or backwards, with exact calendar arithmetic.
fune!(dates.add-days@^1);  // then call add_days(…)
dates.add-months core
Adds months clamping to month end, so 31 January plus a month is the end of February.
Add calendar months to an ISO date, clamping to the month end: 31 Jan + 1 month is 28 or 29 Feb.
fune!(dates.add-months@^1);  // then call add_months(…)
dates.days-between core
Signed calendar days between two dates, for ages of invoices and stays.
Calendar days from one ISO date to another, signed: negative when the second date is earlier.
fune!(dates.days-between@^1);  // then call days_between(…)
dates.month-boundaries core
First and last day of a date's month, for monthly periods and statements.
The first day, last day and length of the calendar month containing a date.
fune!(dates.month-boundaries@^1);  // then call month_boundaries(…)
dates.day-of-week core
ISO weekday of a date, for weekend rules and opening hours.
The ISO 8601 day of the week for a date: 1 is Monday through 7 is Sunday.
fune!(dates.day-of-week@^1);  // then call day_of_week(…)
dates.is-leap-year optional
Whether a year is a leap year, for 365/366-day calculations.
Whether a year is a Gregorian leap year: every 4th, except centuries, except every 400th.
fune!(dates.is-leap-year@^1);  // then call is_leap_year(…)
dates.overlap optional
Days two date ranges share, for prorating and clash checks.
Days two date ranges have in common, with the end of each range stated as inclusive or exclusive.
fune!(dates.overlap@^1);  // then call overlap_days(…)

8. Periods and reporting dates from dates-basics

Put dates into the periods reports are grouped by.

dates.quarter core
Calendar and fiscal quarter of a date for any year-start month.
Calendar quarter and fiscal quarter of a date, with the fiscal year and quarter date ranges, for any start month.
fune!(dates.quarter@^1);  // then call quarter(…)
dates.week-number optional
ISO week number and week-year, for weekly reports.
ISO 8601 week number and week-numbering year of a date: weeks start Monday, week 1 holds the first Thursday.
fune!(dates.week-number@^1);  // then call week_number(…)
dates.day-count-fraction optional
Year fraction by ACT/365F, ACT/360, 30/360 or ACT/ACT, for interest periods.
Year fraction between two dates by ACT/365F, ACT/360, 30/360, 30E/360 or ACT/ACT ISDA, as an exact fraction.
fune!(dates.day-count-fraction@^1);  // then call day_count_fraction(…)

9. Working days and holidays from dates-basics

Skip weekends and public holidays when counting or adding days.

dates.bank-holidays core
UK bank holidays for a region and year, as gov.uk publishes them.
UK bank and public holidays for a region and year, as published by gov.uk, including one-off holidays.
fune!(dates.bank-holidays@^1);  // then call bank_holidays(…)
dates.add-business-days core
Moves a date by working days, skipping weekends and a holiday list.
Move a date forward or back by working days, skipping weekends and a caller-supplied holiday list.
fune!(dates.add-business-days@^1);  // then call add_business_days(…)
dates.business-days-between core
Working days between two dates, for SLAs and notice periods.
Working days between two dates, excluding weekends and a caller-supplied holiday list.
fune!(dates.business-days-between@^1);  // then call business_days_between(…)

10. Repeating schedules from dates-basics

Generate the dates of something that repeats.

dates.recurrence optional
The next n dates of a rule: monthly on the 31st, last Friday, every two weeks.
The next n dates of a repeating rule: monthly on a day, last weekday of the month, every k days or weeks, yearly.
fune!(dates.recurrence@^1);  // then call recurrence(…)

11. Times and durations from dates-basics

Work with times of day, durations and timestamps.

time.duration optional
Parses and adds durations like 1h30m in whole minutes, and formats the total.
Parse durations written as 1h30m, 90m or 01:30, add them up in whole minutes, and format the total.
fune!(time.duration@^1);  // then call duration(…)
time.minutes-between optional
Minutes between two local date-times, across midnight.
Minutes from one local date and time to another, correct across midnight; wall-clock time, no time zones.
fune!(time.minutes-between@^1);  // then call minutes_between(…)
time.round-to-increment optional
Rounds minutes to a billing increment such as 6 or 15.
Round a duration in minutes to a billing increment such as 6 or 15 minutes, up, down or to nearest.
fune!(time.round-to-increment@^1);  // then call round_to_increment(…)
time.iso-to-unix optional
RFC 3339 timestamps to Unix seconds.
An RFC 3339 timestamp with a Z or offset, such as 2026-09-26T13:00:00+01:00, to Unix time in whole seconds.
fune!(time.iso-to-unix@^1);  // then call iso_to_unix(…)
time.unix-to-iso optional
Unix seconds to an ISO 8601 UTC timestamp.
Unix time in seconds to an ISO 8601 UTC timestamp such as 2026-09-26T12:00:00Z, for years 0001 to 9999.
fune!(time.unix-to-iso@^1);  // then call unix_to_iso(…)
time.countdown optional
Seconds left until a moment and a 4:05 style timer text.
Seconds left until a Unix time, whether it has passed, and a timer text like 4:05, for tokens or retry waits.
fune!(time.countdown@^1);  // then call countdown(…)

Gaps

What this kind of app usually needs that Functional Weave does not have yet: write these yourself, or use a service.

  • safeguarding Safeguarding records, parental contacts and consent are yours, with their data protection duties.
  • learning-content Course content, quizzes and an LMS (SCORM, video) are not in caps.
  • time-zones Time zones and daylight saving: caps works in ISO dates, UTC and wall-clock times; converting with the IANA tz rules is yours.
  • locale-formatting Showing dates in a user's language and format ("3 octobre 2026"): caps returns ISO dates, not localised text.
  • non-uk-holidays Public holidays outside the UK: dates.bank-holidays is UK only; pass another country's list to the working-day functions yourself.