Functional Weave
Code in TypeScript

energy.estimate-read@1.0.0

impl/typescript.ts

1,415 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { daysBetween } from "./dates_days_between.ts";  ← from dates.days-between ^1.0.0 · built alongside by fune
import { meterAdvance } from "./energy_meter_advance.ts";  ← from energy.meter-advance ^1.0.0 · built alongside by fune
import { type RoundingMode, roundDiv } from "./math_round_div.ts";  ← from math.round-div ^1.0.0 · built alongside by fune
import { type EstimatedRead, type MeterRead } from "./energy_estimate_read_types.ts";

/**
 * Carry the latest read forward to `onDate` at the average daily consumption
 * between the two reads, rounding once, and wrap past all nines.
 */
export function estimateRead(
  earlierRead: MeterRead,
  latestRead: MeterRead,
  onDate: string,
  digits: number,
  mode: RoundingMode
): EstimatedRead {
  const consumption = meterAdvance(earlierRead.value, latestRead.value, digits);
  const history = daysBetween(earlierRead.date, latestRead.date);
  if (history <= 0) {
    throw new RangeError(`the earlier read must be dated before the latest read, received ${earlierRead.date} and ${latestRead.date}`);
  }
  const ahead = daysBetween(latestRead.date, onDate);
  if (ahead < 0) {
    throw new RangeError(`onDate must not be before the latest read, received ${onDate} and ${latestRead.date}`);
  }
  const product = consumption * ahead;
  if (product > Number.MAX_SAFE_INTEGER) {
    throw new RangeError("estimate too large to calculate exactly");
  }
  const units = roundDiv(product, history, mode);
  const span = 10 ** digits;
  const raw = latestRead.value + units;
  return { read: raw % span, units, rolledOver: raw >= span };
}