Period comparison
Value and Progress metrics can compute period-over-period change. withChangeAgainstPreviousPeriod() compares against the immediately-preceding window:
use App\Models\User;
use RoundlyConsulting\Metrics\Enums\Period;
use RoundlyConsulting\Metrics\Facades\Metrics;
Metrics::value()
->count(User::query())
->range(Period::Today)
->withChangeAgainstPreviousPeriod() // vs. yesterday
->toArray();
// result => ['value' => 42.0, 'previous' => 30.0, 'change' => ['percentage' => 40.0, 'is_increase' => true]]The previous window
| Range | Compared against |
|---|---|
7 … 365 | The N days before the current window |
TODAY, YESTERDAY | The day before |
WTD, MTD, QTD, YTD | The same elapsed span of the previous week, month, quarter or year |
THIS_WEEK … THIS_YEAR | The whole previous week, month, quarter or year |
LAST_WEEK … LAST_YEAR | The period before that |
CUSTOM | A window of exactly the same length that ends one second before it starts — whole days when the end is a bare date |
ALL | No comparison |
The ALL range has no bounded window, so only the value is returned.
Compare against any range
compareTo() compares against any period instead — and implies withChangeAgainstPreviousPeriod(). The comparison period resolves as-is, in the metric’s timezone:
use RoundlyConsulting\Metrics\Enums\Period;
Metrics::value()
->count(Order::query())
->range(Period::ThisMonth)
->compareTo(Period::LastYear) // vs. the whole previous calendar year
->toArray();
// The same month a year ago — an explicit custom window
Metrics::value()
->count(Order::query())
->range(Period::ThisMonth)
->compareTo(Period::Custom, '2025-09-01 00:00:00', '2025-09-30 23:59:59')
->toArray();Progress change
Progress metrics add the previous value’s progress and a change block with the percentage change and the deltas in value and in progress points — a ProgressResult is also a ValueResult, so change() returns the percentage:
Metrics::progress()
->sum(Order::query(), 'total')
->target(10000)
->range(Period::MonthToDate)
->withChangeAgainstPreviousPeriod()
->toArray();
// result => [
// 'value' => 8200.0, 'progress' => 82.0,
// 'previous' => 6500.0, 'previous_progress' => 65.0,
// 'target' => 10000.0, 'avoid' => false,
// 'change' => ['percentage' => 26.0, 'is_increase' => true, 'progress' => 17.0, 'value' => 1700.0],
// ]The change percentage is measured against the size of the previous value, so its sign always follows the direction of the change: from -100 to -50 is +50. From a previous value of zero it is 100 for a rise, -100 for a fall and 0 when the value stays at zero. change.is_increase is true when the current value exceeds the previous one. Without a comparison, previous, change.percentage and change.is_increase are null — on a progress metric every change field is.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.