File Coverage

blib/lib/DateTime/Calendar/Hebrew.pm
Criterion Covered Total %
statement 266 294 90.4
branch 59 102 57.8
condition 57 75 76.0
subroutine 64 68 94.1
pod 30 33 90.9
total 476 572 83.2


line stmt bran cond sub pod time code
1             package DateTime::Calendar::Hebrew;
2 12     12   33207 use DateTime;
  12         3789017  
  12         645  
3 12     12   136 use Params::Validate qw/validate SCALAR OBJECT CODEREF/;
  12         25  
  12         1002  
4              
5 12     12   68 use vars qw($VERSION);
  12         25  
  12         634  
6             $VERSION = '0.05';
7 12     12   319 use 5.010_000;
  12         45  
  12         389  
8              
9 12     12   61 use strict;
  12         18  
  12         373  
10 12     12   54 no strict 'refs';
  12         22  
  12         353  
11              
12 12     12   59 use constant HEBREW_EPOCH => -1373429;
  12         19  
  12         1014  
13              
14             use overload
15 12         104 fallback => 1,
16             '<=>' => '_compare_overload',
17             'cmp' => '_compare_overload',
18             '+' => '_add_overload',
19 12     12   82 '-' => '_subtract_overload';
  12         22  
20              
21             sub new {
22 12     12 1 2317 my $class = shift;
23             my %p = validate( @_,
24             { year => { type => SCALAR },
25             month => { type => SCALAR, default => 1,
26             callbacks => {
27             'is between 1 and 13' =>
28 12 50   12   320 sub { $_[0] >= 1 && $_[0] <= 13 }
29             }
30             },
31             day => { type => SCALAR, default => 1,
32             callbacks => {
33             'is between 1 and 30' =>
34 12 50   12   212 sub { $_[0] >= 1 && $_[0] <= 30 }
35             }
36             },
37             hour => { type => SCALAR, default => 0,
38             callbacks => {
39             'is between 0 and 23' =>
40 8 50   8   134 sub { $_[0] >= 0 && $_[0] <= 23 }
41             }
42             },
43             minute => { type => SCALAR, default => 0,
44             callbacks => {
45             'is between 0 and 59' =>
46 8 50   8   111 sub { $_[0] >= 0 && $_[0] <= 59 }
47             }
48             },
49             second => { type => SCALAR, default => 0,
50             callbacks => {
51             'is between 0 and 59' =>
52 5 50   5   99 sub { $_[0] >= 0 && $_[0] <= 59 }
53             }
54             },
55             nanosecond => { type => SCALAR, default => 0,
56             callbacks => {
57             'is between 0 and 999999999' =>
58 4 50   4   69 sub { $_[0] >= 0 && $_[0] <= 999999999 }
59             }
60             },
61 12         1040 sunset => { type => OBJECT, optional => 1 },
62             time_zone => { type => SCALAR, optional => 1 },
63             } );
64              
65 12         285 my $self = bless \%p, $class;
66              
67 12         70 $self->{rd_days} = &_to_rd(@p{ qw(year month day) });
68 12         59 $self->{rd_secs} = $p{hour} * 60 * 60 + $p{minute} * 60 + $p{second};
69 12 100       62 if($self->{nanosecond}) { $self->{rd_nanosecs} = delete $self->{nanosecond}; }
  1         3  
70              
71 12 100 66     92 if($self->{sunset} and $self->{time_zone}) {
72 2         15 my $DT_Event_Sunrise = $self->{sunset};
73 2         4 my $time_zone = $self->{time_zone};
74 2         20 my $DT = DateTime->from_object(object => $self);
75              
76 2         292 my $sunset = $DT_Event_Sunrise->next($DT->clone->truncate(to => 'day'));
77 2         4620 $sunset->set_time_zone($time_zone);
78              
79 2 50       60914 if($DT > $sunset) {
80 2         774 $self->{after_sunset} = 1;
81 2         19 @{$self}{qw/year month day/} = &_from_rd($self->{rd_days} + 1);
  2         22  
82             }
83             }
84              
85 12         81 return $self;
86             }
87              
88             sub from_object {
89 3     3 1 425 my ( $class ) = shift;
90 3         61 my %p = validate( @_, {
91             object => {
92             type => OBJECT,
93             can => 'utc_rd_values',
94             },
95             });
96              
97 3         179 my $object = $p{object}->clone();
98 3 50       64 $object->set_time_zone('floating') if $object->can( 'set_time_zone' );
99              
100 3         434 my ($rd_days, $rd_secs, $rd_nanosecs) = $object->utc_rd_values();
101 3   50     45 $rd_nanosecs ||= 0;
102              
103 3         60 my %args;
104 3         16 @args{ qw( year month day ) } = &_from_rd($rd_days);
105              
106 3         6 my($h, $m, $s);
107 3         6 $s = $rd_secs % 60;
108 3         10 $m = int($rd_secs / 60);
109 3         7 $h = int($m / 60);
110 3         4 $m %= 60;
111 3         13 @args{ qw(hour minute second) } = ($h, $m, $s);
112              
113 3   50     21 $args{nanosecond} = $rd_nanosecs || 0;
114              
115 3         25 my $new_object = $class->new(%args);
116              
117 3         44 return $new_object;
118             }
119              
120             sub set {
121 1     1 1 9 my $self = shift;
122             my %p = validate( @_,
123             { year => { type => SCALAR, optional => 1 },
124             month => { type => SCALAR, optional => 1,
125             callbacks => {
126             'is between 1 and 13' =>
127 1 50   1   11 sub { $_[0] >= 1 && $_[0] <= 13 }
128             }
129             },
130             day => { type => SCALAR, optional => 1,
131             callbacks => {
132             'is between 1 and 30' =>
133 1 50   1   20 sub { $_[0] >= 1 && $_[0] <= 30 }
134             }
135             },
136             hour => { type => SCALAR, optional => 1,
137             callbacks => {
138             'is between 0 and 23' =>
139 1 50   1   18 sub { $_[0] >= 0 && $_[0] <= 23 }
140             }
141             },
142             minute => { type => SCALAR, optional => 1,
143             callbacks => {
144             'is between 0 and 59' =>
145 1 50   1   17 sub { $_[0] >= 0 && $_[0] <= 59 }
146             }
147             },
148             second => { type => SCALAR, optional => 1,
149             callbacks => {
150             'is between 0 and 59' =>
151 1 50   1   15 sub { $_[0] >= 0 && $_[0] <= 59 }
152             }
153             },
154             nanosecond => { type => SCALAR, optional => 1,
155             callbacks => {
156             'is between 0 and 999999999' =>
157 0 0   0   0 sub { $_[0] >= 0 && $_[0] <= 999999999 }
158             }
159             },
160 1         70 sunset => { type => OBJECT, optional => 1 },
161             time_zone => { type => SCALAR, optional => 1 },
162             } );
163              
164 1         27 $self->{$_} = $p{$_} for keys %p;
165              
166 1         6 $self->{rd_days} = &_to_rd($self->{year}, $self->{month}, $self->{day});
167 1         5 $self->{rd_secs} = $self->{hour} * 60 * 60 + $self->{minute} * 60 + $self->{second};
168 1 50       4 if($self->{nanosecond}) { $self->{rd_nanosecs} = delete $self->{nanosecond}; }
  0         0  
169              
170 1 50 33     4 if($self->{sunset} and $self->{time_zone}) {
171 0         0 my $DT_Event_Sunrise = $self->{sunset};
172 0         0 my $time_zone = $self->{time_zone};
173 0         0 my $DT = DateTime->from_object(object => $self);
174              
175 0         0 my $sunset = $DT_Event_Sunrise->next($DT->clone->truncate(to => 'day'));
176 0         0 $sunset->set_time_zone($time_zone);
177              
178 0 0       0 if($DT > $sunset) {
179 0         0 $self->{after_sunset} = 1;
180 0         0 @{$self}{qw/year month day/} = &_from_rd($self->{rd_days} + 1);
  0         0  
181             }
182             }
183              
184 1         5 return $self;
185             }
186              
187             sub utc_rd_values {
188 15     15 1 163 my $self = shift;
189 15         30 my @res = @{$self}{ qw/rd_days rd_secs rd_nanosecs/ };
  15         50  
190             # Protect against undef
191 15   100     82 $res[2] ||= 0;
192 15         53 return @res;
193             }
194              
195             sub utc_rd_as_seconds {
196 2     2 1 9 my $self = shift;
197 2         5 my ($rd_days, $rd_secs, $rd_nanosecs) = $self->utc_rd_values;
198              
199 2         7 return $rd_days*24*60*60 + $rd_secs;
200             }
201              
202             sub clone {
203 9     9 1 397 my $self = shift;
204 9         73 my $clone = {%$self};
205 9         33 bless $clone, ref $self;
206 9         39 return $clone;
207             }
208              
209             sub _compare_overload {
210 4 50   4   63 return $_[2] ? - $_[0]->_compare($_[1]) : $_[0]->_compare($_[1]);
211             }
212              
213             sub _compare {
214 4     4   9 my($a, $b) = @_;
215              
216 4 50       12 return undef unless defined $b;
217              
218 4 50 33     57 unless($a->can('utc_rd_values') and $b->can('utc_rd_values')) {
219 0         0 die "Cannot compare a datetime to a regular scalar";
220             }
221              
222 4         15 my @a = $a->utc_rd_values;
223 4         12 my @b = $b->utc_rd_values;
224              
225 4         14 foreach my $i (0..2) {
226 12 50       34 return ($a[$i] <=> $b[$i]) if($a[$i] != $b[$i]);
227             }
228              
229 4         15 return 0;
230             }
231              
232             sub _add_overload {
233 2     2   5 my($dt, $dur, $reversed) = @_;
234 2 50       7 ($dur,$dt) = ($dt,$dur) if $reversed;
235 2         7 return $dt->clone->add_duration($dur);
236             }
237              
238             sub _subtract_overload {
239 2     2   5 my($dt, $dur, $reversed) = @_;
240 2 50       8 ($dur,$dt) = ($dt,$dur) if $reversed;
241 2         5 return $dt->clone->subtract_duration($dur);
242             }
243              
244             sub add_duration {
245 8     8 1 511 my ($self, $dur) = @_;
246 8         31 my %deltas = $dur->deltas;
247              
248 8 50       141 if($deltas{days}) { $self->{rd_days} += $deltas{days}; }
  8         24  
249 8 50       23 if($deltas{hours}) { $self->{rd_secs} += $deltas{hours} * 60 * 60; }
  0         0  
250 8 50       21 if($deltas{minutes}) { $self->{rd_secs} += $deltas{minutes} * 60; }
  8         15  
251 8 50       26 if($deltas{seconds}) { $self->{rd_secs} += $deltas{seconds}; }
  8         14  
252 8 50       20 if($deltas{nanoseconds}) { $self->{rd_nanosecs} += $deltas{nanoseconds}; }
  0         0  
253              
254 8         22 while($self->{rd_secs} < 0) {
255 8         10 $self->{rd_days}--;
256 8         19 $self->{rd_secs} += (24 * 60 * 60);
257             }
258              
259 8         22 return $self->_normalize;
260             }
261              
262             sub subtract_duration {
263 4     4 1 7 my ($self, $dur) = @_;
264 4         18 return $self->add_duration($dur->inverse);
265             }
266              
267             sub _normalize {
268 8     8   16 my($self) = shift;
269              
270 8         9 my($h, $m, $s, $d);
271 8         13 $s = $self->{rd_secs} % 60;
272 8         16 $m = int($self->{rd_secs} / 60);
273 8         12 $h = int($m / 60);
274 8         10 $m %= 60;
275 8         11 $d = int($h / 24);
276 8         10 $h %= 24;
277              
278 8         12 $self->{rd_days} += $d;
279 8         16 $self->{rd_secs} = ($h * 60 * 60) + ($m * 60) + $s;
280              
281 8         21 @{$self}{qw/year month day/} = &_from_rd($self->{rd_days});
  8         32  
282 8         15 @{$self}{qw/hour minute second/} = ($h, $m, $s);
  8         27  
283            
284 8         70 return $self;
285             }
286              
287             sub now {
288 1     1 1 22 my $class = shift;
289 1   33     10 $class = ref($class) || $class;
290              
291 1         9 my $dt = DateTime->now;
292 1         482 my $ht = $class->from_object(object => $dt);
293 1         9 return($ht);
294             }
295              
296             sub today {
297 1     1 1 39 my $class = shift;
298 1   33     10 $class = ref($class) || $class;
299              
300 1         10 my $dt = DateTime->today;
301 1         851 my $ht = $class->from_object(object => $dt);
302 1         8 return($ht);
303             }
304              
305             sub _from_rd {
306 13     13   25 my $rd = shift;
307              
308 13         19 my ($year, $month, $day);
309 13         52 $year = int(($rd - HEBREW_EPOCH) / 366);
310 13         46 while ($rd >= &_to_rd($year + 1, 7, 1)) { $year++; }
  120         260  
311 13 100       41 if ($rd < &_to_rd($year, 1, 1)) { $month = 7; }
  4         8  
312 9         17 else { $month = 1; }
313 13         36 while ($rd > &_to_rd($year, $month, (&_LastDayOfMonth($year, $month)))) { $month++; }
  31         63  
314 13         38 $day = $rd - &_to_rd($year, $month, 1) + 1;
315              
316 13         45 return $year, $month, $day;
317             }
318              
319             sub _to_rd {
320 219     219   350 my ($year, $month, $day) = @_;
321 219 50       470 if(scalar @_) {
322 219         452 ($year, $month, $day) = @_;
323             }
324              
325 219         253 my($m, $DayInYear);
326              
327 219         366 $DayInYear = $day;
328 219 100       375 if ($month < 7) {
329 73         93 $m = 7;
330 73         155 while ($m <= (&_LastMonthOfYear($year))) {
331 505         994 $DayInYear += &_LastDayOfMonth($year, $m++);
332             }
333 73         103 $m = 1;
334 73         192 while ($m < $month) {
335 131         231 $DayInYear += &_LastDayOfMonth($year, $m);
336 131         276 $m++;
337             }
338             }
339             else {
340 146         171 $m = 7;
341 146         344 while ($m < $month) {
342 12         20 $DayInYear += &_LastDayOfMonth($year, $m);
343 12         27 $m++;
344             }
345             }
346              
347 219         415 return($DayInYear + (&_CalendarElapsedDays($year) + HEBREW_EPOCH));
348             }
349              
350             sub _leap_year {
351 756     756   788 my $year = shift;
352              
353 756 100       1439 if ((((7 * $year) + 1) % 19) < 7) { return 1; }
  702         1808  
354 54         135 else { return 0; }
355             }
356              
357             sub _LastMonthOfYear {
358 578     578   719 my $year = shift;
359              
360 578 100       834 if (&_leap_year($year)) { return 13; }
  536         1173  
361 42         95 else { return 12; }
362             }
363              
364             sub _CalendarElapsedDays {
365 529     529   595 my $year = shift;
366              
367 529         545 my($MonthsElapsed, $PartsElapsed, $HoursElapsed, $ConjunctionDay, $ConjunctionParts);
368 0         0 my($AlternativeDay);
369              
370 529         1260 $MonthsElapsed = (235 * int(($year - 1) / 19)) + (12 * (($year - 1) % 19)) + int((7 * (($year - 1) % 19) + 1) / 19);
371 529         598 $PartsElapsed = 204 + 793 * ($MonthsElapsed % 1080);
372 529         992 $HoursElapsed = 5 + 12 * $MonthsElapsed + 793 * int($MonthsElapsed / 1080) + int($PartsElapsed / 1080);
373 529         615 $ConjunctionDay = 1 + 29 * $MonthsElapsed + int($HoursElapsed / 24);
374 529         634 $ConjunctionParts = 1080 * ($HoursElapsed % 24) + $PartsElapsed % 1080;
375              
376 529         548 $AlternativeDay = 0;
377 529 100 100     3089 if (($ConjunctionParts >= 19440) ||
      66        
      66        
      100        
      100        
      33        
378             ((($ConjunctionDay % 7) == 2)
379             && ($ConjunctionParts >= 9924)
380             && (!&_leap_year($year))) ||
381             ((($ConjunctionDay % 7) == 1)
382             && ($ConjunctionParts >= 16789)
383             && (&_leap_year($year - 1))))
384 271         302 { $AlternativeDay = $ConjunctionDay + 1; }
385 258         298 else { $AlternativeDay = $ConjunctionDay; }
386              
387 529 100 100     2734 if ((($AlternativeDay % 7) == 0) ||
      100        
388             (($AlternativeDay % 7) == 3) ||
389             (($AlternativeDay % 7) == 5))
390 245         1038 { return (1 + $AlternativeDay); }
391 284         1175 else { return $AlternativeDay; }
392             }
393              
394             sub _DaysInYear {
395 155     155   166 my $year = shift;
396 155         318 return ((&_CalendarElapsedDays($year + 1)) - (&_CalendarElapsedDays($year)));
397             }
398              
399             sub _LongCheshvan {
400 78     78   107 my $year = shift;
401 78 100       148 if ((&_DaysInYear($year) % 10) == 5) { return 1; }
  27         290  
402 51         225 else { return 0; }
403             }
404              
405             sub _ShortKislev {
406 77     77   90 my $year = shift;
407 77 100       158 if ((&_DaysInYear($year) % 10) == 3) { return 1; }
  43         179  
408 34         307 else { return 0; }
409             }
410              
411             sub _LastDayOfMonth {
412 707     707   874 my ($year, $month) = @_;
413              
414 707 100 100     8199 if (($month == 2) ||
      100        
      100        
      66        
      100        
      66        
      100        
      100        
      66        
      100        
415             ($month == 4) ||
416             ($month == 6) ||
417             (($month == 8) && (! &_LongCheshvan($year))) ||
418             (($month == 9) && &_ShortKislev($year)) ||
419             ($month == 10) ||
420             (($month == 12) && (!&_leap_year($year))) ||
421 317         691 ($month == 13)) { return 29; }
422 390         927 else { return 30; }
423             }
424              
425             sub month_name {
426 2     2 1 8 my $self = shift;
427 2         9 my $month = $self->month;
428 2 50       10 if(@_) { $month = shift; }
  0         0  
429              
430 2         10 return (qw/Nissan Iyar Sivan Tamuz Av Elul Tishrei Cheshvan Kislev Tevet Shevat AdarI AdarII/)[$month-1];
431             }
432              
433             sub day_name {
434 2     2 1 10 my $self = shift;
435 2         9 my $day = $self->day_of_week;
436 2 50       14 if(@_) { $day = shift; }
  0         0  
437              
438 2         9 return (qw/Sunday Monday Tuesday Wednesday Thursday Friday Shabbos/)[$day - 1];
439             }
440              
441 12     12   38436 use DateTime::TimeZone::Floating qw( );
  12         40  
  12         21634  
442 6     6 0 1246 sub time_zone { DateTime::TimeZone::Floating->new() }
443              
444              
445 11     11 1 48 sub year { $_[0]->{year} }
446              
447 10     10 1 35 sub month { $_[0]->{month} }
448             *mon = \&month;
449              
450 1     1 0 7 sub month_0 { $_[0]->month - 1 }
451             *mon_0 = \&month_0;
452              
453 9     9 1 58 sub day_of_month { $_[0]->{day} }
454             *day = \&day_of_month;
455             *mday = \&day_of_month;
456              
457 1     1 1 6 sub day_of_month_0 { $_[0]->day - 1 }
458             *day_0 = \&day_of_month_0;
459             *mday_0 = \&day_of_month_0;
460              
461             sub day_of_week {
462 3     3 1 12 my $rd_days = $_[0]->{rd_days};
463 3 50       12 if($_[0]->{after_sunset}) { $rd_days++; }
  0         0  
464 3         7 return $rd_days % 7 + 1;
465             }
466             *wday = \&day_of_week;
467             *dow = \&day_of_week;
468              
469             sub day_of_week_0 {
470 4     4 1 14 my $rd_days = $_[0]->{rd_days};
471 4 50       11 if($_[0]->{after_sunset}) { $rd_days++; }
  0         0  
472 4         19 return $rd_days % 7;
473             }
474             *wday_0 = \&day_of_week_0;
475             *dow_0 = \&day_of_week_0;
476              
477 1     1 1 8 sub hour { $_[0]->{hour} }
478             *hr = \&hour;
479              
480 1     1 1 8 sub minute { $_[0]->{minute} }
481             *min = \&minute;
482              
483 1     1 1 6 sub second { $_[0]->{second} }
484             *sec = \&second;
485              
486             sub day_of_year {
487 6     6 1 14 my $self = shift;
488 6         8 my ($year, $month, $day) = @{$self}{qw/year month day/};
  6         18  
489              
490 6         8 my $m = 1;
491 6         14 while ($m < $month) {
492 15         27 $day += &_LastDayOfMonth($year, $m);
493 15         35 $m++;
494             }
495 6         16 return $day;
496             }
497             *doy = \&day_of_year;
498              
499             sub week_number {
500 3     3 0 12 my $self = shift;
501              
502 3         14 my $day_of_year = $self->day_of_year;
503 3         9 my $start_of_year = &_to_rd($self->year, 1, 1);
504 3         8 my $first_week_started_on = $start_of_year % 7 + 1;
505              
506 3         10 return (($day_of_year + (7 - $first_week_started_on)) / 7) + 1;
507             }
508              
509 1     1 1 10 sub day_of_year_0 { $_[0]->day_of_year - 1; }
510             *doy_0 = \&day_of_year_0;
511              
512             sub hms {
513 0     0 1 0 my ($self, $sep) = @_;
514 0 0       0 $sep = ':' unless defined $sep;
515              
516 0         0 return sprintf( "%02d%s%02d%s%02d",
517             $self->hour, $sep,
518             $self->minute, $sep,
519             $self->second );
520             }
521             *time = \&hms;
522              
523             sub hm {
524 0     0 1 0 my ($self, $sep) = @_;
525 0 0       0 $sep = ':' unless defined $sep;
526              
527 0         0 return sprintf( "%02d%s%02d",
528             $self->hour, $sep,
529             $self->minute );
530             }
531              
532             sub ymd {
533 2     2 1 20 my ($self, $sep) = @_;
534 2 100       10 $sep = '-' unless defined $sep;
535              
536 2         6 return sprintf( "%04d%s%02d%s%02d",
537             $self->year, $sep,
538             $self->month, $sep,
539             $self->day );
540             }
541             *date = \&ymd;
542              
543             sub mdy {
544 1     1 1 8 my ($self, $sep) = @_;
545 1 50       3 $sep = '-' unless defined $sep;
546              
547 1         3 return sprintf( "%02d%s%02d%s%04d",
548             $self->month, $sep,
549             $self->day, $sep,
550             $self->year );
551             }
552              
553             sub dmy {
554 1     1 1 7 my ($self, $sep) = @_;
555 1 50       3 $sep = '-' unless defined $sep;
556              
557 1         8 return sprintf( "%02d%s%02d%s%04d",
558             $self->day, $sep,
559             $self->month, $sep,
560             $self->year );
561             }
562              
563             sub datetime {
564 0     0 1 0 my $self = shift;
565 0         0 return ($self->ymd('-') . "T" . $self->hms);
566             }
567              
568             my %formats = (
569             'A' => sub { $_[0]->day_name },
570             'a' => sub { my $a = $_[0]->day_of_week_0; (qw/Sun Mon Tue Wed Thu Fri Shabbat/)[$a] },
571             'B' => sub { $_[0]->month_name },
572             'd' => sub { sprintf( '%02d', $_[0]->day) },
573             'D' => sub { $_[0]->strftime( '%m/%d/%Y') },
574             'e' => sub { sprintf( '%2d', $_[0]->day) },
575             'F' => sub { $_[0]->ymd('-') },
576             'j' => sub { sprintf('%03d', $_[0]->day_of_year) },
577             'H' => sub { sprintf('%02d', $_[0]->hour) },
578             'I' => sub { ($_[0]->hour == 12) ? '12' : sprintf('%02d', ($_[0]->hour % 12)) },
579             'k' => sub { sprintf('%2d', $_[0]->hour) },
580             'l' => sub { ($_[0]->hour == 12) ? '12' : sprintf('%2d', ($_[0]->hour % 12)) },
581             'M' => sub { sprintf('%02d', $_[0]->minute) },
582             'm' => sub { sprintf('%02d', $_[0]->month) },
583             'n' => sub { "\n" },
584             'P' => sub { ($_[0]->hour >= 12) ? "PM" : "AM" },
585             'p' => sub { ($_[0]->hour >= 12) ? "pm" : "am" },
586             'r' => sub { $_[0]->strftime( '%I:%M:%S %p') },
587             'R' => sub { $_[0]->strftime( '%H:%M') },
588             'S' => sub { sprintf('%02d', $_[0]->second) },
589             'T' => sub { $_[0]->strftime( '%H:%M:%S') },
590             't' => sub { "\t" },
591             'u' => sub { my $u = $_[0]->day_of_week_0; $u == 0 ? 7 : $u },
592             'U' => sub { my $w = $_[0]->week_number; defined $w ? sprintf('%02d', $w) : ' ' },
593             'w' => sub { $_[0]->day_of_week_0 },
594             'W' => sub { sprintf('%02d', $_[0]->week_number) },
595             'y' => sub { sprintf('%02d', substr($_[0]->year, -2)) },
596             'Y' => sub { return $_[0]->year },
597             '%' => sub { '%' },
598             );
599             $formats{W} = $formats{V} = $formats{U};
600              
601             sub strftime {
602 16     16 1 139 my ($self, @r) = @_;
603              
604 16         27 foreach (@r) {
605 16 50       63 s/%([%*A-Za-z])/ $formats{$1} ? $formats{$1}->($self) : $1 /ge;
  18         76  
606 16 50       75 return $_ unless wantarray;
607             }
608 0           return @r;
609             }
610              
611              
612              
613             1;
614             __END__