Repository navigation
Getting Started
Status: pre-1.0; the API may still change in a minor release.
| Channel | Install |
|---|---|
| Rust | cargo add workclock jiff |
| Python (pip) | pip install workclock |
| Python (uv) | uv add workclock |
| JavaScript | npm i workclock |
The Rust API takes and returns jiff 0.2 types, so Rust code depends on jiff too.
Each quickstart models a support desk in London that works 09:00–17:00 on weekdays with a lunch hour and is closed on 25 and 28 December 2026. A ticket opened at 16:30 on Christmas Eve with an 8-hour SLA is due at 09:30 on 30 December.
use jiff::civil::{date, time};
use jiff::{SignedDuration, Zoned};
use workclock::{Break, Holidays, Schedule, Weekdays, WorkDay};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let support = Schedule::builder()
.time_zone("Europe/London")
.rule(WorkDay::new(time(9, 0, 0, 0), time(17, 0, 0, 0), Weekdays::MON_TO_FRI))
.rule(Break::new(time(12, 0, 0, 0), time(13, 0, 0, 0), Weekdays::MON_TO_FRI))
.rule(Holidays::new([date(2026, 12, 25), date(2026, 12, 28)]))
.build()?;
let opened: Zoned = "2026-12-24T16:30[Europe/London]".parse()?;
let due = support.add(&opened, SignedDuration::from_hours(8))?;
assert_eq!(due.to_string(), "2026-12-30T09:30:00Z");
let now: Zoned = "2026-12-29T11:00[Europe/London]".parse()?;
assert_eq!(support.between(&opened, &now), SignedDuration::from_mins(150));
Ok(())
}from datetime import date, datetime, time
from zoneinfo import ZoneInfo
from workclock import Break, Holidays, Schedule, WorkDay
london = ZoneInfo("Europe/London")
support = Schedule(
[
WorkDay(time(9), time(17)), # Monday to Friday by default
Break(time(12), time(13)),
Holidays([date(2026, 12, 25), date(2026, 12, 28)]),
],
time_zone=london,
)
opened = datetime(2026, 12, 24, 16, 30, tzinfo=london)
support.add(opened, hours=8) # 2026-12-30 09:30, London time
support.between(opened, datetime(2026, 12, 29, 11, tzinfo=london)) # 2:30:00between_many, add_many and sub_many take lists or NumPy arrays and
process them in one call. Most code written for businesstimedelta runs
unchanged with import workclock.compat as businesstimedelta;
Migrating from businesstimedelta lists where it differs.
import { Schedule } from "workclock";
const support = new Schedule({
timeZone: "Europe/London",
rules: [
{ type: "workday", start: "09:00", end: "17:00" },
{ type: "break", start: "12:00", end: "13:00" },
{ type: "holidays", dates: ["2026-12-25", "2026-12-28"] },
],
});
support.add("2026-12-24T16:30:00Z", 8 * 3_600_000); // Date 2026-12-30T09:30:00.000Z
support.between("2026-12-24T16:30:00Z", new Date("2026-12-29T11:00:00Z")); // 9000000 msInstants are Dates or ISO 8601 strings with an offset; durations are
milliseconds. In browsers without a bundler, import the default init from
workclock/web and await init() first.
Longer programs: Rust, Python and JavaScript.
workclock is MIT licensed. The repository documentation is authoritative; this wiki summarises it.