manufacturing.takt-time
Takt time: available production time divided by customer demand, exact and in whole seconds.
1.0.0 · published 2026-10-03 by charlie · Anterra
Pinned by 14 tests, run in TypeScript, Python and Rust.
What it does
Takt time is the pace a line must work at to meet demand:
takt = available time / customer demand
For example
takt_time(27,000, 450, down)→ exact …, seconds 60 an 8-hour shift less two 15-minute breaks (27000 s) for 450 units is 60 stakt_time(27,000, 400, down)→ exact …, seconds 67 27000 s for 400 units is exactly 67.5 s; down keeps pace at 67takt_time(27,000, 400, half-up)→ exact …, seconds 68 67.5 s rounds half-up to 68
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 takt_time(available_seconds: i64, demand: i64, mode: &str) -> TaktTime
| available_seconds | int | working time in the period, after breaks and planned stops |
| demand | int | units the customer needs in the same period, more than zero |
| mode | RoundingMode | how the exact takt becomes whole seconds; down never falls behind demand |
| returns | TaktTime |
The type it declares, generated into your project
/// The exact takt as a fraction of seconds, and the same rounded to whole seconds.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TaktTime {
/// seconds per unit, reduced
pub exact: Rational,
/// seconds per unit, rounded by mode
pub seconds: i64,
}
Your code names it in one line, in the file that uses it
fune!(manufacturing.takt-time@^1); // then call takt_time(…)
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::math_rational::{rational, rational_to_integer, rational_to_value}; ← from math.rational ^1.0.0 · built alongside by fune
const MAX_SAFE: i64 = (1i64 << 53) - 1;
/// Takt time, available time / demand, as an exact fraction and in whole
/// seconds. The whole seconds are rounded once from the exact fraction, so a
/// caller balancing a line on `exact` never inherits a rounding step.
///
/// # Panics
/// Panics on negative available time, demand that is not positive, or an
/// unknown rounding mode.
pub fn takt_time(available_seconds: i64, demand: i64, mode: &str) -> TaktTime {
if !(0..=MAX_SAFE).contains(&available_seconds) {
panic!(
"availableSeconds must be a whole number of seconds, not negative, received {}",
available_seconds
);
}
if !(1..=MAX_SAFE).contains(&demand) {
panic!("demand must be a whole number of units greater than zero, received {}", demand);
}
let exact = rational(available_seconds, demand);
let seconds = rational_to_integer(&exact, mode);
TaktTime { exact, seconds }
}
pub fn takt_time_to_value(result: &TaktTime) -> Value {
Value::obj(vec![
("exact", rational_to_value(&result.exact)),
("seconds", Value::Int(result.seconds)),
])
}
pub fn fune_vector(args: &[Value]) -> Value {
if let Value::Float(f) = &args[0] {
panic!("availableSeconds must be a whole number of seconds, not negative, received {}", f);
}
if let Value::Float(f) = &args[1] {
panic!("demand must be a whole number of units greater than zero, received {}", f);
}
takt_time_to_value(&takt_time(args[0].as_i64(), args[1].as_i64(), args[2].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 manufacturing.takt-time
The manifest, vectors and README with only the Rust implementation. Install it without the registry with fune add ./manufacturing.takt-time-1.0.0-rust.fune, or fetch it from a terminal with fune pull manufacturing.takt-time@1.0.0:rust.
The whole function, every language, is one file too: manufacturing.takt-time-1.0.0.fune, 9,998 bytes, sha256 fd7d347610f0d78c840a26ef782ce2053b081d4bf02cd41df8ded064c3afccb7. 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 manufacturing.takt-time
after — your function gets the result and the arguments, and returns the final result.
// fune: after manufacturing.takt-time
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 math.rational in manufacturing.takt-time
// fune: replace math.round-div in manufacturing.takt-time
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 manufacturing.takt-time --steps.
// fune: step manufacturing.takt-time 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.
| Case | Arguments | Expected | |
|---|---|---|---|
| an 8-hour shift less two 15-minute breaks (27000 s) for 450 units is 60 s | 27,000, 450, down | → | exact …, seconds 60 |
| 27000 s for 400 units is exactly 67.5 s; down keeps pace at 67 | 27,000, 400, down | → | exact …, seconds 67 |
| 67.5 s rounds half-up to 68 | 27,000, 400, half-up | → | exact …, seconds 68 |
| 67.5 s rounds half-even to 68 (68 is even) | 27,000, 400, half-even | → | exact …, seconds 68 |
| an exact half on an even second: 26 s over 4 units is 6.5, half-even goes down to 6 | 26, 4, half-even | → | exact …, seconds 6 |
| 27000 s for 460 units is 1350/23 = 58.70 s; half-up gives 59 | 27,000, 460, half-up | → | exact …, seconds 59 |
| 1350/23 rounds down to 58 | 27,000, 460, down | → | exact …, seconds 58 |
| two shifts over a 5-day week: 270000 s for 4800 units is 56.25 s, up gives 57 | 270,000, 4,800, up | → | exact …, seconds 57 |
| demand larger than the seconds available: takt under one second | 3,600, 7,200, half-up | → | exact …, seconds 1 |
| no available time gives a takt of zero | 0, 100, down | → | exact …, seconds 0 |
Show the other 4 tests
| Case | Arguments | Expected | |
|---|---|---|---|
| zero demand is an error | 27,000, 0, down | → | error: demand must be a whole number of units greater than zero |
| negative available time is an error | -1, 10, down | → | error: availableSeconds must be a whole number of seconds, not negative |
| fractional demand is an error | 27,000, 2.5, down | → | error: demand must be a whole number of units greater than zero |
| an unknown rounding mode is an error | 27,000, 400, nearest | → | error: unknown rounding mode |
More from the author
An 8-hour shift less two 15-minute breaks is 27,000 seconds; with a demand of 450 units that is one unit every 60 seconds.
**Exact first, then rounded once.** The answer is returned twice: `exact`, the reduced fraction of seconds (27,000 / 400 is `135/2`), and `seconds`, that fraction rounded to whole seconds by the mode you choose. Keep `exact` for line balancing (dividing takt among stations or comparing it with cycle times) so no rounding compounds; use `seconds` for the board on the shop floor.
**Which mode.** `down` is the safe choice for a pace: a takt rounded up (67.5 s to 68 s) makes 397 units in the shift, not 400. `half-up` and `half-even` give the nearest second; `up` is there for completeness.
**Available time is the caller's.** Pass the time the line is actually planned to run in the period (shift length less breaks, meetings and planned maintenance), in seconds, and demand for the same period. The function does no calendar arithmetic, so a week or a month works the same as a shift.
Zero available time gives a takt of 0. Demand must be more than zero (no demand means no pace to keep), and neither may be negative.
Files
| Path | Bytes |
|---|---|
| README.md | 1,279 |
| impl/python.py | 1,161 |
| impl/rust.rs | 1,676 |
| impl/typescript.ts | 999 |
| vectors.json | 2,403 |