-
-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathTicks.php
More file actions
97 lines (83 loc) · 2.54 KB
/
Ticks.php
File metadata and controls
97 lines (83 loc) · 2.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<?php
declare(strict_types=1);
/*
* This file is part of the PHP-CRON-EXPR package.
*
* (c) Jitendra Adhikari <jiten.adhikary@gmail.com>
* <https://github.com/adhocore>
*
* Licensed under MIT license.
*/
namespace Ahc\Cron;
use DateTime;
/**
* Ticks for next/prev ticks of an expr based on given time.
* Next tick support is experimental.
* Prev tick is not yet implemented.
*/
class Ticks
{
/** @var Expression */
protected $expr;
protected $limits = [
ReferenceTime::MINUTE => 60,
ReferenceTime::HOUR => 24,
ReferenceTime::MONTHDAY => 31,
ReferenceTime::MONTH => 12,
ReferenceTime::WEEKDAY => 366,
ReferenceTime::YEAR => 100,
];
public function __construct(Expression $expr)
{
$this->expr = $expr;
}
public function next(string $expr, $time = null): DateTime
{
$checker = $this->expr->segmentChecker();
$segments = $this->expr->segments($expr);
$iter = 500;
$ref = new ReferenceTime($time);
$ref->add(60 - $ref->timestamp % 60); // truncate seconds
over:
while ($iter > 0) {
$iter--;
foreach ($segments as $pos => $seg) {
if ($seg === '*' || $seg === '?') {
continue;
}
[$new, $isOk] = $this->bumpUntilDue($checker, $seg, $pos, $ref);
if ($isOk) {
$ref = $new;
goto over;
}
}
}
$date = $ref->dateTime();
if ($this->expr->segmentsDue($segments, $date)) {
return $date;
}
throw new \RuntimeException('Tried so hard');
}
private function bumpUntilDue(SegmentChecker $checker, string $seg, int $pos, ReferenceTime $ref): array
{
$iter = $this->limits[$pos];
while ($iter > 0) {
$iter--;
if ($checker->setReference($ref)->checkDue($seg, $pos)) {
return [$ref, true];
}
if ($pos === ReferenceTime::MINUTE) {
$ref->add(60);
} elseif ($pos === ReferenceTime::HOUR) {
$ref->add(3600);
} elseif ($pos === ReferenceTime::MONTHDAY || $pos === ReferenceTime::WEEKDAY) {
$ref->add(86400);
} elseif ($pos === ReferenceTime::MONTH) {
$ref->addMonth();
} elseif ($pos === ReferenceTime::YEAR) {
$ref->addYear();
}
}
return [$ref, false];
}
}