line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
################################################################################ |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# $Id: Calendar.pm 211 2009-05-25 06:05:50Z aijaz $ |
4
|
|
|
|
|
|
|
# |
5
|
|
|
|
|
|
|
################################################################################ |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 NAME |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
TaskForest::Calendar -- |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 SYNOPSIS |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
use TaskForest::LocalTime; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = &LocalTime::localtime(); |
16
|
|
|
|
|
|
|
# |
17
|
|
|
|
|
|
|
# THE MONTH IS 1-BASED, AND THE YEAR IS THE FULL YEAR |
18
|
|
|
|
|
|
|
# (i.e., $mon++; $year += 1900; is not required) |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
&LocalTime::setTime({ year => $year, |
21
|
|
|
|
|
|
|
month => $mon, |
22
|
|
|
|
|
|
|
day => $day, |
23
|
|
|
|
|
|
|
hour => $hour, |
24
|
|
|
|
|
|
|
min => $min, |
25
|
|
|
|
|
|
|
sec => $sec, |
26
|
|
|
|
|
|
|
tz => $tz |
27
|
|
|
|
|
|
|
}); |
28
|
|
|
|
|
|
|
# ... |
29
|
|
|
|
|
|
|
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = &LocalTime::localtime(); |
30
|
|
|
|
|
|
|
# |
31
|
|
|
|
|
|
|
# THE MONTH IS 1-BASED, AND THE YEAR IS THE FULL YEAR |
32
|
|
|
|
|
|
|
# (i.e., $mon++; $year += 1900; is not required) |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
=head1 DOCUMENTATION |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
If you're just looking to use the taskforest application, the only |
37
|
|
|
|
|
|
|
documentation you need to read is that for TaskForest. You can do this |
38
|
|
|
|
|
|
|
either of the two ways: |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
perldoc TaskForest |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
OR |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
man TaskForest |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=head1 DESCRIPTION |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
This is a simple package that provides support for Calendar functions |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head1 METHODS |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=cut |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
package TaskForest::Calendar; |
55
|
94
|
|
|
94
|
|
15254
|
use strict; |
|
94
|
|
|
|
|
201
|
|
|
94
|
|
|
|
|
7817
|
|
56
|
94
|
|
|
94
|
|
764
|
use warnings; |
|
94
|
|
|
|
|
354
|
|
|
94
|
|
|
|
|
4191
|
|
57
|
94
|
|
|
94
|
|
739
|
use Carp; |
|
94
|
|
|
|
|
169
|
|
|
94
|
|
|
|
|
7581
|
|
58
|
94
|
|
|
94
|
|
5284
|
use DateTime; |
|
94
|
|
|
|
|
597440
|
|
|
94
|
|
|
|
|
2153
|
|
59
|
94
|
|
|
94
|
|
3153
|
use Time::Local; |
|
94
|
|
|
|
|
5105
|
|
|
94
|
|
|
|
|
5383
|
|
60
|
94
|
|
|
94
|
|
564
|
use Data::Dumper; |
|
94
|
|
|
|
|
200
|
|
|
94
|
|
|
|
|
5912
|
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
BEGIN { |
63
|
94
|
|
|
94
|
|
497
|
use vars qw($VERSION); |
|
94
|
|
|
|
|
205
|
|
|
94
|
|
|
|
|
7975
|
|
64
|
94
|
|
|
94
|
|
146692
|
$VERSION = '1.30'; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
my $time_offset = 0; |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------ |
71
|
|
|
|
|
|
|
=pod |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=over 4 |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=item setTime() |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
Usage : &LocalTime::setTime({ year => $year, |
78
|
|
|
|
|
|
|
month => $mon, |
79
|
|
|
|
|
|
|
day => $day, |
80
|
|
|
|
|
|
|
hour => $hour, |
81
|
|
|
|
|
|
|
min => $min, |
82
|
|
|
|
|
|
|
sec => $sec, |
83
|
|
|
|
|
|
|
tz => $tz |
84
|
|
|
|
|
|
|
}); |
85
|
|
|
|
|
|
|
Purpose : This method 'sets' the current time to the time specified, in the |
86
|
|
|
|
|
|
|
timezone specified. |
87
|
|
|
|
|
|
|
Returns : Nothing |
88
|
|
|
|
|
|
|
Argument : A hash of values |
89
|
|
|
|
|
|
|
Throws : Nothing |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=back |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
=cut |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------ |
96
|
|
|
|
|
|
|
sub canRunToday { |
97
|
807
|
|
|
807
|
0
|
11690175
|
my $args = shift; |
98
|
|
|
|
|
|
|
|
99
|
807
|
|
|
|
|
1573
|
my $rules = $args->{rules}; |
100
|
807
|
|
|
|
|
1355
|
my $tz = $args->{tz}; |
101
|
|
|
|
|
|
|
|
102
|
807
|
|
|
|
|
2330
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = &TaskForest::LocalTime::ft($tz); |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# for each rule, see if today applies (yes or no or inconclusive). |
105
|
|
|
|
|
|
|
# default is no. |
106
|
|
|
|
|
|
|
# last matching rule that returns yes or no wins |
107
|
|
|
|
|
|
|
|
108
|
807
|
|
|
|
|
26178
|
my $today_hash = { |
109
|
|
|
|
|
|
|
sec => $sec, |
110
|
|
|
|
|
|
|
min => $min, |
111
|
|
|
|
|
|
|
hour => $hour, |
112
|
|
|
|
|
|
|
mday => $mday, |
113
|
|
|
|
|
|
|
mon => $mon, |
114
|
|
|
|
|
|
|
year => $year, |
115
|
|
|
|
|
|
|
wday => $wday, |
116
|
|
|
|
|
|
|
yday => $yday, |
117
|
|
|
|
|
|
|
isdst => $isdst, |
118
|
|
|
|
|
|
|
}; |
119
|
|
|
|
|
|
|
|
120
|
807
|
|
|
|
|
1689
|
my $ok = '-'; |
121
|
807
|
|
|
|
|
1591
|
foreach my $rule (@$rules) { |
122
|
892
|
|
|
|
|
1836
|
$rule =~ s/\#.*//; |
123
|
892
|
100
|
|
|
|
4060
|
next unless $rule =~ /\S/; |
124
|
815
|
|
|
|
|
1889
|
my $match = doesRuleMatch($today_hash, $rule); |
125
|
815
|
100
|
100
|
|
|
4778
|
if ($match eq '+' or $match eq '-') { |
|
|
100
|
|
|
|
|
|
126
|
89
|
|
|
|
|
210
|
$ok = $match; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
elsif ($match eq 'N/A') { |
129
|
|
|
|
|
|
|
# not applicable - do nothing |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
else { |
132
|
709
|
|
|
|
|
4225
|
return $match; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
98
|
|
|
|
|
648
|
return $ok; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub doesRuleMatch { |
141
|
815
|
|
|
815
|
0
|
1455
|
my ($today, $rule) = @_; |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# [+|-] ( [ [first | second | third | fourth | fifth] [last] DOW ] | (YYYY|*)/(MM|*)/(DD|*) ) |
144
|
|
|
|
|
|
|
# trim white space |
145
|
815
|
|
|
|
|
2814
|
$rule =~ s/^\s+//; |
146
|
815
|
|
|
|
|
3816
|
$rule =~ s/\s+$//; |
147
|
815
|
|
|
|
|
1529
|
$rule =~ tr/A-Z/a-z/; |
148
|
|
|
|
|
|
|
|
149
|
815
|
|
|
|
|
3145
|
my @components = split(/\s+/, $rule); |
150
|
815
|
50
|
|
|
|
2203
|
return "No components" unless (@components); |
151
|
|
|
|
|
|
|
|
152
|
815
|
|
|
|
|
1270
|
my $plus_or_minus = '+'; |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# if +/- isn't defined, assume it's a + |
155
|
|
|
|
|
|
|
# |
156
|
815
|
100
|
100
|
|
|
2452
|
if ($components[0] eq '+' || $components[0] eq '-') { |
157
|
789
|
|
|
|
|
1374
|
$plus_or_minus = shift(@components); |
158
|
|
|
|
|
|
|
} |
159
|
815
|
100
|
|
|
|
1642
|
return "No components after plus or minus" unless (@components); |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
|
162
|
810
|
|
|
|
|
1155
|
my $nth = undef; |
163
|
810
|
|
|
|
|
840
|
my $dow = undef; |
164
|
810
|
|
|
|
|
4868
|
my %offsets = ( first => 1, second => 2, third => 3, fourth => 4, fifth => 5, last => -1, every => 0, ); |
165
|
810
|
|
|
|
|
3848
|
my %dows = ( sun => 0 , mon => 1, tue => 2, wed => 3, thu => 4, fri => 5, sat => 6, ); |
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
# if the second item is _/_/_, then assume that there is no nth DOW |
168
|
|
|
|
|
|
|
|
169
|
810
|
100
|
|
|
|
2616
|
if (defined $offsets{$components[0]}) { |
170
|
730
|
100
|
|
|
|
1646
|
return "No components after offset" if (scalar(@components) < 2); |
171
|
|
|
|
|
|
|
|
172
|
723
|
|
|
|
|
1361
|
$nth = $offsets{$components[0]}; |
173
|
|
|
|
|
|
|
|
174
|
723
|
100
|
|
|
|
1564
|
if ($components[1] eq 'last') { |
175
|
307
|
100
|
|
|
|
753
|
$nth = ($nth > 0)? $nth * -1 : -1; |
176
|
307
|
|
|
|
|
574
|
splice(@components, 1, 1); # get rid of 'last' |
177
|
|
|
|
|
|
|
} |
178
|
723
|
100
|
|
|
|
1609
|
return "No components after offset last" if (scalar(@components) < 2); |
179
|
|
|
|
|
|
|
|
180
|
716
|
|
|
|
|
1399
|
$dow = $dows{substr($components[1], 0, 3)}; |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# now get rid of the first 2 |
183
|
716
|
|
|
|
|
10358
|
splice(@components, 0, 2); |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
796
|
|
|
|
|
1026
|
my ($y, $m, $d); |
187
|
796
|
100
|
|
|
|
1575
|
if ($components[0]) { |
188
|
698
|
|
|
|
|
951
|
my $yyyymmdd = $components[0]; |
189
|
698
|
|
|
|
|
2108
|
my ($y, $m, $d) = split(/\//, $yyyymmdd); |
190
|
|
|
|
|
|
|
|
191
|
698
|
100
|
|
|
|
1802
|
if (defined $nth) { |
192
|
618
|
100
|
|
|
|
4175
|
return "Date of month not allowed when specifying day of week" if $d; # can't have last Friday in 2009/November/1 |
193
|
226
|
|
|
|
|
349
|
$d = '*'; # do this to make the check for keep_going easier |
194
|
|
|
|
|
|
|
} |
195
|
306
|
100
|
66
|
|
|
2375
|
return "Date not specified in a valid format" unless ($y && $m && $d); |
|
|
|
66
|
|
|
|
|
196
|
|
|
|
|
|
|
|
197
|
305
|
100
|
|
|
|
649
|
if ($y ne '*') { $y *= 1; if ($y < 1970 ) { return "Invalid year"; } } |
|
249
|
100
|
|
|
|
403
|
|
|
249
|
|
|
|
|
516
|
|
|
99
|
|
|
|
|
568
|
|
198
|
206
|
100
|
66
|
|
|
500
|
if ($m ne '*') { $m *= 1; if ($m < 1 || $m > 12 ) { return "Invalid month"; } } |
|
152
|
100
|
|
|
|
201
|
|
|
152
|
|
|
|
|
680
|
|
|
99
|
|
|
|
|
608
|
|
199
|
107
|
100
|
66
|
|
|
386
|
if ($d ne '*') { $d *= 1; if ($d < 1 || $d > 31 ) { return "Invalid day"; } } |
|
16
|
100
|
|
|
|
19
|
|
|
16
|
|
|
|
|
67
|
|
|
1
|
|
|
|
|
7
|
|
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# now try to eliminate based on yyyy mm and dd |
203
|
|
|
|
|
|
|
|
204
|
106
|
|
|
|
|
131
|
my $keep_going; |
205
|
|
|
|
|
|
|
|
206
|
106
|
100
|
100
|
|
|
1211
|
if ( ($y eq '*' || $y == $today->{year}) |
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
207
|
|
|
|
|
|
|
&& |
208
|
|
|
|
|
|
|
($m eq '*' || $m == $today->{mon}) |
209
|
|
|
|
|
|
|
&& |
210
|
|
|
|
|
|
|
($d eq '*' || $d == $today->{mday}) |
211
|
|
|
|
|
|
|
) |
212
|
|
|
|
|
|
|
{ |
213
|
95
|
|
|
|
|
134
|
$keep_going = 1; |
214
|
95
|
|
|
|
|
162
|
$y = $today->{year}; |
215
|
95
|
|
|
|
|
136
|
$m = $today->{mon}; |
216
|
95
|
|
|
|
|
177
|
$d = $today->{mday}; |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
else { |
219
|
11
|
|
|
|
|
14
|
$keep_going = 0; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
106
|
100
|
|
|
|
311
|
return 'N/A' unless $keep_going; |
223
|
|
|
|
|
|
|
#return '-' unless $keep_going; |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
# now we know that the date part matches. |
226
|
|
|
|
|
|
|
# now check for the day of week part, if present |
227
|
|
|
|
|
|
|
|
228
|
95
|
100
|
66
|
|
|
470
|
if (defined $nth && defined $dow) { |
229
|
|
|
|
|
|
|
# $nth could be 0 (every) |
230
|
|
|
|
|
|
|
|
231
|
28
|
100
|
|
|
|
56
|
if ($dow == $today->{wday}) { |
232
|
|
|
|
|
|
|
# check nth. Check easy ones first |
233
|
|
|
|
|
|
|
# |
234
|
26
|
100
|
|
|
|
53
|
if ($nth == 0) { return $plus_or_minus; } |
|
2
|
|
|
|
|
11
|
|
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# find days of week |
237
|
24
|
|
|
|
|
58
|
my $dates = findDaysOfWeek($y, $m, $dow); |
238
|
|
|
|
|
|
|
|
239
|
24
|
100
|
|
|
|
59
|
if ($nth > 0) { $nth--; } # so we can use it as an array subscript |
|
13
|
|
|
|
|
16
|
|
240
|
|
|
|
|
|
|
|
241
|
24
|
100
|
100
|
|
|
71
|
return '-' if $nth == 4 and scalar(@$dates) < 5; # If the fifth dow does exist |
242
|
|
|
|
|
|
|
|
243
|
23
|
100
|
|
|
|
56
|
if ($dates->[$nth] == $today->{mday}) { |
244
|
19
|
|
|
|
|
115
|
return $plus_or_minus; |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
else { |
247
|
|
|
|
|
|
|
#return '-'; |
248
|
4
|
|
|
|
|
28
|
return 'N/A'; |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
else { |
252
|
|
|
|
|
|
|
#return '-'; |
253
|
2
|
|
|
|
|
13
|
return 'N/A'; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
else { |
257
|
67
|
|
|
|
|
380
|
return $plus_or_minus; |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
98
|
|
|
|
|
519
|
return 'Applicable date range not present'; |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# returns an array of 4 or 5 mdays, each of which correspond to the nth dow of y/m |
267
|
|
|
|
|
|
|
sub findDaysOfWeek { |
268
|
8417
|
|
|
8417
|
0
|
83144928
|
my ($y, $m, $dow) = @_; |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
# find the first dow |
271
|
|
|
|
|
|
|
#my ($sec1,$min1,$hour1,$mday1,$mon1,$year1,$wday1,$yday1,$isdst1) = localtime(timelocal(0, 0, 0, 1, $m - 1, $y - 1900)); |
272
|
8417
|
|
|
|
|
43002
|
my $dt = DateTime->new(year => $y, |
273
|
|
|
|
|
|
|
month => $m, |
274
|
|
|
|
|
|
|
day => 1, |
275
|
|
|
|
|
|
|
hour => 0, |
276
|
|
|
|
|
|
|
minute => 0, |
277
|
|
|
|
|
|
|
second => 0, |
278
|
|
|
|
|
|
|
); |
279
|
8417
|
|
|
|
|
13734533
|
my $wday1 = $dt->day_of_week; |
280
|
8417
|
100
|
|
|
|
49700
|
$wday1 = 0 if $wday1 == 7; |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
# dow $wday1 transform |
283
|
|
|
|
|
|
|
# 3 0 + 3 = 3 |
284
|
|
|
|
|
|
|
# 3 1 + (3 - 1) = 2 |
285
|
|
|
|
|
|
|
# 3 2 + (3 - 2) = 1 |
286
|
|
|
|
|
|
|
# 3 3 + (3 - 3) = 0 |
287
|
|
|
|
|
|
|
# 3 4 + (3 - 4) = -1 + 7 = 6 |
288
|
|
|
|
|
|
|
# 3 5 + (3 - 5) = -2 + 7 = 5 |
289
|
|
|
|
|
|
|
# 3 6 + (3 - 6) = -3 + 7 = 4 |
290
|
|
|
|
|
|
|
# 0 0 0 |
291
|
|
|
|
|
|
|
# 0 1 0 - 1 + 7 = 6 |
292
|
|
|
|
|
|
|
|
293
|
8417
|
|
|
|
|
15300
|
my @result = (); |
294
|
8417
|
100
|
|
|
|
35598
|
$result[0] = ($dow >= $wday1) ? $dow - $wday1 + 1 : $dow - $wday1 + 1 + 7; |
295
|
|
|
|
|
|
|
|
296
|
8417
|
|
|
|
|
36072
|
my @days_in_month = (-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); |
297
|
8417
|
100
|
100
|
|
|
26744
|
if ($m == 2 and $dt->is_leap_year()) { |
298
|
|
|
|
|
|
|
#$days_in_month[2] += ($y % 4) ? 0 : ($y % 100) ? 1 : ($y % 400) ? 0: 1; |
299
|
184
|
|
|
|
|
1780
|
$days_in_month[2] ++; |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
|
302
|
8417
|
|
|
|
|
16386
|
my $days_in_month = $days_in_month[$m]; |
303
|
|
|
|
|
|
|
|
304
|
8417
|
|
|
|
|
9759
|
my $next = 0; |
305
|
8417
|
|
|
|
|
34480
|
for (my $next = $result[0] + 7; $next <= $days_in_month; $next += 7) { |
306
|
28183
|
|
|
|
|
81466
|
push(@result, $next); |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
|
309
|
8417
|
|
|
|
|
79748
|
return (\@result); |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
1; |