# 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.