File Coverage

lib/Date/Manip/DM6.pm
Criterion Covered Total %
statement 291 467 62.3
branch 149 282 52.8
condition 43 63 68.2
subroutine 22 40 55.0
pod 34 34 100.0
total 539 886 60.8


line stmt bran cond sub pod time code
1             package Date::Manip::DM6;
2             # Copyright (c) 1995-2022 Sullivan Beck. All rights reserved.
3             # This program is free software; you can redistribute it and/or modify it
4             # under the same terms as Perl itself.
5              
6             ###########################################################################
7             ###########################################################################
8              
9             our (@ISA,@EXPORT);
10              
11             require 5.010000;
12             require Exporter;
13             @ISA = qw(Exporter);
14             @EXPORT = qw(
15             DateManipVersion
16             Date_Init
17             ParseDate
18             ParseDateString
19             ParseDateDelta
20             ParseDateFormat
21             ParseRecur
22             Date_IsHoliday
23             Date_IsWorkDay
24             Date_Cmp
25             DateCalc
26             UnixDate
27             Delta_Format
28             Date_GetPrev
29             Date_GetNext
30             Date_SetTime
31             Date_SetDateField
32             Events_List
33             Date_NextWorkDay
34             Date_PrevWorkDay
35             Date_NearestWorkDay
36              
37             Date_DayOfWeek
38             Date_SecsSince1970
39             Date_SecsSince1970GMT
40             Date_DaysSince1BC
41             Date_DayOfYear
42             Date_NthDayOfYear
43             Date_DaysInMonth
44             Date_DaysInYear
45             Date_WeekOfYear
46             Date_LeapYear
47             Date_DaySuffix
48             Date_ConvTZ
49             Date_TimeZone
50             );
51              
52 168     168   1172 use strict;
  168         324  
  168         4913  
53 168     168   79810 use integer;
  168         2662  
  168         850  
54 168     168   5040 use warnings;
  168         345  
  168         12291  
55              
56             our $VERSION;
57             $VERSION='6.90';
58              
59             ###########################################################################
60              
61             our ($dmb,$dmt,$date,$delta,$recur,$date2,$dateUT);
62 168     168   158942 use Date::Manip::Date;
  168         634  
  168         8140  
63 168     168   1140 use Carp;
  168         418  
  168         936518  
64              
65             $dateUT = new Date::Manip::Date;
66             $dateUT->config('setdate','now,Etc/GMT');
67              
68             $date = new Date::Manip::Date;
69             $date2 = $date->new_date();
70             $delta = $date->new_delta();
71             $recur = $date->new_recur();
72             $dmb = $date->base();
73             $dmt = $date->tz();
74              
75             ########################################################################
76             ########################################################################
77             # THESE ARE THE MAIN ROUTINES
78             ########################################################################
79             ########################################################################
80              
81             sub DateManipVersion {
82 168     168 1 42218 my($flag) = @_;
83 168         1884 return $date->version($flag);
84             }
85              
86             sub Date_Init {
87 23     23 1 1592 my(@args) = @_;
88 23         51 my(@args2);
89              
90 23         65 foreach my $arg (@args) {
91 24 50       250 if ($arg =~ /^(\S+)\s*=\s*(.*)$/) {
92 24         142 push(@args2,$1,$2);
93             } else {
94 0         0 carp "ERROR: invalid Date_Init argument: $arg";
95             }
96             }
97 23         156 $date->config(@args2);
98 23         236 return $date->err();
99             }
100              
101             sub ParseDateString {
102 247     247 1 122647 my($string,@opts) = @_;
103 247 50       575 $string = '' if (! defined($string));
104 247         799 my $err = $date->parse($string,@opts);
105 247 100       690 return '' if ($err);
106 203         583 my $ret = $date->value('local');
107 203         923 return $ret;
108             }
109              
110             sub ParseDateFormat {
111 3     3 1 2502 my($format,$string) = @_;
112 3 50       10 $string = '' if (! defined($string));
113 3         18 my $err = $date->parse_format($format,$string);
114 3 50       7 return '' if ($err);
115 3         15 my $ret = $date->value('local');
116 3         17 return $ret;
117             }
118              
119             sub ParseDate {
120 0     0 1 0 my($arg,@opts) = @_;
121              
122 0 0       0 $arg = '' if (! defined($arg));
123 0         0 my $ref = ref($arg);
124 0         0 my $list = 0;
125              
126 0         0 my @args;
127 0 0       0 if (! $ref) {
    0          
    0          
128 0         0 @args = ($arg);
129             } elsif ($ref eq 'ARRAY') {
130 0         0 @args = @$arg;
131 0         0 $list = 1;
132             } elsif ($ref eq 'SCALAR') {
133 0         0 @args = ($$arg);
134             } else {
135 0         0 print "ERROR: Invalid arguments to ParseDate.\n";
136 0         0 return '';
137             }
138              
139 0         0 while (@args) {
140 0         0 my $string = join(' ',@args);
141 0         0 my $err = $date->parse($string,@opts);
142 0 0       0 if (! $err) {
143 0 0       0 splice(@$arg,0,$#args+1) if ($list);
144 0         0 my $ret = $date->value('local');
145 0         0 return $ret;
146             }
147 0         0 pop(@args);
148             }
149              
150 0         0 return '';
151             }
152              
153             sub ParseDateDelta {
154 33     33 1 17176 my(@a) = @_;
155              
156 33 50 33     131 if (@a < 1 || @a > 2) {
157 0         0 print "ERROR: Invalid number of arguments to ParseDateDelta.\n";
158 0         0 return '';
159             }
160 33         63 my($args,$mode) = @_;
161 33 50       64 $args = '' if (! defined($args));
162 33 100       71 $mode = '' if (! $mode);
163 33         52 $mode = lc($mode);
164 33 50 33     63 if ($mode && ($mode ne 'exact' && $mode ne 'semi' && $mode ne 'approx')) {
      33        
      66        
165 0         0 print "ERROR: Invalid arguments to ParseDateDelta.\n";
166 0         0 return '';
167             }
168              
169 33         46 my @args;
170 33         47 my $ref = ref($args);
171 33         40 my $list = 0;
172              
173 33 50       58 if (! $ref) {
    0          
    0          
174 33         59 @args = ($args);
175             } elsif ($ref eq 'ARRAY') {
176 0         0 @args = @$args;
177 0         0 $list = 1;
178             } elsif ($ref eq 'SCALAR') {
179 0         0 @args = ($$args);
180             } else {
181 0         0 print "ERROR: Invalid arguments to ParseDateDelta.\n";
182 0         0 return '';
183             }
184              
185 33         65 while (@args) {
186 33         74 my $string = join(' ',@args);
187 33         87 my $err = $delta->parse($string);
188 33 100       67 if (! $err) {
189 24 100       50 $delta->convert($mode) if ($mode);
190 24 50       41 splice(@$args,0,$#args+1) if ($list);
191 24         62 my $ret = $delta->value('local');
192 24         111 return $ret;
193             }
194 9         25 pop(@args);
195             }
196              
197 9         30 return '';
198             }
199              
200             sub UnixDate {
201 2     2 1 1157 my($string,@in) = @_;
202 2         4 my(@ret);
203              
204 2         11 my $err = $date->parse($string);
205 2 50       7 return () if ($err);
206              
207 2         6 foreach my $in (@in) {
208 2         10 push(@ret,$date->printf($in));
209             }
210              
211 2 50       7 if (! wantarray) {
212 0         0 return join(" ",@ret);
213             }
214 2         15 return @ret;
215             }
216              
217             sub Delta_Format {
218 19     19 1 16117 my($string,@args) = @_;
219              
220 19         56 my $err = $delta->parse($string);
221 19 50       57 return () if ($err);
222              
223 19         26 my($mode,$dec,@in);
224 19 50 100     103 if (! defined($args[0])) {
    100 100        
    50          
225 0         0 $mode = 'exact';
226 0         0 @in = @args;
227 0         0 shift(@in);
228              
229             } elsif (lc($args[0]) eq 'exact' ||
230             lc($args[0]) eq 'approx' ||
231             lc($args[0]) eq 'semi') {
232 18         40 ($mode,$dec,@in) = (@args);
233 18         33 $mode = lc($mode);
234              
235             } elsif ($args[0] =~ /^\d+$/) {
236 0         0 ($mode,$dec,@in) = ('exact',@args);
237              
238             } else {
239 1         2 $mode = 'exact';
240 1         3 @in = @args;
241             }
242              
243 19 100       33 $dec = 0 if (! $dec);
244 19         75 @in = _Delta_Format_old($mode,$dec,@in);
245              
246 19         30 my @ret = ();
247 19         31 foreach my $in (@in) {
248 19         56 push(@ret,$delta->printf($in));
249             }
250              
251 19 50       44 if (! wantarray) {
252 0         0 return join(" ",@ret);
253             }
254              
255 19         79 return @ret;
256             }
257              
258             sub _Delta_Format_old {
259 19     19   43 my($mode,$dec,@in) = @_;
260 19         25 my(@ret);
261 19         52 my $business = $delta->type('business');
262              
263 19         34 foreach my $in (@in) {
264 19         28 my $out = '';
265              
266             # This will look for old formats (%Xd, %Xh, %Xt) and turn them
267             # into the new format: %XYZ
268              
269 19         36 while ($in) {
270 248 100       956 if ($in =~ s/^([^%]+)//) {
    50          
    100          
271 115         256 $out .= $1;
272              
273             } elsif ($in =~ /^%[yMwdhms][yMwdhms][yMwdhms]/) {
274             # It's one of the new formats so don't modify it.
275 0         0 $in =~ s/^%//;
276 0         0 $out .= '%';
277              
278             } elsif ($in =~ s/^%([yMwdhms])([dht])//) {
279 126         289 my($field,$scope) = ($1,$2);
280 126         178 $out .= '%';
281              
282 126 100       265 if ($scope eq 'd') {
    100          
    50          
283 42 100 100     152 if ($mode eq 'approx') {
    100 100        
    100 100        
    100 100        
    100          
284 14         42 $out .= ".${dec}${field}${field}s";
285             } elsif ($field eq 'y' || $field eq 'M') {
286 8         23 $out .= ".${dec}${field}${field}M";
287             } elsif ($mode eq 'semi') {
288 10         61 $out .= ".${dec}${field}${field}s";
289             } elsif ($field eq 'w' && $business) {
290 1         4 $out .= ".${dec}www";
291             } elsif (($field eq 'w' || $field eq 'd') && ! $business) {
292 2         7 $out .= ".${dec}${field}${field}d";
293             } else {
294 7         18 $out .= ".${dec}${field}${field}s";
295             }
296              
297             } elsif ($scope eq 'h') {
298 42 100 100     179 if ($mode eq 'approx') {
    100 100        
    100          
    100          
    100          
    100          
299 14         43 $out .= ".${dec}${field}y${field}";
300             } elsif ($field eq 'y' || $field eq 'M') {
301 8         20 $out .= ".${dec}${field}y${field}";
302             } elsif ($mode eq 'semi') {
303 10         25 $out .= ".${dec}${field}w${field}";
304             } elsif ($field eq 'w') {
305 2         6 $out .= ".${dec}www";
306             } elsif ($field eq 'd' && ! $business) {
307 1         4 $out .= ".${dec}dwd";
308             } elsif ($business) {
309 4         16 $out .= ".${dec}${field}d${field}";
310             } else {
311 3         12 $out .= ".${dec}${field}h${field}";
312             }
313              
314             } elsif ($scope eq 't') {
315 42 100 100     191 if ($mode eq 'approx') {
    100 100        
    100 100        
    100 100        
    100          
    100          
316 14         33 $out .= ".${dec}${field}ys";
317             } elsif ($field eq 'y' || $field eq 'M') {
318 8         22 $out .= ".${dec}${field}yM";
319             } elsif ($mode eq 'semi') {
320 10         26 $out .= ".${dec}${field}ws";
321             } elsif ($field eq 'w' && $business) {
322 1         7 $out .= ".${dec}www";
323             } elsif (($field eq 'w' || $field eq 'd') && ! $business) {
324 2         6 $out .= ".${dec}${field}wd";
325             } elsif ($business) {
326 4         14 $out .= ".${dec}${field}ds";
327             } else {
328 3         13 $out .= ".${dec}${field}hs";
329             }
330             }
331              
332             } else {
333             # It's one of the new formats so don't modify it.
334 7         18 $in =~ s/^%//;
335 7         15 $out .= '%';
336             }
337             }
338              
339 19         51 push(@ret,$out);
340             }
341              
342 19         54 return @ret;
343             }
344              
345             sub DateCalc {
346 120     120 1 78841 my($d1,$d2,@args) = @_;
347              
348             # Handle \$err arg
349              
350 120         203 my($ref,$errref);
351              
352 120 50 66     457 if (@args && ref($args[0])) {
353 0         0 $errref = shift(@args);
354 0         0 $ref = 1;
355             } else {
356 120         179 $ref = 0;
357             }
358              
359             # Parse $d1 and $d2
360              
361 120         187 my ($obj1,$obj2,$err,$usemode);
362 120         169 $usemode = 1;
363              
364 120         362 $obj1 = $date->new_date();
365 120         345 $err = $obj1->parse($d1,'nodelta');
366 120 50       269 if ($err) {
367 0         0 $obj1 = $date->new_delta();
368 0         0 $err = $obj1->parse($d1);
369 0 0       0 if ($err) {
370 0 0       0 $$errref = 1 if ($ref);
371 0         0 return '';
372             }
373 0         0 $usemode = 0;
374             }
375              
376 120         363 $obj2 = $date->new_date();
377 120         355 $err = $obj2->parse($d2,'nodelta');
378 120 100       333 if ($err) {
379 49         163 $obj2 = $date->new_delta();
380 49         148 $err = $obj2->parse($d2);
381 49 50       107 if ($err) {
382 0 0       0 $$errref = 2 if ($ref);
383 0         0 return '';
384             }
385 49         75 $usemode = 0;
386             }
387              
388             # Handle $mode
389              
390 120         162 my($mode);
391 120 100       255 if (@args) {
392 60         111 $mode = shift(@args);
393             }
394 120 50       248 if (@args) {
395 0 0       0 $$errref = 3 if ($ref);
396 0         0 return '';
397             }
398              
399             # Apply the $mode to any deltas
400              
401 120 100       249 if (defined($mode)) {
402 60 50       166 if (ref($obj1) eq 'Date::Manip::Delta') {
403 0 0       0 if ($$obj1{'data'}{'gotmode'}) {
404 0 0 0     0 if ($mode == 2 || $mode == 3) {
405 0 0       0 if (! $obj1->type('business')) {
406 0 0       0 $$errref = 3 if ($ref);
407 0         0 return '';
408             }
409             } else {
410 0 0       0 if ($obj1->type('business')) {
411 0 0       0 $$errref = 3 if ($ref);
412 0         0 return '';
413             }
414             }
415             } else {
416 0 0 0     0 if ($mode == 2 || $mode == 3) {
417 0         0 $obj1->set('mode','business');
418             } else {
419 0         0 $obj1->set('mode','normal');
420             }
421             }
422             }
423              
424 60 50       134 if (ref($obj2) eq 'Date::Manip::Delta') {
425 0 0       0 if ($$obj2{'data'}{'gotmode'}) {
426 0 0 0     0 if ($mode == 2 || $mode == 3) {
427 0 0       0 if (! $obj2->type('business')) {
428 0 0       0 $$errref = 3 if ($ref);
429 0         0 return '';
430             }
431             } else {
432 0 0       0 if ($obj2->type('business')) {
433 0 0       0 $$errref = 3 if ($ref);
434 0         0 return '';
435             }
436             }
437             } else {
438 0 0 0     0 if ($mode ==2 || $mode == 3) {
439 0         0 $obj2->set('mode','business');
440             } else {
441 0         0 $obj2->set('mode','normal');
442             }
443             }
444             }
445             }
446              
447             # Do the calculation
448              
449 120         167 my $obj3;
450 120 100       227 if ($usemode) {
451 71 100       195 $mode = 'exact' if (! $mode);
452 71         445 my %tmp = ('0' => 'exact',
453             '1' => 'approx',
454             '2' => 'bapprox',
455             '3' => 'business',
456             'exact' => 'exact',
457             'semi' => 'semi',
458             'approx' => 'approx',
459             'business'=> 'business',
460             'bsemi' => 'bsemi',
461             'bapprox' => 'bapprox',
462             );
463              
464 71 50       166 if (exists $tmp{$mode}) {
465 71         124 $mode = $tmp{$mode};
466             } else {
467 0 0       0 $$errref = 3 if ($ref);
468 0         0 return '';
469             }
470              
471 71         226 $obj3 = $obj1->calc($obj2,$mode);
472             } else {
473 49         165 $obj3 = $obj1->calc($obj2);
474             }
475              
476 120         327 my $ret = $obj3->value();
477 120         1601 return $ret;
478             }
479              
480             sub Date_GetPrev {
481 34     34 1 41147 my($string,$dow,$curr,@time) = @_;
482 34         117 my $err = $date->parse($string);
483 34 50       63 return '' if ($err);
484              
485 34 100       57 if (defined($dow)) {
486 11         19 $dow = lc($dow);
487 11 50       46 if (exists $$dmb{'data'}{'wordmatch'}{'day_char'}{$dow}) {
    100          
    50          
488 0         0 $dow = $$dmb{'data'}{'wordmatch'}{'day_char'}{$dow};
489             } elsif (exists $$dmb{'data'}{'wordmatch'}{'day_abb'}{$dow}) {
490 10         22 $dow = $$dmb{'data'}{'wordmatch'}{'day_abb'}{$dow};
491             } elsif (exists $$dmb{'data'}{'wordmatch'}{'day_name'}{$dow}) {
492 0         0 $dow = $$dmb{'data'}{'wordmatch'}{'day_name'}{$dow};
493             }
494             }
495              
496 34 100       63 if ($#time == 0) {
497 7         30 @time = @{ $dmb->split('hms',$time[0]) };
  7         22  
498             }
499              
500 34 100       67 if (@time) {
501 29         64 while ($#time < 2) {
502 7         20 push(@time,0);
503             }
504 29         90 $date->prev($dow,$curr,\@time);
505             } else {
506 5         17 $date->prev($dow,$curr);
507             }
508 34         95 my $ret = $date->value();
509 34         143 return $ret;
510             }
511              
512             sub Date_GetNext {
513 34     34 1 40104 my($string,$dow,$curr,@time) = @_;
514 34         141 my $err = $date->parse($string);
515 34 50       69 return '' if ($err);
516              
517 34 100       70 if (defined($dow)) {
518 11         20 $dow = lc($dow);
519 11 50       44 if (exists $$dmb{'data'}{'wordmatch'}{'day_char'}{$dow}) {
    100          
    50          
520 0         0 $dow = $$dmb{'data'}{'wordmatch'}{'day_char'}{$dow};
521             } elsif (exists $$dmb{'data'}{'wordmatch'}{'day_abb'}{$dow}) {
522 10         19 $dow = $$dmb{'data'}{'wordmatch'}{'day_abb'}{$dow};
523             } elsif (exists $$dmb{'data'}{'wordmatch'}{'day_name'}{$dow}) {
524 0         0 $dow = $$dmb{'data'}{'wordmatch'}{'day_name'}{$dow};
525             }
526             }
527              
528 34 100       67 if ($#time == 0) {
529 7         12 @time = @{ $dmb->split('hms',$time[0]) };
  7         22  
530             }
531              
532 34 100       62 if (@time) {
533 29         64 while ($#time < 2) {
534 7         18 push(@time,0);
535             }
536 29         119 $date->next($dow,$curr,\@time);
537             } else {
538 5         16 $date->next($dow,$curr);
539             }
540 34         94 my $ret = $date->value();
541 34         143 return $ret;
542             }
543              
544             sub Date_SetTime {
545 5     5 1 4797 my($string,@time) = @_;
546              
547 5         22 my $err = $date->parse($string);
548 5 50       11 return '' if ($err);
549              
550 5 100       14 if ($#time == 0) {
551 3         4 @time = @{ $dmb->split('hms',$time[0]) };
  3         15  
552             }
553              
554 5         15 while ($#time < 2) {
555 1         4 push(@time,0);
556             }
557              
558 5         18 $date->set('time',\@time);
559 5         15 my $val = $date->value();
560 5         24 return $val;
561             }
562              
563             sub Date_SetDateField {
564 0     0 1 0 my($string,$field,$val) = @_;
565              
566 0         0 my $err = $date->parse($string);
567 0 0       0 return '' if ($err);
568              
569 0         0 $date->set($field,$val);
570 0         0 my $ret = $date->value();
571 0         0 return $ret;
572             }
573              
574             sub Date_NextWorkDay {
575 0     0 1 0 my($string,$n,$checktime) = @_;
576 0         0 my $err = $date->parse($string);
577 0 0       0 return '' if ($err);
578 0         0 $date->next_business_day($n,$checktime);
579 0         0 my $val = $date->value();
580 0         0 return $val;
581             }
582              
583             sub Date_PrevWorkDay {
584 0     0 1 0 my($string,$n,$checktime) = @_;
585 0         0 my $err = $date->parse($string);
586 0 0       0 return '' if ($err);
587 0         0 $date->prev_business_day($n,$checktime);
588 0         0 my $val = $date->value();
589 0         0 return $val;
590             }
591              
592             sub Date_NearestWorkDay {
593 0     0 1 0 my($string,$tomorrowfirst) = @_;
594 0         0 my $err = $date->parse($string);
595 0 0       0 return '' if ($err);
596 0         0 $date->nearest_business_day($tomorrowfirst);
597 0         0 my $val = $date->value();
598 0         0 return $val;
599             }
600              
601             sub ParseRecur {
602 93     93 1 131237 my($string,@args) = @_;
603              
604 93 50       301 if ($#args == 3) {
605 0         0 my($base,$d0,$d1,$flags) = @args;
606 0         0 @args = ();
607 0 0       0 push(@args,$flags) if ($flags);
608 0         0 push(@args,$base,$d0,$d1);
609             }
610              
611 93         395 my $err = $recur->parse($string,@args);
612 93 50       226 return '' if ($err);
613              
614 93 50       194 if (wantarray) {
615 93         355 my @dates = $recur->dates();
616 93         145 my @ret;
617 93         186 foreach my $d (@dates) {
618 363         786 my $val = $d->value();
619 363         835 push(@ret,$val);
620             }
621 93         586 return @ret;
622             }
623              
624 0         0 my @int = @{ $$recur{'data'}{'interval'} };
  0         0  
625 0         0 my @rtime = @{ $$recur{'data'}{'rtime'} };
  0         0  
626 0         0 my @flags = @{ $$recur{'data'}{'flags'} };
  0         0  
627 0         0 my $start = $$recur{'data'}{'start'};
628 0         0 my $end = $$recur{'data'}{'end'};
629 0         0 my $base = $$recur{'data'}{'base'};
630              
631 0         0 my $r;
632 0 0       0 if (@int) {
633 0         0 $r = join(':',@int);
634             }
635 0 0       0 if (@rtime) {
636 0         0 my @rt;
637 0         0 foreach my $rt (@rtime) {
638 0         0 push(@rt,join(",",@$rt));
639             }
640 0         0 $r .= '*' . join(':',@rt);
641             }
642              
643 0         0 $r .= '*' . join(",",@flags);
644              
645 0 0       0 my $val = (defined($base) ? $base->value() : '');
646 0         0 $r .= "*$val";
647              
648 0 0       0 $val = (defined($start) ? $start->value() : '');
649 0         0 $r .= "*$val";
650              
651 0 0       0 $val = (defined($end) ? $end->value() : '');
652 0         0 $r .= "*$val";
653              
654 0         0 return $r;
655             }
656              
657             sub Events_List {
658 8     8 1 12926 my($datestr,@args) = @_;
659              
660             # First argument is always a date
661              
662 8         39 my $err = $date->parse($datestr);
663 8 50       20 return [] if ($err);
664              
665             # Second argument is absent, a date, or 0.
666              
667 8         11 my @list;
668 8         13 my $flag = 0;
669 8         15 my ($date0,$date1);
670              
671 8 100       19 if (! @args) {
672             # absent
673 4         16 @list = $date->list_events('dates');
674              
675             } else {
676             # a date or 0
677 4         11 my $arg = shift(@args);
678 4 100       15 $flag = shift(@args) if (@args);
679 4 50       12 if (@args) {
680 0         0 carp "ERROR: unknown argument list";
681 0         0 return [];
682             }
683              
684 4 100       11 if (! $arg) {
685 1         4 my($y,$m,$d) = $date->value();
686 1         6 $date2->set('date',[$y,$m,$d,23,59,59]);
687 1         5 @list = $date->list_events(0, 'dates');
688              
689             } else {
690 3         13 $err = $date2->parse($arg);
691 3 50       13 if ($err) {
692 0         0 carp "ERROR: invalid argument: $arg";
693 0         0 return [];
694             }
695 3         16 @list = $date->list_events($date2, 'dates');
696             }
697             }
698              
699             # Handle the flag
700              
701 8 100       36 if (! $flag) {
702 6         12 my @ret = ();
703 6         14 foreach my $e (@list) {
704 11         28 my($d,@n) = @$e;
705 11         26 my $v = $d->value();
706 11         41 push(@ret,$v,[@n]);
707             }
708 6         38 return \@ret;
709             }
710              
711 2         7 push(@list,[$date2]);
712 2         6 my %ret;
713              
714 2 100       12 if ($flag==1) {
    50          
715 1         4 while ($#list > 0) {
716 4         8 my($d0,@n) = @{ shift(@list) };
  4         10  
717 4         11 my $d1 = $list[0]->[0];
718 4         11 my $delta = $d0->calc($d1);
719              
720 4         10 foreach $flag (@n) {
721 5 50       13 $flag = '' if (! defined($flag));
722 5 100       13 if (exists $ret{$flag}) {
723 2         9 $ret{$flag} = $ret{$flag}->calc($delta);
724             } else {
725 3         10 $ret{$flag} = $delta;
726             }
727             }
728             }
729              
730             } elsif ($flag==2) {
731 1         5 while ($#list > 0) {
732 4         9 my($d0,@n) = @{ shift(@list) };
  4         10  
733 4         8 my $d1 = $list[0]->[0];
734 4         12 my $delta = $d0->calc($d1);
735 4         17 $flag = join("+",sort(@n));
736              
737 4 100       12 if (exists $ret{$flag}) {
738 1         5 $ret{$flag} = $ret{$flag}->calc($delta);
739             } else {
740 3         12 $ret{$flag} = $delta;
741             }
742             }
743              
744             } else {
745 0         0 carp "ERROR: Invalid flag $flag";
746 0         0 return [];
747             }
748              
749 2         10 foreach my $flag (keys %ret) {
750 6         19 $ret{$flag} = $ret{$flag}->value();
751             }
752              
753 2         12 return \%ret;
754             }
755              
756             ########################################################################
757             # ADDITIONAL ROUTINES
758             ########################################################################
759              
760             sub Date_DayOfWeek {
761 0     0 1 0 my($m,$d,$y) = @_;
762 0         0 return $dmb->day_of_week([$y,$m,$d]);
763             }
764              
765             sub Date_SecsSince1970 {
766 0     0 1 0 my($m,$d,$y,$h,$mn,$s) = @_;
767 0         0 return $dmb->secs_since_1970([$y,$m,$d,$h,$mn,$s]);
768             }
769              
770             sub Date_SecsSince1970GMT {
771 0     0 1 0 my($m,$d,$y,$h,$mn,$s) = @_;
772 0         0 $date->set('date',[$y,$m,$d,$h,$mn,$s]);
773 0         0 return $date->secs_since_1970_GMT();
774             }
775              
776             sub Date_DaysSince1BC {
777 0     0 1 0 my($m,$d,$y) = @_;
778 0         0 return $dmb->days_since_1BC([$y,$m,$d]);
779             }
780              
781             sub Date_DayOfYear {
782 0     0 1 0 my($m,$d,$y) = @_;
783 0         0 return $dmb->day_of_year([$y,$m,$d]);
784             }
785              
786             sub Date_NthDayOfYear {
787 7     7 1 5741 my($y,$n) = @_;
788 7         11 my @ret = @{ $dmb->day_of_year($y,$n) };
  7         21  
789 7 100       22 push(@ret,0,0,0) if ($#ret == 2);
790 7         21 return @ret;
791             }
792              
793             sub Date_DaysInMonth {
794 0     0 1 0 my($m,$y) = @_;
795 0         0 return $dmb->days_in_month($y,$m);
796             }
797              
798             sub Date_DaysInYear {
799 0     0 1 0 my($y) = @_;
800 0         0 return $dmb->days_in_year($y);
801             }
802              
803             sub Date_WeekOfYear {
804 0     0 1 0 my($m,$d,$y,$first) = @_;
805 0         0 my($yy,$ww) = $dmb->_week_of_year($first,[$y,$m,$d]);
806 0 0       0 return 0 if ($yy<$y);
807 0 0       0 return 53 if ($yy>$y);
808 0         0 return $ww;
809             }
810              
811             sub Date_LeapYear {
812 0     0 1 0 my($y) = @_;
813 0         0 return $dmb->leapyear($y);
814             }
815              
816             sub Date_DaySuffix {
817 0     0 1 0 my($d) = @_;
818 0         0 return $$dmb{'data'}{'wordlist'}{'nth_dom'}[$d-1];
819             }
820              
821             sub Date_TimeZone {
822 0     0 1 0 my($ret) = $dmb->_now('tz');
823 0         0 return $ret;
824             }
825              
826             sub Date_ConvTZ {
827 14     14 1 13871 my($str,$from,$to) = @_;
828 14 50       37 $from = $dmb->_now('tz') if (! $from);
829 14 50       34 $to = $dmb->_now('tz') if (! $to);
830              
831             # Parse the date (ignoring timezone information):
832              
833 14         63 my $err = $dateUT->parse($str);
834 14 50       33 return '' if ($err);
835 14         44 my $d = [ $dateUT->value() ];
836 14 50       41 return '' if (! $d);
837              
838             # Get the timezone for $from. First, we'll assume that
839             # the date matches exactly (so if the timezone is passed
840             # in as an abbreviation, we'll try to get the timezone
841             # that fits the date/abbrev combination). If we can't,
842             # we'll just assume that the timezone is more generic
843             # and try it without the date.
844              
845 14         21 my $tmp;
846 14         44 $tmp = $dmt->zone($from,$d);
847 14 50       35 if (! $tmp) {
848 0         0 $tmp = $dmt->zone($from);
849 0 0       0 return '' if (! $tmp);
850             }
851 14         27 $from = $tmp;
852              
853 14         38 $tmp = $dmt->zone($to,$d);
854 14 100       43 if (! $tmp) {
855 2         8 $tmp = $dmt->zone($to);
856 2 50       8 return '' if (! $tmp);
857             }
858 14         28 $to = $tmp;
859              
860 14         41 ($err,$d) = $dmt->convert($d,$from,$to);
861 14 50       42 return '' if ($err);
862 14         64 return $dmb->join('date',$d);
863             }
864              
865             sub Date_IsWorkDay {
866 0     0 1 0 my($str,$checktime) = @_;
867 0         0 my $err = $date->parse($str);
868 0 0       0 return '' if ($err);
869 0         0 return $date->is_business_day($checktime);
870             }
871              
872             sub Date_IsHoliday {
873 2     2 1 1780 my($str) = @_;
874 2         12 my $err = $date->parse($str);
875 2 50       18 return undef if ($err);
876 2 100       6 if (wantarray) {
877 1         5 my @ret = $date->holiday();
878 1         4 return @ret;
879             } else {
880 1         7 my $ret = $date->holiday();
881 1         5 return $ret;
882             }
883             }
884              
885             sub Date_Cmp {
886 0     0 1   my($str1,$str2) = @_;
887 0           my $err = $date->parse($str1);
888 0 0         return undef if ($err);
889 0           $err = $date2->parse($str2);
890 0 0         return undef if ($err);
891 0           return $date->cmp($date2);
892             }
893              
894             1;
895             # Local Variables:
896             # mode: cperl
897             # indent-tabs-mode: nil
898             # cperl-indent-level: 3
899             # cperl-continued-statement-offset: 2
900             # cperl-continued-brace-offset: 0
901             # cperl-brace-offset: 0
902             # cperl-brace-imaginary-offset: 0
903             # cperl-label-offset: 0
904             # End: