74 lines
2.1 KiB
PHP
74 lines
2.1 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Support;
|
||
|
|
|
||
|
|
use Illuminate\Support\Carbon;
|
||
|
|
use InvalidArgumentException;
|
||
|
|
|
||
|
|
class DateRange
|
||
|
|
{
|
||
|
|
public const MAX_DAYS = 731;
|
||
|
|
|
||
|
|
public function __construct(
|
||
|
|
public readonly Carbon $from,
|
||
|
|
public readonly Carbon $to,
|
||
|
|
) {
|
||
|
|
if ($to->lessThan($from)) {
|
||
|
|
throw new InvalidArgumentException('The end of a date range cannot precede its start.');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function preset(string $preset): self
|
||
|
|
{
|
||
|
|
$now = Carbon::now();
|
||
|
|
|
||
|
|
return match ($preset) {
|
||
|
|
'today' => new self($now->copy()->startOfDay(), $now->copy()->endOfDay()),
|
||
|
|
'week' => new self($now->copy()->startOfWeek(), $now->copy()->endOfWeek()),
|
||
|
|
'month' => new self($now->copy()->startOfMonth(), $now->copy()->endOfMonth()),
|
||
|
|
'year' => new self($now->copy()->startOfYear(), $now->copy()->endOfYear()),
|
||
|
|
'all' => new self(Carbon::createFromTimestamp(0), $now->copy()->endOfDay()),
|
||
|
|
default => throw new InvalidArgumentException("Unknown date range preset [{$preset}]."),
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @return array<string, string>
|
||
|
|
*/
|
||
|
|
public static function presets(): array
|
||
|
|
{
|
||
|
|
return [
|
||
|
|
'today' => 'Today',
|
||
|
|
'week' => 'This Week',
|
||
|
|
'month' => 'This Month',
|
||
|
|
'year' => 'This Year',
|
||
|
|
'all' => 'All Time',
|
||
|
|
];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Every day the range touches, as Y-m-d, so callers can zero-fill empty buckets.
|
||
|
|
*
|
||
|
|
* @return array<int, string>
|
||
|
|
*/
|
||
|
|
public function days(): array
|
||
|
|
{
|
||
|
|
$days = [];
|
||
|
|
$cursor = $this->from->copy()->startOfDay();
|
||
|
|
$last = $this->to->copy()->startOfDay();
|
||
|
|
|
||
|
|
if ($cursor->diffInDays($last) >= self::MAX_DAYS) {
|
||
|
|
throw new InvalidArgumentException(
|
||
|
|
'A range wider than '.self::MAX_DAYS.' days cannot be bucketed by day; bucket by month instead.'
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
while ($cursor->lessThanOrEqualTo($last)) {
|
||
|
|
$days[] = $cursor->toDateString();
|
||
|
|
$cursor->addDay();
|
||
|
|
}
|
||
|
|
|
||
|
|
return $days;
|
||
|
|
}
|
||
|
|
}
|