Skip to content

Benchmarks

Karthik P edited this page Oct 26, 2026 · 6 revisions

Benchmarks compare workclock (Rust, Python and JavaScript) with businesstimedelta 1.0.1 and with a loop written by hand with each language's standard library, on three cases, all with one schedule: Europe/London, Monday to Friday 09:00–17:00, a 12:00–13:00 break and the bank holidays of England in 2026 and 2027.

  • single: between across 5½ hours on one Tuesday.
  • year: between from 2026-01-01 to 2027-01-01.
  • batch: between for 1,000,000 pairs of up to a week each.

The standard-library loops use datetime and zoneinfo in Python and Temporal in JavaScript, which Node.js 26 turns on by default. They walk the local dates of a span and add each working day's overlap, for this one schedule only. Tests check them against workclock, so every speed-up compares code that gives the same answers.

Results

Medians from GitHub Actions run 40285792116 on 2026-10-26, on a GitHub-hosted Ubuntu runner (AMD EPYC 7763, 4 logical cores, 16 GiB) with Rust 1.99.1, Python 3.15.1 and Node.js 26.12.1:

Case Rust JavaScript Python workclock.compat Python stdlib JavaScript stdlib businesstimedelta 1.0.1
single 1.19 µs 1.77 µs 3.96 µs 7.24 µs 4.01 µs 9.06 µs 169 µs
year 84.5 µs 106 µs 85.4 µs 88.7 µs 719 µs 1.71 ms 53 ms
batch 1.96 s 2.54 s 2.13 s 7.99 s 9.95 s 38.3 s 9.9 min

The batch row uses betweenMany on Float64Arrays in JavaScript and between_many on NumPy arrays in Python. From Python, workclock is 43× faster than businesstimedelta on single, 620× on year and 280× on batch.

Against the standard-library loop, Python's single call is level (1×): most of workclock's call goes on crossing into Rust. workclock is 8.4× faster on year and 4.7× on batch. From JavaScript it is 5.1× faster than the Temporal loop on single, 16× on year and 15× on batch.

GitHub's runners don't all have the same CPU. Three runs on 2026-10-26, on AMD EPYC 7763 and Intel Xeon 8573C runners, differed by about 20% in time, but the speed-ups over businesstimedelta stayed within about 6%. Compare the speed-ups rather than raw times. benchmarks/RESULTS.md lists every variant with its p95, and the Performance section of DESIGN.md explains the numbers.

Running them

The Benchmarks workflow runs all three suites on GitHub Actions for every v* tag, and anyone with write access can start it from the Actions tab. Its businesstimedelta-batch input adds businesstimedelta's batch case, which takes about 10 minutes there. The run's summary page shows RESULTS.md, and its benchmark-results artifact holds the file with the raw JSON. The workflow never commits; RESULTS.md changes through a pull request. The local commands are in benchmarks/README.md.

Instruction counts

CI also counts the instructions each case executes, under Valgrind: Rust with gungraun and Python with cachegrind. The count repeats from run to run, so the instructions job compares the base and head of every pull request and fails it if single or year executes over 3% more instructions. batch is only reported. See Instruction counts for the local commands.

Clone this wiki locally