6
6
7
7
trait DateScopes
8
8
{
9
+ /**
10
+ * For example, if you subtract one month from March 31, you would get February 31, which is not a valid date.
11
+ * The subMonthsNoOverflow method for instance would instead return February 28 (or February 29 in a leap year),
12
+ * as it adjusts the day to the last day of the month when the resulting date would be invalid.
13
+ *
14
+ * In Carbon, the date units that can have this "overflow" behavior are months, years, decades, etc. because their lengths can vary.
15
+ * Days, hours, minutes, and seconds have fixed lengths, so they do not have this issue.
16
+ *
17
+ * @var array|string[]
18
+ */
19
+ private array $ fixedLengthDateUnits = [
20
+ 'second ' ,
21
+ 'minute ' ,
22
+ 'hour ' ,
23
+ 'day '
24
+ ];
25
+
9
26
/**
10
27
* @param Builder $query Eloquent Builder
11
28
* @param string $dateUnit A valid date unit, such as hour, day, month, year etc...
@@ -21,23 +38,25 @@ public function scopeOfLastUnit(Builder $query, string $dateUnit, int $value, Da
21
38
22
39
$ startFunc = 'startOf ' .ucfirst ($ dateUnit );
23
40
$ endFunc = 'endOf ' .ucfirst ($ dateUnit );
24
- $ subFunc = 'sub ' .ucfirst ($ dateUnit ).'s ' ;
41
+
42
+ $ applyNoOverflow = (in_array ($ dateUnit , $ this ->fixedLengthDateUnits )) ? 'NoOverflow ' : '' ;
43
+ $ subFunc = 'sub ' .ucfirst ($ dateUnit ).'s ' .$ applyNoOverflow ;
25
44
26
45
$ sub = ($ dateUnit === 'second ' ) ? 0 : 1 ;
27
46
28
47
if ($ dateRange === DateRange::EXCLUSIVE ) {
29
48
$ range = [
30
- 'from ' => now ()->$ startFunc ( )->$ subFunc ( $ value ),
31
- 'to ' => now ()->$ endFunc ( )->$ subFunc ( $ sub ),
49
+ 'from ' => now ()->$ subFunc ( $ value )->$ startFunc ( ),
50
+ 'to ' => now ()->$ subFunc ( $ sub )->$ endFunc ( ),
32
51
];
33
52
} else {
34
53
$ range = [
35
- 'from ' => now ()->$ startFunc ()-> $ subFunc ($ value - $ sub ),
54
+ 'from ' => now ()->$ subFunc ($ value - $ sub)-> $ startFunc ( ),
36
55
'to ' => now ()->$ endFunc (),
37
56
];
38
57
}
39
58
40
- // dd(collect($range)->transform(fn ($item) => $item->format('Y-m-d H:i:s')));
59
+ // dd(collect($range)->transform(fn ($item) => $item->format('Y-m-d H:i:s'))->toArray() );
41
60
42
61
return $ query ->whereBetween (config ('date-scopes.created_column ' ), $ range );
43
62
}
0 commit comments