File Coverage

blib/lib/DateTime/Ordinal.pm
Criterion Covered Total %
statement 111 118 94.0
branch 65 76 85.5
condition 6 8 75.0
subroutine 16 18 88.8
pod 2 4 50.0
total 200 224 89.2


line stmt bran cond sub pod time code
1              
2             use 5.006;
3 6     6   514080 use strict;
  6         67  
4 6     6   31 use warnings;
  6         8  
  6         101  
5 6     6   21  
  6         10  
  6         170  
6             use parent 'DateTime';
7 6     6   2343 use POSIX qw( floor );
  6         1465  
  6         28  
8 6     6   2684480 our $VERSION = '0.04';
  6         16  
  6         53  
9              
10             our (%strftime_patterns, %sub_format, @ORDINALS, @NTT);
11             BEGIN {
12             for my $sub (qw/
13 6     6   28 month
14             mon
15             month_0
16             mon_0
17             day_of_month
18             day
19             mday
20             weekday_of_month
21             quarter
22             day_of_month_0
23             day_0
24             mday_0
25             day_of_week
26             wday
27             dow
28             day_of_week_0
29             wday_0
30             dow_0
31             local_day_of_week
32             day_of_quarter
33             doq
34             day_of_quarter_0
35             doq_0
36             day_of_year
37             doy
38             day_of_year_0
39             doy_0
40             hour
41             hour_1
42             hour_12
43             hour_12_0
44             minute
45             min
46             second
47             sec
48             nanosecond
49             millisecond
50             microsecond
51             leap_seconds
52             week
53             year
54             week_year
55             week_number
56             week_of_month
57             /) {
58             no strict 'refs';
59 6     6   825 *{"${sub}"} = sub {
  6         12  
  6         7784  
60 264         749 _sub($sub, @_);
61 931     931   147730 };
62 264         630 }
63             %strftime_patterns = (
64             'a' => sub { $_[0]->day_abbr },
65 1         12 'A' => sub { $_[0]->day_name },
66 4         30 'b' => sub { $_[0]->month_abbr },
67 1         9 'B' => sub { $_[0]->month_name },
68 4         17 'c' => sub {
69             $_[0]->format_cldr( $_[0]->{locale}->datetime_format_default() );
70 1         7 },
71             'C' => sub {
72             my $y = int( $_[0]->year / 100 );
73 2         7 return $_[1] ? _ordinal($y) : $y;
74 2 100       10 },
75             'd' => sub { $_[1] ? $_[0]->day_of_month($_[1]) : sprintf( '%02d', $_[0]->day_of_month ) },
76 11 100       38 'D' => sub { $_[0]->strftime('%m/%d/%y') },
77 1         7 'e' => sub { $_[1] ? $_[0]->day_of_month($_[1]) : sprintf( '%2d', $_[0]->day_of_month ) },
78 2 100       11 'F' => sub { $_[0]->strftime('%Y-%m-%d') },
79 1         5 'g' => sub {
80             my $w = substr( $_[0]->week_year, -2 );
81 2         7 return $_[1] ? _ordinal($w) : $w;
82 2 100       10 },
83             'G' => sub { $_[0]->week_year($_[1]) },
84 2         6 'H' => sub { $_[1] ? $_[0]->hour($_[1]) : sprintf( '%02d', $_[0]->hour ) },
85 7 100       30 'I' => sub { $_[1] ? $_[0]->hour_12($_[1]) : sprintf( '%02d', $_[0]->hour_12 ) },
86 3 100       18 'j' => sub { $_[1] ? $_[0]->day_of_year($_[1]) : sprintf( '%03d', $_[0]->day_of_year ) },
87 4 100       25 'k' => sub { $_[1] ? $_[0]->hour($_[1]) : sprintf( '%2d', $_[0]->hour ) },
88 2 100       11 'l' => sub { $_[1] ? $_[0]->hour_12($_[1]) : sprintf( '%2d', $_[0]->hour_12 ) },
89 2 100       10 'm' => sub { $_[1] ? $_[0]->month($_[1]) : sprintf( '%02d', $_[0]->month ) },
90 10 100       37 'M' => sub { $_[1] ? $_[0]->minute($_[1]) : sprintf( '%02d', $_[0]->minute ) },
91 8 100       29 'n' => sub {"\n"}, # should this be OS-sensitive?
92 1         4 'N' => \&_format_nanosecs,
93             'p' => sub { $_[0]->am_or_pm() },
94 2         9 'P' => sub { lc $_[0]->am_or_pm() },
95 1         5 'r' => sub { $_[0]->strftime('%I:%M:%S %p') },
96 1         5 'R' => sub { $_[0]->strftime('%H:%M') },
97 1         4 's' => sub { $_[0]->epoch },
98 1         11 'S' => sub { sprintf( '%02d', $_[0]->second ) },
99 2         8 't' => sub {"\t"},
100 1         3 'T' => sub { $_[0]->strftime('%H:%M:%S') },
101 1         5 'u' => sub { $_[0]->day_of_week($_[1]) },
102 1         7 'U' => sub {
103             my $sun = $_[0]->day_of_year - ( $_[0]->day_of_week + 7 ) % 7;
104 1         6 return sprintf( '%02d', int( ( $sun + 6 ) / 7 ) );
105 1         9 },
106             'V' => sub { sprintf( '%02d', $_[0]->week_number ) },
107 1         7 'w' => sub {
108             my $dow = $_[0]->day_of_week;
109 2         6 my $w = $dow % 7;
110 2         6 return $_[1] ? _ordinal($w) : $w;
111 2 100       10 },
112             'W' => sub {
113             my $mon = $_[0]->day_of_year - ( $_[0]->day_of_week + 6 ) % 7;
114 1         4 return sprintf( '%02d', int( ( $mon + 6 ) / 7 ) );
115 1         8 },
116             'x' => sub {
117             $_[0]->format_cldr( $_[0]->{locale}->date_format_default() );
118 1         8 },
119             'X' => sub {
120             $_[0]->format_cldr( $_[0]->{locale}->time_format_default() );
121 1         7 },
122             'y' => sub {
123             my $y = sprintf( '%02d', substr( $_[0]->year, -2 ) );
124 3         35 return $_[1] ? _ordinal($y) : $y;
125 3 100       34 },
126             'Y' => sub { $_[0]->year($_[1]) },
127 8         20 'z' => sub { DateTime::TimeZone->offset_as_string( $_[0]->offset ) },
128 1         9 'Z' => sub { $_[0]->{tz}->short_name_for_datetime( $_[0] ) },
129 1         6 '%' => sub {'%'},
130 1         3 );
131 6         430 $strftime_patterns{h} = $strftime_patterns{b};
132 6         34 @ORDINALS = qw/th st nd rd/;
133 6         19 @NTT = (
134 6         107 [
135             '',
136             ['one', 'first'],
137             ['two', 'second'],
138             ['three', 'third'],
139             ['four', 'fourth'],
140             ['five', 'fifth'],
141             ['six', 'sixth'],
142             ['seven', 'seventh'],
143             ['eight', 'eighth'],
144             ['nine', 'ninth'],
145             ['ten', 'tenth'],
146             ['eleven', 'eleventh'],
147             ['twelve', 'twelfth'],
148             ['thirteen', 'thirteenth'],
149             ['fourteen', 'fourteenth'],
150             ['fifthteen', 'fifthteenth'],
151             ['sixteen', 'sixteenth'],
152             ['seventeen', 'seventeenth'],
153             ['eighteen', 'eighteenth'],
154             ['nineteen', 'nineteenth'],
155             ],
156             [
157             '',
158             '',
159             ['twenty', 'twentieth'],
160             ['thirty', 'thirtieth'],
161             ['forty', 'fortieth'],
162             ['fifty', 'fiftieth'],
163             ['sixty', 'sixtieth'],
164             ['seventy', 'seventieth'],
165             ['eighty', 'eightieth'],
166             ['ninety', 'nintieth']
167             ],
168             'hundred',
169             'thousand',
170             'million',
171             'billion',
172             'trillion',
173             'quadrillion',
174             'quintillion',
175             'sextillion',
176             'septillion',
177             'octillion'
178             );
179             %sub_format = (
180             f => sub { _num2text(shift) },
181 168         321 o => sub { _ordinal(shift) },
182 181         354 of => sub { _num2text(shift, 1) },
183 171         349 oe => sub { _ordinal(shift, 1) }
184 1         4 );
185 6         5635 }
186              
187              
188 16     16 0 3757 my ($package, %args) = @_;
189             set_sub_format($args{sub_format}) if ($args{sub_format});
190             }
191 6     6   64  
192 6 50       12865  
193             my $self = shift;
194              
195 0     0 0 0 # make a copy or caller's scalars get munged
  0         0  
196             my @patterns = @_;
197             my @r;
198 78     78 1 74511 foreach my $p (@patterns) {
199             $p =~ s/
200             (?:
201 78         173 %\{(\w+)\}(?:\s*\(([\w\d]+)\))* # method name like %{day_name}
202 78         118 |
203 78         129 %([%a-zA-Z])(?:\s*\(([\w\d]+)\))* # single character specifier like %d
204 78         496 |
205             %(\d+)N # special case for %N
206             )
207             /
208             ( $1
209             ? ( $self->can($1) ? $self->$1($2) : "\%{$1}" )
210             : $3
211             ? ( $strftime_patterns{$3} ? $strftime_patterns{$3}->($self, $4) : "\%$2" )
212             : $5
213             ? $strftime_patterns{N}->($self, $5)
214             : '' # this won't happen
215             )
216             /sgex;
217             return $p unless wantarray;
218 107 50       577 push @r, $p;
    50          
    0          
    50          
    100          
219             }
220              
221             return @r;
222 78 50       531 }
223 0         0  
224             require DateTime::Format::Strptime;
225             DateTime::Ordinal->from_object(object => DateTime::Format::Strptime->new(
226 0         0 on_error => 'croak',
227             pattern => $_[1],
228             ($_[3] ? %{$_[3]} : ())
229             )->parse_datetime($_[2]));
230 0     0 1 0 }
231              
232             my ($orig, $self, $ordinal, $default) = @_;
233             $orig = "SUPER::$orig";
234 0 0       0 my $val = $self->$orig || $default || 0;
  0         0  
235             return $sub_format{$ordinal || ''} && $val ? $sub_format{$ordinal}->($val, $self) : $val;
236             }
237              
238             return ($_[1] ? '' : $_[0]) . $ORDINALS[$_[0] =~ m{(?<!1)([123])$} ? $1 : 0];
239 947     947   1874 }
240 947         1575
241 947   100     2797 my $self = shift;
242 947 100 66     8304 my $precision = @_ ? shift : 9;
243            
244             my $divide_by = 10**( 9 - $precision );
245            
246 192 100   192   4503 return sprintf(
    100          
247             '%0' . $precision . 'u',
248             floor( $self->{rd_nanosecs} / $divide_by )
249             );
250 1     1   2 }
251 1 50       4  
252             my ($ns, $l, $o, @n2t) = ('', 3, ($_[1] ? -1 : 0), reverse(split('', $_[0])));
253 1         7 my $hundred = sub {
254             my ($string, $ord, @trip) = ('', @_, 0, 0, 0);
255             if ($trip[1] > 1) {
256             for (0, 1) {
257 1         16 $string = sprintf(
258             "%s%s",
259             $NTT[$_][$trip[$_]][$string ? 0 : $ord],
260             ($string ? '-' . $string : '')
261             ) if $trip[$_];
262 375 100   375   19190 }
263             } elsif ($trip[0] || $trip[1]) { $string = $NTT[0][$trip[1] . $trip[0]][$ord]; }
264 406     406   922 $string = sprintf(
265 406 100 66     1125 "%s %s%s",
    100          
266 24         34 $NTT[0][$trip[2]][0],
267 48 100       219 $NTT[2],
    100          
    100          
268             ($string ? ' and ' . $string : ($ord != 0 ? 'th' : ''))
269             ) if $trip[2];
270             return $string;
271             };
272             $ns = $hundred->($o, splice(@n2t, 0, 3));
273 366         1139 while (@n2t) {
274 406 50       779 my $h = $hundred->(0, splice(@n2t, 0, 3));
    100          
    100          
275             $ns = sprintf(
276             "%s %s%s",
277             $h,
278             $NTT[$l],
279             ($ns
280 406         815 ? ($ns =~ m/and/
281 375         1707 ? ', '
282 375         828 : ' and '
283 375         756 ) . $ns
284 31         56 : ($o == 0
285 31 100       145 ? ''
    100          
    100          
    100          
286             :'th'
287             )
288             )
289             ) if $h;
290             $l++;
291             }
292             return $ns;
293             }
294              
295             1; # End of DateTime::Ordinal
296              
297              
298             =head1 NAME
299              
300 31         61 DateTime::Ordinal - The great new DateTime::Ordinal!
301              
302 375         3074 =head1 VERSION
303              
304             Version 0.04
305              
306             =cut
307              
308             =head1 SYNOPSIS
309              
310             Quick summary of what the module does.
311              
312             use DateTime::Ordinal;
313              
314             my $dt = DateTime::Ordinal->new(
315             year => 3000,
316             month => 4,
317             day => 1,
318             hour => 2,
319             minute => 3,
320             second => 4,
321             );
322              
323             $dt->day # 1
324             $dt->day('o') # 1st
325             $dt->day('f') # one
326             $dt->day('of') # first
327              
328             $dt->hour # 2
329             $dt->hour('o') # 2nd
330             $dt->hour('f') # two
331             $dt->hour('of') # second
332              
333             $dt->minute # 3
334             $dt->minute('o') # 3rd
335             $dt->minute('f') # three
336             $dt->minute('of') # third
337              
338             $dt->second # 4
339             $dt->second('o') # 4th
340             $dt->second('f') # four
341             $dt->second('of') # fourth
342              
343             $dt->strftime("It's the %M(of) minute of the %H(o) hour on day %d(f) in the %m(of) month within the year %Y(f)");
344             # "It's the third minute of the 2nd hour on day one in the fourth month within the year three thousand");
345              
346             ...
347              
348             use Lingua::ITA::Numbers
349             use DateTime::Ordinal (
350             sub_format => {
351             f => sub {
352             my $number = Lingua::ITA::Numbers->new(shift);
353             return $number->get_string;
354             }
355             }
356             );
357              
358             my $dt = DateTime::Ordinal->new(
359             hour => 1,
360             minute => 2,
361             second => 3,
362             locale => 'it'
363             );
364              
365             $dt->hour('f') # uno
366             $dt->minute('f') # due
367             $dt->second('f') # tre
368              
369             =head1 SUBROUTINES/METHODS
370              
371             =cut
372              
373             =head2 strftime
374              
375             =cut
376              
377             =head2 month
378              
379             =cut
380              
381             =head2 mon
382              
383             =cut
384              
385             =head2 month_0
386              
387             =cut
388              
389             =head2 mon_0
390              
391             =cut
392              
393             =head2 day_of_month
394              
395             =cut
396              
397             =head2 day
398              
399             =cut
400              
401             =head2 mday
402              
403             =cut
404              
405             =head2 weekday_of_month
406              
407             =cut
408              
409             =head2 quarter
410              
411             =cut
412              
413             =head2 day_of_month_0
414              
415             =cut
416              
417             =head2 day_0
418              
419             =cut
420              
421             =head2 mday_0
422              
423             =cut
424              
425             =head2 day_of_week
426              
427             =cut
428              
429             =head2 wday
430              
431             =cut
432              
433             =head2 dow
434              
435             =cut
436              
437             =head2 day_of_week_0
438              
439             =cut
440              
441             =head2 wday_0
442              
443             =cut
444              
445             =head2 dow_0
446              
447             =cut
448              
449             =head2 local_day_of_week
450              
451             =cut
452              
453             =head2 day_of_quarter
454              
455             =cut
456              
457             =head2 doq
458              
459             =cut
460              
461             =head2 day_of_quarter_0
462              
463             =cut
464              
465             =head2 doq_0
466              
467             =cut
468              
469             =head2 day_of_year
470              
471             =cut
472              
473             =head2 doy
474              
475             =cut
476              
477             =head2 day_of_year_0
478              
479             =cut
480              
481             =head2 doy_0
482              
483             =cut
484              
485             =head2 hour
486              
487             =cut
488              
489             =head2 hour_1
490              
491             =cut
492              
493             =head2 hour_12
494              
495             =cut
496              
497             =head2 hour_12_0
498              
499             =cut
500              
501             =head2 minute
502              
503             =cut
504              
505             =head2 min
506              
507             =cut
508              
509             =head2 second
510              
511             =cut
512              
513             =head2 sec
514              
515             =cut
516              
517             =head2 nanosecond
518              
519             =cut
520              
521             =head2 millisecond
522              
523             =cut
524              
525             =head2 microsecond
526              
527             =cut
528              
529             =head2 leap_seconds
530              
531             =cut
532              
533             =head2 week
534              
535             =cut
536              
537             =head2 year
538              
539             =cut
540              
541             =head2 week_year
542              
543             =cut
544              
545             =head2 week_number
546              
547             =cut
548              
549             =head2 week_of_month
550              
551             =cut
552              
553             =head2 strptime
554              
555             =cut
556              
557             =head1 AUTHOR
558              
559             LNATION, C<< <thisusedtobeanemail at gmail.com> >>
560              
561             =head1 BUGS
562              
563             Please report any bugs or feature requests to C<bug-datetime-ordinal at rt.cpan.org>, or through
564             the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=DateTime-Ordinal>. I will be notified, and then you'll
565             automatically be notified of progress on your bug as I make changes.
566              
567             =head1 SUPPORT
568              
569             You can find documentation for this module with the perldoc command.
570              
571             perldoc DateTime::Ordinal
572              
573              
574             You can also look for information at:
575              
576             =over 4
577              
578             =item * RT: CPAN's request tracker (report bugs here)
579              
580             L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=DateTime-Ordinal>
581              
582             =item * AnnoCPAN: Annotated CPAN documentation
583              
584             L<http://annocpan.org/dist/DateTime-Ordinal>
585              
586             =item * CPAN Ratings
587              
588             L<https://cpanratings.perl.org/d/DateTime-Ordinal>
589              
590             =item * Search CPAN
591              
592             L<https://metacpan.org/release/DateTime-Ordinal>
593              
594             =back
595              
596              
597             =head1 ACKNOWLEDGEMENTS
598              
599              
600             =head1 LICENSE AND COPYRIGHT
601              
602             This software is Copyright (c) 2019 by LNATION.
603              
604             This is free software, licensed under:
605              
606             The Artistic License 2.0 (GPL Compatible)
607              
608              
609             =cut
610