Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from .dates_days_between import days_between ← from dates.days-between ^1.0.0 · built alongside by fune
from .energy_estimate_read_types import EstimatedRead, MeterRead
from .energy_meter_advance import meter_advance ← from energy.meter-advance ^1.0.0 · built alongside by fune
from .math_round_div import RoundingMode, round_div ← from math.round-div ^1.0.0 · built alongside by fune
MAX_SAFE = 9007199254740991
def estimate_read(
earlier_read: MeterRead, latest_read: MeterRead, on_date: str, digits: int, mode: RoundingMode
) -> EstimatedRead:
"""Carry the latest read forward to ``on_date`` at the average daily
consumption between the two reads, rounding once, and wrap past all nines.
"""
consumption = meter_advance(earlier_read.value, latest_read.value, digits)
history = days_between(earlier_read.date, latest_read.date)
if history <= 0:
raise ValueError(
"the earlier read must be dated before the latest read, received %s and %s"
% (earlier_read.date, latest_read.date)
)
ahead = days_between(latest_read.date, on_date)
if ahead < 0:
raise ValueError(
"onDate must not be before the latest read, received %s and %s" % (on_date, latest_read.date)
)
product = consumption * ahead
if product > MAX_SAFE:
raise ValueError("estimate too large to calculate exactly")
units = round_div(product, history, mode)
span = 10**digits
raw = latest_read.value + units
return EstimatedRead(read=raw % span, units=units, rolled_over=raw >= span)