Skip to content

Commit

Permalink
use sub no overflow for all non-fixed date units and also first sub a…
Browse files Browse the repository at this point in the history
…nd then set to start/end, which guarantees a right start/end range
  • Loading branch information
Sairahcaz committed Apr 14, 2023
1 parent 95589ad commit 9df28bf
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 8 deletions.
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ The default for this package is **exclusive** approach,
which means when you for instance query for the last 7 days it will **not include** the current day!
You can change the default if you need in the published config file.

### Config
### Global configuration

You can publish the config file with:

Expand All @@ -55,7 +55,7 @@ return [
/**
* If you want to include the current day/week/month/year etc. in the range,
* you could use the inclusive range here as a default.
* Note that you can also optionally specify it for quite every scope we offer
* Note that you can also fluently specify the range for quite every scope we offer
* directly when using the scope:
* Transaction::ofLast7Days(DateRange::INCLUSIVE); (this works for all but the singular "ofLast"-scopes)
* This will do an inclusive query, even though the global default range here is set to exclusive.
Expand All @@ -71,6 +71,20 @@ return [

If you want to change the default range to inclusive set `DATE_SCOPES_DEFAULT_RANGE=inclusive` in your `.env`.

### Fluent configuration

As already mentioned above in the `default_range` config description text,
you can also fluently specify the range for quite every scope we offer
directly when using the scope:

```php
// This works for all "ofLast"-scopes, expect the singulars like "ofLastHour",
// because it would not make sense for those.
Transaction::ofLast7Days(DateRange::INCLUSIVE);
```

This will do an inclusive query (today-6 days), even though the global default range here was set to exclusive.

## Scopes

- [`seconds`](#seconds)
Expand Down
2 changes: 1 addition & 1 deletion config/date-scopes.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/**
* If you want to include the current day/week/month/year etc. in the range,
* you could use the inclusive range here as a default.
* Note that you can also optionally specify it for quite every scope we offer
* Note that you can also fluently specify it for quite every scope we offer
* directly when using the scope:
* Transaction::ofLast7Days(DateRange::INCLUSIVE); (this works for all but the singular "ofLast"-scopes)
* This will do an inclusive query, even though the global default range here is set to exclusive.
Expand Down
29 changes: 24 additions & 5 deletions src/DateScopes.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@

trait DateScopes
{
/**
* For example, if you subtract one month from March 31, you would get February 31, which is not a valid date.
* The subMonthsNoOverflow method for instance would instead return February 28 (or February 29 in a leap year),
* as it adjusts the day to the last day of the month when the resulting date would be invalid.
*
* In Carbon, the date units that can have this "overflow" behavior are months, years, decades, etc. because their lengths can vary.
* Days, hours, minutes, and seconds have fixed lengths, so they do not have this issue.
*
* @var array|string[]
*/
private array $fixedLengthDateUnits = [
'second',
'minute',
'hour',
'day'
];

/**
* @param Builder $query Eloquent Builder
* @param string $dateUnit A valid date unit, such as hour, day, month, year etc...
Expand All @@ -21,23 +38,25 @@ public function scopeOfLastUnit(Builder $query, string $dateUnit, int $value, Da

$startFunc = 'startOf'.ucfirst($dateUnit);
$endFunc = 'endOf'.ucfirst($dateUnit);
$subFunc = 'sub'.ucfirst($dateUnit).'s';

$applyNoOverflow = (in_array($dateUnit, $this->fixedLengthDateUnits)) ? 'NoOverflow' : '' ;
$subFunc = 'sub'.ucfirst($dateUnit).'s'.$applyNoOverflow;

$sub = ($dateUnit === 'second') ? 0 : 1;

if ($dateRange === DateRange::EXCLUSIVE) {
$range = [
'from' => now()->$startFunc()->$subFunc($value),
'to' => now()->$endFunc()->$subFunc($sub),
'from' => now()->$subFunc($value)->$startFunc(),
'to' => now()->$subFunc($sub)->$endFunc(),
];
} else {
$range = [
'from' => now()->$startFunc()->$subFunc($value - $sub),
'from' => now()->$subFunc($value - $sub)->$startFunc(),
'to' => now()->$endFunc(),
];
}

// dd(collect($range)->transform(fn ($item) => $item->format('Y-m-d H:i:s')));
// dd(collect($range)->transform(fn ($item) => $item->format('Y-m-d H:i:s'))->toArray());

return $query->whereBetween(config('date-scopes.created_column'), $range);
}
Expand Down

0 comments on commit 9df28bf

Please sign in to comment.