Functional Weave
Code in Rust

energy.tariff-time-of-use@1.0.1

README.md

2,245 bytes · view raw

# energy.tariff-time-of-use

Prices half-hourly smart meter consumption against a time-of-use tariff and
returns the bill lines:

- **Economy 7 / Economy 10 / peak and off-peak**: rates for daily windows,
  `{ name: "night", start: "00:30", end: "07:30", rate: 12000 }`, repeating every
  day. A window may wrap past midnight (`22:00` to `05:00`), and `from = to`
  means all day.
- **Agile-style dynamic prices**: a rate for each dated interval,
  `{ name: "agile", start: "2026-03-01T16:00", end: "2026-03-01T16:30", rate: 24999 }`,
  as a supplier's price list gives them. Prices may be negative.

Both kinds can be mixed; every half hour of usage must fall in **exactly
one** rate, and an overlap or a gap is an error naming the half hour, so a
price list with a missing slot cannot silently undercharge.

## Units and rounding

- Usage is in **watt-hours** (thousandths of a kWh), the resolution smart
  meter half-hourly data comes in.
- Rates are in **thousandths of a minor unit per kWh**: 24.567p/kWh is
  `24567`. Dynamic prices are published to more places than a penny holds
  (15.4035p); thousandths keep them to within 0.0005p, which is at most a
  penny on 2,000 kWh.
- Each line is costed **exactly** (sum of watt-hours x rate over its half
  hours) and rounded **once** by `mode`; the total is the sum of the rounded
  lines, so it always matches the lines printed. Rounding each half hour
  instead drifts, by up to half a penny per half hour, 17,520 times a year.
- Lines are grouped by rate `name`, in the order names first appear in
  `rates`; a name with no usage still gets a zero line, so a bill always has
  the same lines.

## Clocks

Times are compared as written: the usage and the rates must be in the same
clock. Smart meter data is usually in UTC, and many Economy 7 meters switch
on GMT all year, so in summer their night window is an hour later in local
time. Convert one side before calling. Only the form of a date is checked
(`YYYY-MM-DD`), not that it exists.

## Bounds

A line's exact cost (watt-hours x rate) must stay within 2^53 millionths of
a minor unit, about 300 GWh at 30p/kWh.

1.0.1 fixes Python accepting a trailing newline or non-ASCII digits in usage and rate start and end times; adds tests.