Skip to content

Commit 0e3d455

Browse files
committed
feat: extract checker class
1 parent 48e64ef commit 0e3d455

File tree

1 file changed

+176
-0
lines changed

1 file changed

+176
-0
lines changed

src/SegmentChecker.php

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
<?php
2+
3+
namespace Ahc\Cron;
4+
5+
/**
6+
* Cron Expression Parser.
7+
*
8+
* This class checks if a cron segment satisfies given time.
9+
*
10+
* @author Jitendra Adhikari <[email protected]>
11+
*/
12+
class SegmentChecker
13+
{
14+
public static function isDue($segment, $pos, $time)
15+
{
16+
$isDue = true;
17+
$offsets = explode(',', trim($segment));
18+
19+
foreach ($offsets as $offset) {
20+
if (null === $isDue = static::isOffsetDue($offset, $pos, $time)) {
21+
throw new \UnexpectedValueException(
22+
sprintf('Invalid offset value %s for segment #%d', $offset, $pos)
23+
);
24+
}
25+
26+
if ($isDue) {
27+
return true;
28+
}
29+
}
30+
31+
return false;
32+
}
33+
34+
/**
35+
* Check if a given offset at a position is due with respect to given time.
36+
*
37+
* @param string $offset
38+
* @param int $pos
39+
* @param array $time
40+
*
41+
* @return bool|null
42+
*/
43+
protected static function isOffsetDue($offset, $pos, $time)
44+
{
45+
if (strpos($offset, '/') !== false) {
46+
return static::inStep($time[$pos], $offset);
47+
}
48+
49+
if (strpos($offset, '-') !== false) {
50+
return static::inRange($time[$pos], $offset);
51+
}
52+
53+
if (is_numeric($offset)) {
54+
return $time[$pos] == $offset;
55+
}
56+
57+
$isModifier = strpbrk($offset, 'LCW#');
58+
59+
if ($pos === 2 && $isModifier) {
60+
return static::checkMonthDay($offset, $time);
61+
}
62+
63+
if ($pos === 4 && $isModifier) {
64+
return static::checkWeekDay($offset, $time);
65+
}
66+
}
67+
68+
protected static function inRange($value, $offset)
69+
{
70+
$parts = explode('-', $offset);
71+
72+
return $parts[0] <= $value && $value <= $parts[1];
73+
}
74+
75+
protected static function inStep($value, $offset)
76+
{
77+
if (strpos($offset, '*/') !== false || strpos($offset, '0/') !== false) {
78+
$parts = explode('/', $offset, 2);
79+
80+
return $value % $parts[1] === 0;
81+
}
82+
83+
$parts = explode('/', $offset, 2);
84+
$subparts = explode('-', $parts[0], 2) + [1 => $value];
85+
86+
return ($subparts[0] <= $value && $value <= $subparts[1] && $parts[1])
87+
? in_array($value, range($subparts[0], $subparts[1], $parts[1]))
88+
: false;
89+
}
90+
91+
/**
92+
* Check if modifiers [L C W #] are satisfied.
93+
*
94+
* @internal
95+
*
96+
* @param string $value
97+
* @param int $time
98+
*
99+
* @return bool|null
100+
*/
101+
protected static function checkMonthDay($value, $time)
102+
{
103+
$month = $time[8] < 10 ? '0' . $time[8] : $time[8];
104+
105+
if ($value == 'L') {
106+
return $time[2] == $time[6];
107+
}
108+
109+
if ($pos = strpos($value, 'W')) {
110+
$value = substr($value, 0, $pos);
111+
112+
return static::isClosestWeekDay($value, $month, $time);
113+
}
114+
}
115+
116+
protected static function isClosestWeekDay($value, $month, $time)
117+
{
118+
foreach ([0, -1, 1, -2, 2] as $i) {
119+
$incr = $value + $i;
120+
if ($incr > 0 && $incr <= $time[6]) {
121+
if ($incr < 10) {
122+
$incr = '0' . $incr;
123+
}
124+
125+
$parts = explode(' ', date('N m j', strtotime("$time[5]-$month-$incr")));
126+
if ($parts[0] < 6 && $parts[1] == $month) {
127+
return $time[2] == $parts[2];
128+
}
129+
}
130+
}
131+
}
132+
133+
/**
134+
* Check if modifiers [L C W #] are satisfied.
135+
*
136+
* @internal
137+
*
138+
* @param string $value
139+
* @param int $time
140+
*
141+
* @return bool|null
142+
*/
143+
protected static function checkWeekDay($value, $time)
144+
{
145+
$month = $time[8] < 10 ? '0' . $time[8] : $time[8];
146+
147+
if (strpos($value, 'L')) {
148+
return static::lastWeekDay($value, $month, $time);
149+
}
150+
151+
if (strpos($value, '#')) {
152+
$value = explode('#', str_replace('0#', '7#', $value));
153+
154+
if ($value[0] < 0 || $value[0] > 7 || $value[1] < 1 || $value[1] > 5 || $time[9] != $value[0]) {
155+
return false;
156+
}
157+
158+
return intval($time[7] / 7) == $value[1] - 1;
159+
}
160+
}
161+
162+
protected static function lastWeekDay($value, $month, $time)
163+
{
164+
$value = explode('L', str_replace('7L', '0L', $value));
165+
$decr = $time[6];
166+
167+
for ($i = 0; $i < 7; $i++) {
168+
$decr -= $i;
169+
if (date('w', strtotime("$time[5]-$month-$decr")) == $value[0]) {
170+
return $time[2] == $decr;
171+
}
172+
}
173+
174+
return false;
175+
}
176+
}

0 commit comments

Comments
 (0)