Skip to content

Understanding Usage-Based Billing

In the world of cloud computing, usage-based billing is a pricing model where customers are charged based on their usage of a service. I quite like this model because it's fair. You pay for what you use, no more, no less. Let's explore this with a practical example.

Suppose you're a cloud provider charging customers for the amount of storage they use. Sounds simple? But what happens when:

  • Usage changes multiple times during the month
  • Early cancellation, what is fair to charge?
  • Storage buckets can be created and deleted at any time

A practical example

In this completely hypothetical example, let's explore how to calculate a bill for a cloud storage service that charges $0.020 per GB per month. Let's follow a customer's usage pattern for a single bucket:

Think of "Storage Usage" as an event that causes a change, like uploading or deleting files, where we can calculate the usage at that point in time. Here's a simplified timeline:

Date & Time Storage Usage
Start of month 468 GB
Feb 3, 7:00 PM 502 GB
Feb 9, 1:00 PM 570 GB
Feb 9, 3:00 PM 602 GB
Feb 18, 11:00 AM 604 GB
Feb 22, 12:00 PM Account cancelled
Feb 28, 11:59 PM End of month

How to calculate a fair bill?

Time-weighted average usage

The key is calculating a time-weighted average of usage. For this example, let's use hour as our time unit to keep thing ssimple. Note, when dealing with frequent changes, you'll want to use minutes or even seconds.

Calcualte for a full month first, then adjust for early cancellation.

  1. Break down usage into time periods (for all of February assuming 28 days):

    • 468 GB for 67 hours
    • 502 GB for 138 hours
    • 570 GB for 2 hours
    • 602 GB for 212 hours
    • 604 GB for 253 hours (until end of month)
  2. Calculate GB-hours for each period:

    • 468 × 67 = 31,356
    • 502 × 138 = 69,276
    • 570 × 2 = 1,140
    • 602 × 212 = 127,624
    • 604 × 253 = 152,812
  3. Sum up the GB-hours and divide by total hours:

    • Total GB-hours: 382,208
    • Total hours in February: 672
    • Average GB: 382,208 ÷ 672 = 568.76 GB

    Early cancellation

    Now, if the customer cancels on February 22 at noon, the calculation changes:

    • We only count hours until cancellation (516 instead of 672)
    • The last period becomes shorter (97 hours instead of 253)
    • This gives a different average: 287,984 ÷ 516 = 558.11 GB

    The beauty of this approach is that it automatically adjusts to any time period while maintaining fair billing based on actual usage patterns.

  4. Calculate the bill for both scenarios:

    Full month (through February 28):

    • Average GB = 568.76 GB (calculated from all 672 hours)
    • Daily rate = $0.020 ÷ 28 = $0.000714 per GB per day
    • Days used = 28
    • Final bill = 568.76 GB × $0.000714 × 28 = $11.38

    Partial month (cancelled February 22 at noon):

    • Average GB = 558.11 GB (calculated from 516 hours until cancellation)
    • Daily rate = $0.020 ÷ 28 = $0.000714 per GB per day
    • Days used = 21.5
    • Final bill = 558.11 GB × $0.000714 × 21.5 = $8.57

    Note, the average GB differs between scenarios because we're only considering usage up until the cancellation time in the partial month case.

Generalize

bill = (
    # First, calculate the weighted units
    (Σ(units_i × hours_i) ÷ total_hours)

    # Then, get the daily rate
    × (rate_per_month ÷ days_in_month)

    # Finally, multiply by days used
    × days_used
)

The formula can be broken down into three parts (using our February example):

  1. Time-weighted average usage: sum(units × hours) ÷ total_hours

    = 382,208 GB-hours ÷ 672 hours = 568.76 GB

    This represents average usage accounting for all changes during the month

  2. Daily rate: rate_per_month ÷ days_in_month

    = $0.020 ÷ 28 = $0.000714 per GB per day

    This converts monthly rate into a daily rate

  3. Days used (proration factor)

    • Full month: 28 days
    • If cancelled Feb 22 at noon: 21.5 days
    • This adjusts bill for partial month usage

Putting it all together:

  • Full month: 568.76 GB × $0.000714 × 28 = $11.38
  • Partial month: 558.11 GB × $0.000714 × 21.5 = $8.57

Bonus, for fun I built a simple Go package (mfridman/billing) to calculate this:

// TODO(mf): add example when the package is published

Early cancellation (or deletion of resources)

One of the most common billing scenarios is when customers cancel their service mid-month or delete resources before the end of the billing period. This can complicate billing calculations. The above formula should handle this because:

  • The total_hours in the denominator only counts hours up until cancellation
  • The days_used term prorates the monthly rate appropriately
  • The weighted average usage only considers the actual usage period

For example, if a customer cancels on February 22 at noon:

  • Instead of using all 672 hours in February, total_hours would be 516 (up until cancellation)
  • days_used would be 21.5 instead of 28
  • Usage after cancellation time is completely ignored in the calculation

This ensures customers only pay for what they actually used, both in terms of:

  • Time (through prorated days)
  • Resource consumption (through time-weighted average usage)

Useful

  • Track usage changes with precise timestamps

    • Storing raw usage data at the highest practical resolution
  • Use consistent time zones!

    • Store all timestamps in UTC internally
    • Convert to local time only for display purposes
    • Be explicit about time zones in customer-facing reports
  • Round final bills appropriately (typically to nearest cent)

  • Provide detailed usage reports whenever possible

Lastly, make sure the billing system is not just accurate, but also understandable to customers.