Skip to content

Days of cover

If demand continues as usual, how many days will current stock last?

Current value (inventory case data): 63.1 days - ✕ Act. Open the case.

Field Value
Definition On-hand units at the last date divided by average daily demand over the window.
Formula on_hand_units(last date) / (sum(demand_units) / days)
Unit days
Granularity SKU; snapshot at period end.
Direction Inside a band ↔ (too high and too low are both bad)
Target and thresholds 14.0 days to 35.0 days (amber 7.0 days to 60.0 days)
Parameters –
Owner Supply Planner
Source Synthetic stock simulation on public demand
Input table inventory_daily, columns date, on_hand_units, demand_units
Recommended chart histogram - Distribution of SKUs by cover with the green band shaded - shows both tails.
Related KPIs Inventory turnover, Stockout rate (SKU-days), Obsolete stock share

How to read it

Too low means stockout risk before the next replenishment; too high means tied-up capital and obsolescence risk. That is why it has a band, not a direction.

Common misreadings

  • Using trailing demand for a seasonal item right before its season understates the risk.
  • A fleet-level number nets SKUs with zero cover against SKUs with a year of cover.

Worked example (from the test suite)

date on_hand_units demand_units
2024-01-01 100 10
2024-01-02 90 10
2024-01-03 60 10

Expected result: 6.00 days. Average daily demand = 30 / 3 = 10 units. Stock on the last date = 60. 60 / 10 = 6.0 days.

This example is asserted in tests/test_formulas.py against the Python function and in tests/test_sql.py against the SQL below.

Implementations

Python function (the single implementation used by the site):

@kpi("days_of_cover")
def days_of_cover(df: pd.DataFrame) -> float:
    days = df["date"].nunique()
    if not days:
        return float("nan")
    on_hand_last = df.loc[df["date"].eq(df["date"].max()), "on_hand_units"].sum()
    return safe_ratio(on_hand_last, df["demand_units"].sum() / days)

Reference SQL (tested on SQLite):

SELECT (SELECT SUM(on_hand_units) FROM inventory_daily WHERE date = (SELECT MAX(date) FROM inventory_daily))
       / (SUM(demand_units) * 1.0 / COUNT(DISTINCT date))
FROM inventory_daily