File Coverage

blib/lib/Time/Format.pm
Criterion Covered Total %
statement 75 80 93.7
branch 27 38 71.0
condition 4 6 66.6
subroutine 13 13 100.0
pod 2 2 100.0
total 121 139 87.0


line stmt bran cond sub pod time code
1             =for gpg
2             -----BEGIN PGP SIGNED MESSAGE-----
3             Hash: SHA1
4              
5             =encoding utf8
6              
7             =head1 NAME
8              
9             Time::Format - Easy-to-use date/time formatting.
10              
11             =head1 VERSION
12              
13             This is version 1.14 of Time::Format, July 22, 2019.
14              
15             =cut
16              
17 25     25   4471946 use strict;
  25         160  
  25         12607  
18             package Time::Format;
19             $Time::Format::VERSION = '1.14';
20              
21             # This module claims to be compatible with the following versions
22             # of Time::Format_XS.
23             %Time::Format::XSCOMPAT = map {$_ => 1} qw(1.01 1.02 1.03);
24              
25             sub _croak
26             {
27 2     2   11 require Carp;
28 2         245 goto &Carp::croak;
29             }
30              
31             # Here we go through a bunch of tests to decide whether we can use the
32             # XS module, or if we need to load and compile the perl-only
33             # subroutines (which are stored in __DATA__).
34             my $load_perlonly = 0;
35             $load_perlonly = 1 if defined $Time::Format::NOXS && $Time::Format::NOXS;
36              
37             if (!$load_perlonly)
38             {
39             # Check whether the optional XS module is installed.
40             eval { require Time::Format_XS };
41              
42             if ($@ || !defined $Time::Format_XS::VERSION)
43             {
44             $load_perlonly = 1;
45             }
46             else
47             {
48             # Check that we're compatible with them (backwards compatibility)
49             # or they're compatible with us (forwards compatibility).
50             unless ($Time::Format::XSCOMPAT{$Time::Format_XS::VERSION}
51             || $Time::Format_XS::PLCOMPAT{$Time::Format::VERSION})
52             {
53             warn "Your Time::Format_XS version ($Time::Format_XS::VERSION) "
54             . "is not compatible with Time::Format version ($Time::Format::VERSION).\n"
55             . "Using Perl-only functions.\n";
56             $load_perlonly = 1;
57             }
58             }
59              
60             # Okay to use the XS version? Great. Wrap it.
61             if (!$load_perlonly)
62             {
63             *time_format = \&Time::Format_XS::time_format;
64             }
65             }
66              
67             if ($load_perlonly)
68             {
69             # Time::Format_XS not installed, or version mismatch, or NOXS was set.
70             # The perl routines will need to be loaded.
71             # But defer this until someone actually calls time_format().
72             *time_format = sub
73             {
74 256 100   256   577215 goto &time_format_perlonly if defined &time_format_perlonly;
75              
76 11         66 local $^W = 0; # disable warning about subroutines redefined
77 11         51 local $/ = undef;
78 11         48 my $top = tell DATA;
79 11         991 my $d = <DATA>;
80              
81             # Why rewind? Because if the program forks, a second process may need to read DATA.
82             # See CPAN RT bug 121367 (and maybe 74880 too).
83 11         107 seek DATA, $top, 0;
84              
85 11         3098 eval $d;
86 11 50       47465 die if $@;
87 11         92 goto &time_format_perlonly;
88             };
89             undef $Time::Format_XS::VERSION; # Indicate that XS version is not available.
90             }
91              
92              
93             my @EXPORT = qw(%time time_format);
94             my @EXPORT_OK = qw(%time %strftime %manip time_format time_strftime time_manip);
95              
96             # We don't need any of Exporter's fancy features, so it's quicker to
97             # do the import ourselves.
98             sub import
99             {
100 25     25   190 my $pkg = shift;
101 25         90 my ($cpkg,$file,$line) = caller;
102 25         54 my @symbols;
103 25 100       2014 if (@_)
104             {
105 19 100       79 if (grep $_ eq ':all', @_)
106             {
107 5         16 @symbols = (@EXPORT, @EXPORT_OK, grep $_ ne ':all', @_);
108             } else {
109 14         37 @symbols = @_;
110             }
111 19         32 my %seen;
112 19         120 @symbols = grep !$seen{$_}++, @symbols;
113             } else {
114 6         18 @symbols = @EXPORT;
115             }
116 25         44 my %ok;
117 25         113 @ok{@EXPORT_OK,@EXPORT} = ();
118 25         78 my @badsym = grep !exists $ok{$_}, @symbols;
119 25 50       84 if (@badsym)
120             {
121 0 0       0 my $s = @badsym>1? 's' : '';
122 0 0       0 my $v = @badsym>1? 'are' : 'is';
123 0         0 _croak ("The symbol$s ", join(', ', @badsym), " $v not exported by Time::Format at $file line $line.\n");
124             }
125              
126 25     25   199 no strict 'refs';
  25         49  
  25         5001  
127 25         62 foreach my $sym (@symbols)
128             {
129 67         278 $sym =~ s/^([\$\&\@\%])?//;
130 67   100     317 my $pfx = $1 || '&';
131 67         147 my $calsym = $cpkg . '::' . $sym;
132 67         114 my $mysym = $pkg . '::' . $sym;
133 67 100       187 if ($pfx eq '%')
    50          
    50          
134             {
135 34         337 *$calsym = \%$mysym;
136             } elsif ($pfx eq '@') {
137 0         0 *$calsym = \@$mysym;
138             } elsif ($pfx eq '$') {
139 0         0 *$calsym = \$$mysym;
140             } else {
141 33         3591 *$calsym = \&$mysym;
142             }
143             }
144             }
145              
146             # Simple tied-hash implementation.
147              
148             # Each hash is simply tied to a subroutine reference. "Fetching" a
149             # value from the hash invokes the subroutine. If a hash (tied or
150             # otherwise) has multiple comma-separated values but the leading
151             # character is a $, then Perl joins the values with $;. This makes it
152             # easy to simulate function calls with tied hashes -- we just split on
153             # $; to recreate the argument list.
154             #
155             # 2005/12/01: We must ensure that time_format gets two arguments, since
156             # the XS version cannot handle variable argument lists.
157              
158 25     25   190 use vars qw(%time %strftime %manip);
  25         52  
  25         5888  
159             tie %time, 'Time::Format', sub { push @_, 'time' if @_ == 1; goto &time_format};
160             tie %strftime, 'Time::Format', \&time_strftime;
161             tie %manip, 'Time::Format', \&time_manip;
162              
163             sub TIEHASH
164             {
165 75     75   138 my $class = shift;
166 75   50     171 my $func = shift || die "Bad call to $class\::TIEHASH";
167 75         191 bless $func, $class;
168             }
169              
170             sub FETCH
171             {
172 221     221   4012587 my $self = shift;
173 221         410 my $key = shift;
174 221         3205 my @args = split $;, $key, -1;
175 221         883 $self->(@args);
176             }
177              
178 25         129 use subs qw(
179 25     25   13102 STORE EXISTS CLEAR FIRSTKEY NEXTKEY );
  25         731  
180             *STORE = *EXISTS = *CLEAR = *FIRSTKEY = *NEXTKEY = sub
181             {
182 2     2   1077 my ($pkg,$file,$line) = caller;
183 2         13 _croak "Invalid call to Time::Format internal function at $file line $line.";
184             };
185              
186              
187             # Module finder -- do we have the specified module available?
188             {
189             my %have;
190             sub _have
191             {
192 364   50 364   20109 my $module = shift || return;
193 364 100       1347 return $have{$module} if exists $have{$module};
194              
195 18         53 my $incmod = $module;
196 18         103 $incmod =~ s!::!/!g;
197 18 100       160 return $have{$module} = 1 if exists $INC{"$incmod.pm"};
198              
199 5         29 $@ = '';
200 5         449 eval "require $module";
201 5 50       445048 return $have{$module} = $@? 0 : 1;
202             }
203             }
204              
205              
206             # POSIX strftime, for people who like those weird % formats.
207             sub time_strftime
208             {
209             # Check if POSIX is available (why wouldn't it be?)
210 14 50   14 1 736 return 'NO_POSIX' unless _have('POSIX');
211              
212 14         61 my $fmt = shift;
213 14         31 my @time;
214              
215             # If more than one arg, assume they're doing the whole arg list
216 14 100       49 if (@_ > 1)
217             {
218 1         4 @time = @_;
219             }
220             else # use unix time (current or passed)
221             {
222 13 100       34 my $time = @_? shift : time;
223 13         287 @time = localtime $time;
224             }
225              
226 14         449 return POSIX::strftime($fmt, @time);
227             }
228              
229              
230             # Date::Manip interface
231             sub time_manip
232             {
233 14 50   14 1 74029 return "NO_DATEMANIP" unless _have('Date::Manip');
234              
235 14         55 my $fmt = shift;
236 14 100       51 my $time = @_? shift : 'now';
237              
238 14 100       75 $time = $1 if $time =~ /^\s* (epoch \s+ \d+)/x;
239              
240 14         51 return Date::Manip::UnixDate($time, $fmt);
241             }
242              
243              
244             1;
245             __DATA__
246             # The following is only compiled if Time::Format_XS is not available.
247             #line 248 "Time/Format.pm"
248              
249             use Time::Local;
250              
251             # Default names for months, days
252             my %english_names =
253             (
254             Month => [qw[January February March April May June July August September October November December]],
255             Weekday => [qw[Sunday Monday Tuesday Wednesday Thursday Friday Saturday]],
256             th => [qw[/th st nd rd th th th th th th th th th th th th th th th th th st nd rd th th th th th th th st]],
257             );
258             my %names;
259             my $locale;
260             my %loc_cache; # Cache for remembering times that have already been parsed out.
261             my $cache_size=0; # Number of keys in %loc_cache
262             my $cache_size_limit = 1024; # Max number of times to cache
263              
264             # Internal function to initialize locale info.
265             # Returns true if the locale changed.
266             sub setup_locale
267             {
268             # Do nothing if locale has not changed since %names was set up.
269             my $locale_in_use;
270             $locale_in_use = POSIX::setlocale(POSIX::LC_TIME()) if _have('POSIX');
271             $locale_in_use = '' if !defined $locale_in_use;
272             return if defined $locale && $locale eq $locale_in_use;
273              
274             my (@Month, @Mon, @Weekday, @Day);
275              
276             unless (eval {
277             require I18N::Langinfo;
278             I18N::Langinfo->import(qw(langinfo));
279             @Month = map langinfo($_), I18N::Langinfo::MON_1(), I18N::Langinfo::MON_2(), I18N::Langinfo::MON_3(),
280             I18N::Langinfo::MON_4(), I18N::Langinfo::MON_5(), I18N::Langinfo::MON_6(),
281             I18N::Langinfo::MON_7(), I18N::Langinfo::MON_8(), I18N::Langinfo::MON_9(),
282             I18N::Langinfo::MON_10(), I18N::Langinfo::MON_11(), I18N::Langinfo::MON_12();
283             @Mon = map langinfo($_), I18N::Langinfo::ABMON_1(), I18N::Langinfo::ABMON_2(), I18N::Langinfo::ABMON_3(),
284             I18N::Langinfo::ABMON_4(), I18N::Langinfo::ABMON_5(), I18N::Langinfo::ABMON_6(),
285             I18N::Langinfo::ABMON_7(), I18N::Langinfo::ABMON_8(), I18N::Langinfo::ABMON_9(),
286             I18N::Langinfo::ABMON_10(), I18N::Langinfo::ABMON_11(), I18N::Langinfo::ABMON_12();
287             @Weekday = map langinfo($_), I18N::Langinfo::DAY_1(), I18N::Langinfo::DAY_2(), I18N::Langinfo::DAY_3(),
288             I18N::Langinfo::DAY_4(), I18N::Langinfo::DAY_5(), I18N::Langinfo::DAY_6(), I18N::Langinfo::DAY_7();
289             @Day = map langinfo($_), I18N::Langinfo::ABDAY_1(), I18N::Langinfo::ABDAY_2(), I18N::Langinfo::ABDAY_3(),
290             I18N::Langinfo::ABDAY_4(), I18N::Langinfo::ABDAY_5(), I18N::Langinfo::ABDAY_6(), I18N::Langinfo::ABDAY_7();
291             1;
292             }
293             )
294             { # Internationalization didn't work for some reason; go with English.
295             @Month = @{ $english_names{Month} };
296             @Weekday = @{ $english_names{Weekday} };
297             @Mon = map substr($_,0,3), @Month;
298             @Day = map substr($_,0,3), @Weekday;
299             $@ = '';
300             }
301              
302             # Store in %names, setting proper case
303             $names{Month} = \@Month;
304             $names{Weekday} = \@Weekday;
305             $names{Mon} = \@Mon;
306             $names{Day} = \@Day;
307             $names{th} = $english_names{th};
308             $names{TH} = [map uc, @{$names{th}}];
309              
310             foreach my $name (keys %names)
311             {
312             my $aref = $names{$name}; # locale-native case
313             $names{uc $name} = [map uc, @$aref]; # upper=case
314             $names{lc $name} = [map lc, @$aref]; # lower-case
315             }
316              
317             %loc_cache = (); # locale changes are rare. Clear out cache.
318             $cache_size = 0;
319             $locale = $locale_in_use;
320              
321             return 1;
322             }
323              
324             # Types of time values we can handle:
325             my $NUMERIC_TIME = \&decode_epoch;
326             my $DATETIME_OBJECT = \&decode_DateTime_object;
327             my $DATETIME_STRING = \&decode_DateTime_string;
328             # my $DATEMANIP_STRING = \&decode_DateManip_string;
329              
330             # What kind of argument was passed to time_format?
331             # Returns (type, time, cache_time_key, milliseconds, microseconds)
332             sub _classify_time
333             {
334             my $timeval = shift;
335             $timeval = 'time' if !defined $timeval;
336              
337             my $frac; # Fractional seconds, if any
338             my $cache_value; # 1/20 of 1 cent
339             my $time_type;
340              
341             # DateTime object?
342             if (UNIVERSAL::isa($timeval, 'DateTime'))
343             {
344             $cache_value = "$timeval"; # stringify
345             $frac = $timeval->nanosecond() / 1e9;
346             $time_type = $DATETIME_OBJECT;
347             }
348             # Numeric time?
349             # 1 to 11 digits-- Epoch time should be <= 10 digits, and 12 digits might be YYYYMMDDHHMM.
350             elsif ($timeval =~ /^\s* ( (\d{1,11}) (?:[.,](\d+))? ) $/x)
351             {
352             $timeval = $1;
353             $cache_value = $2;
354             $frac = $3? '0.' . $3 : 0;
355             $time_type = $NUMERIC_TIME;
356             }
357             # Stringified DateTime object?
358             # Except we make it more flexible by allowing the date OR the time to be specfied
359             # This will also match Date::Manip strings, and many ISO-8601 strings.
360             elsif ($timeval =~ m{\A( (?!\d{6,8}\z) # string must not consist of only 6 or 8 digits.
361             (?: # year-month-day
362             \d{4} # year
363             [-/.]? (?:0[1-9]|1[0-2]) # month
364             [-/.]? (?:0[1-9]|[12]\d|3[01]) # day
365             )? # ymd is optional
366             (?: (?<=\d) [T_ ] (?=\d) )? # separator: T or _ or space, but only if ymd and hms both present
367             ) # End of $1: YMD and separator
368             (?: # hms is optional
369             (
370             (?:[01]\d|2[0-4]) # hour
371             [:.]? (?:[0-5]\d) # minute
372             [:.]? (?:[0-5]\d|6[0-1])? # second
373             ) # End of $2: HMS
374             (?: [,.] (\d+))? # optional fraction
375             (Z?) # optional "zulu" (UTC) designator
376             )? # end of optional (HMS.fraction)
377             \z
378             }x)
379             {
380             $cache_value = ($1 || q{}) . ($2 || q{}) . ($4 || q{});
381             $frac = $3? '0.' . $3 : 0;
382             $time_type = $DATETIME_STRING;
383             }
384             # Not set, or set to 'time' string?
385             elsif ($timeval eq 'time' || $timeval eq q{})
386             {
387             # Get numeric time
388             $timeval = _have('Time::HiRes')? Time::HiRes::time() : time;
389             $cache_value = int $timeval;
390             $frac = $timeval - $cache_value;
391             $time_type = $NUMERIC_TIME;
392             }
393             # *Tiny* numeric time (very close to zero; exponential notation)?
394             # (See bug 87484, https://rt.cpan.org/Ticket/Display.html?id=87484)
395             elsif ($timeval =~ /^\s* -? \d\.\d+ e-\d+ \s*$/x)
396             {
397             $timeval = sprintf '%8.6f', abs($timeval);
398             $cache_value = int $timeval;
399             $frac = $timeval - $cache_value;
400             $time_type = $NUMERIC_TIME;
401             }
402             else
403             {
404             # User passed us something we don't know how to handle.
405             _croak qq{Unrecognized time value: "$timeval"};
406             }
407             # We messed up.
408             die qq{Illegal time type "$time_type"; programming error in Time::Format. Contact author.}
409             if !defined &$time_type;
410              
411             # Calculate millisecond, microsecond from fraction
412             # msec and usec are TRUNCATED, not ROUNDED, because rounding up
413             # to the next higher second would be a nightmare.
414             my $msec = sprintf '%03d', int ( 1_000 * $frac);
415             my $usec = sprintf '%06d', int (1_000_000 * $frac);
416              
417             return ($time_type, $timeval, $cache_value, $msec, $usec);
418             }
419              
420             # Helper function -- returns localtime() hashref
421             sub _loctime
422             {
423             my ($decode, $time, $cachekey, $msec, $usec) = _classify_time(@_);
424             my $locale_changed = setup_locale;
425              
426             # Cached, because I expect this'll be called on the same time values frequently.
427             die "Programming error: undefined cache value. Contact Time::Format author."
428             if !defined $cachekey;
429              
430             # If locale has changed, can't use the cached value.
431             if (!$locale_changed && exists $loc_cache{$cachekey})
432             {
433             my $h = $loc_cache{$cachekey};
434             ($h->{mmm}, $h->{uuuuuu}) = ($msec, $usec);
435             return $h;
436             }
437              
438             # Hour-12, time zone, localtime parts, decoded from input
439             my ($h12, $tz, @time_parts) = $decode->($time);
440              
441             # Populate a whole mess o' data elements
442             my %th;
443             my $m0 = $time_parts[4] - 1; # zero-based month
444              
445             # NOTE: When adding new codes, be wary of adding any that interfere
446             # with the user's ability to use the words "at", "on", or "of" literally.
447              
448             # year, hour(12), month, day, hour, minute, second, millisecond, microsecond, time zone
449             @th{qw[yyyy H m{on} d h m{in} s mmm uuuuuu tz]} = ( $time_parts[5], $h12, @time_parts[4,3,2,1,0], $msec, $usec, $tz);
450             @th{qw[yy HH mm{on} dd hh mm{in} ss]} = map $_<10?"0$_":$_, $time_parts[5]%100, $h12, @time_parts[4,3,2,1,0];
451             @th{qw[ ?H ?m{on} ?d ?h ?m{in} ?s]} = map $_<10?" $_":$_, $h12, @time_parts[4,3,2,1,0];
452              
453             # AM/PM
454             my ($h,$d,$wx) = @time_parts[2,3,6]; # Day, weekday index
455             my $a = $h<12? 'a' : 'p';
456             $th{am} = $th{pm} = $a . 'm';
457             $th{'a.m.'} = $th{'p.m.'} = $a . '.m.';
458             @th{qw/AM PM A.M. P.M./} = map uc, @th{qw/am pm a.m. p.m./};
459              
460             $th{$_} = $names{$_}[$wx] for qw/Weekday WEEKDAY weekday Day DAY day/;
461             $th{$_} = $names{$_}[$m0] for qw/Month MONTH month Mon MON mon/;
462             $th{$_} = $names{$_}[$d] for qw/th TH/;
463              
464             # Don't let the time cache grow boundlessly.
465             if (++$cache_size == $cache_size_limit)
466             {
467             $cache_size = 0;
468             %loc_cache = ();
469             }
470             return $loc_cache{$cachekey} = \%th;
471             }
472              
473             sub decode_DateTime_object
474             {
475             my $dt = shift;
476              
477             my @t = ($dt->hour_12, $dt->time_zone_short_name,
478             $dt->second, $dt->minute, $dt->hour,
479             $dt->day, $dt->month, $dt->year,
480             $dt->dow, $dt->doy, $dt->is_dst);
481             $t[-3] = 0 if $t[-3] == 7; # Convert 1-7 (Mon-Sun) to 0-6 (Sun-Sat).
482              
483             return @t;
484             }
485              
486             # 2005-10-31T15:14:39
487             sub decode_DateTime_string
488             {
489             my $dts = shift;
490             unless ($dts =~ m{\A (?!>\d{6,8}\z) # string must not consist of only 6 or 8 digits.
491             (?:
492             (\d{4}) [-/.]? (\d{2}) [-/.]? (\d{2}) # year-month-day
493             )? # ymd is optional, but next must not be digit
494             (?: (?<=\d) [T_ ] (?=\d) )? # separator: T or _ or space, but only if ymd and hms both present
495             (?: # hms is optional
496             (\d{2}) [:.]? (\d{2}) [:.]? (\d{2}) # hour:minute:second
497             (?: [,.] \d+)? # optional fraction (ignored in this sub)
498             (Z?) # optional "zulu" (UTC) indicator
499             )? \z
500             }x)
501             {
502             # This "should" never happen, since we checked the format of
503             # the string already.
504             die qq{Unrecognized DateTime string "$dts": probable Time::Format bug};
505             }
506              
507             my ($y,$mon,$d,$h,$min,$s,$tz) = ($1,$2,$3,$4,$5,$6,$7);
508             my ($d_only, $t_only);
509             my ($h12, $is_dst, $dow);
510             if (!defined $y)
511             {
512             # Time only. Set date to 1969-12-31.
513             $y = 1969;
514             $mon = 12;
515             $d = 31;
516             $h12 = $h == 0? 12
517             : $h > 12? $h - 12
518             : $h;
519             $is_dst = 0; # (it's the dead of winter!)
520             $dow = 3; # 12/31/1969 is Wednesday.
521             $t_only = 1;
522             }
523             if (!defined $h)
524             {
525             $h = 0;
526             $min = 0;
527             $s = 0;
528             $d_only = 1;
529             }
530              
531             if (!$t_only)
532             {
533             $h12 = $h == 0? 12
534             : $h > 12? $h - 12
535             : $h;
536              
537             # DST?
538             # If year is before 1970, use current year.
539             my $tmp_year = $y > 1969? $y : (localtime)[5]+1900;
540             my $ttime = timelocal(0, 0, 0, $d, $mon-1, $tmp_year);
541             my @t = localtime $ttime;
542             $is_dst = $t[8];
543             $dow = _dow($y, $mon, $d);
544             }
545              
546             # +0 is to force numeric (remove leading zeroes)
547             my @t = map {$_+0} ($s,$min,$h,$d,$mon,$y);
548             $h12 += 0;
549              
550             if ($tz && $tz eq 'Z')
551             {
552             $tz = 'UTC';
553             }
554             elsif (_have('POSIX'))
555             {
556             $tz = POSIX::strftime('%Z', @t, $dow, -1, $is_dst);
557             }
558              
559             return ($h12, $tz, @t, $dow, -1, $is_dst);
560             }
561              
562             sub decode_epoch
563             {
564             my $time = shift; # Assumed to be an epoch time integer
565              
566             my @t = localtime $time;
567             my $tz = _have('POSIX')? POSIX::strftime('%Z', @t) : '';
568             my $h = $t[2]; # Hour (24), Month index
569             $t[4]++;
570             $t[5] += 1900;
571             my $h12 = $h>12? $h-12 : ($h || 12);
572              
573             return ($h12, $tz, @t);
574             }
575              
576             # $int = dow ($year, $month, $day);
577             #
578             # Returns the day of the week (0=Sunday .. 6=Saturday). Uses Zeller's
579             # congruence, so it isn't subject to the unix 2038 limitation.
580             #
581             #---> $int = dow ($year, $month, $day);
582             sub _dow
583             {
584             my ($Y, $M, $D) = @_;
585              
586             $M -= 2;
587             if ($M < 1)
588             {
589             $M += 12;
590             $Y--;
591             }
592             my $C = int($Y/100);
593             $Y %= 100;
594              
595             return (int((26*$M - 2)/10) + $D + $Y + int($Y/4) + int($C/4) - 2*$C) % 7;
596             }
597              
598              
599             # The heart of the module. Didja ever see so many wicked regexes in a row?
600              
601             my %disam; # Disambiguator for 'm' format.
602             $disam{$_} = "{on}" foreach qw/yy d dd ?d/; # If year or day is nearby, it's 'month'
603             $disam{$_} = "{in}" foreach qw/h hh ?h H HH ?H s ss ?s/; # If hour or second is nearby, it's 'minute'
604             sub time_format_perlonly
605             {
606             my $fmt = shift;
607             my $time = _loctime(@_);
608              
609             # Remove \Q...\E sequences
610             my $rc;
611             if (index($fmt, '\Q') >= 0)
612             {
613             $rc = init_store($fmt);
614             $fmt =~ s/\\Q(.*?)(?:\\E|$)/remember($1)/seg;
615             }
616              
617             # "Guess" how to interpret ambiguous 'm'
618             $fmt =~ s/
619             (?<!\\) # Must not follow a backslash
620             (?=[ydhH]) # Must start with one of these
621             ( # $1 begins
622             ( # $2 begins. Capture:
623             yy # a year
624             | [dhH] # a day or hour
625             )
626             [^?m\\]? # Followed by something that's not part of a month
627             )
628             (?![?m]?m\{[io]n\}) # make sure it's not already unambiguous
629             (?!mon) # don't confuse "mon" with "m" "on"
630             ([?m]?m) # $3 is a month code
631             /$1$3$disam{$2}/gx;
632              
633             # Ambiguous 'm', part 2.
634             $fmt =~ s/(?<!\\) # ignore things that begin with backslash
635             ([?m]?m) # $1 is a month code
636             ( # $2 begins.
637             [^\\]? # 0 or 1 characters
638             (?=[?dsy]) # Next char must be one of these
639             ( # $3 begins. Capture:
640             \??[ds] # a day or a second
641             | yy # or a year
642             )
643             )/$1$disam{$3}$2/gx;
644              
645             # The Big Date/Time Pattern of Doom
646             $fmt =~ s/
647             (?<!\\) # Don't expand something preceded by backslash
648             (?=[dDy?hHsaApPMmWwutT]) # Jump to one of these characters
649             (
650             [Dd]ay|DAY # Weekday abbreviation
651             | yy(?:yy)? # Year
652             | [?m]?m\{[oi]n\} # Unambiguous month-minute codes
653             | th | TH # day suffix
654             | [?d]?d # Day
655             | [?h]?h # Hour (24)
656             | [?H]?H # Hour (12)
657             | [?s]?s # Second
658             | [apAP]\.?[mM]\.? # am and pm strings
659             | [Mm]on(?:th)?|MON(?:TH)? # Month names and abbrev
660             | [Ww]eekday|WEEKDAY # Weekday names
661             | mmm|uuuuuu # millisecond and microsecond
662             | tz # time zone
663             )/$time->{$1}/gx;
664              
665             # Simulate \U \L \u \l
666             $fmt =~ s/((?:\\[UL])+)((?:\\[ul])+)/$2$1/g;
667             $fmt =~ s/\\U(.*?)(?=\\[EULul]|$)/\U$1/gs;
668             $fmt =~ s/\\L(.*?)(?=\\[EULul]|$)/\L$1/gs;
669             $fmt =~ s/\\l(.)/\l$1/gs;
670             $fmt =~ s/\\u(.)/\u$1/gs;
671             $fmt =~ s/\\E//g;
672              
673             $fmt =~ tr/\\//d; # Remove extraneous backslashes.
674              
675             if (defined $rc) # Fixup \Q \E regions.
676             {
677             $fmt =~ s/$rc(..)/recall($1)/seg;
678             }
679             return $fmt;
680             }
681              
682             # Code for remembering/restoring \Q...\E regions.
683             # init_store finds a sigil character that's not used within the format string.
684             # remember stores a string in the next slot in @store, and returns a coded replacement.
685             # recall looks up and returns a string from @store.
686             {
687             my $rcode;
688             my @store;
689             my $stx;
690              
691             sub init_store
692             {
693             my $str = shift;
694             $stx = 0;
695             return $rcode = "\x01" unless index($str,"\x01") >= 0;
696              
697             for ($rcode="\x02"; $rcode<"\xFF"; $rcode=chr(1+ord $rcode))
698             {
699             return $rcode unless index($str, $rcode) >= 0;
700             }
701             _croak "Time::Format cannot process string: no unique characters left.";
702             }
703              
704             sub remember
705             {
706             my $enc;
707             do # Must not return a code that contains a backslash
708             {
709             $enc = pack 'S', $stx++;
710             } while index($enc, '\\') >= 0;
711              
712             $store[$stx-1] = shift;
713             return join '', map "\\$_", split //, "$rcode$enc"; # backslash-escape it!
714             }
715              
716             sub recall
717             {
718             return $store[unpack 'S', shift];
719             }
720             }
721              
722             __END__
723              
724             =head1 SYNOPSIS
725              
726             use Time::Format qw(%time %strftime %manip);
727              
728             $time{$format}
729             $time{$format, $unixtime}
730              
731             print "Today is $time{'yyyy/mm/dd'}\n";
732             print "Yesterday was $time{'yyyy/mm/dd', time-24*60*60}\n";
733             print "The time is $time{'hh:mm:ss'}\n";
734             print "Another time is $time{'H:mm am tz', $another_time}\n";
735             print "Timestamp: $time{'yyyymmdd.hhmmss.mmm'}\n";
736              
737             C<%time> also accepts Date::Manip strings and DateTime objects:
738              
739             $dm = Date::Manip::ParseDate('last monday');
740             print "Last monday was $time{'Month d, yyyy', $dm}";
741             $dt = DateTime->new (....);
742             print "Here's another date: $time{'m/d/yy', $dt}";
743              
744             It also accepts most ISO-8601 date/time strings:
745              
746             $t = '2005/10/31T17:11:09'; # date separator: / or - or .
747             $t = '2005-10-31 17.11.09'; # in-between separator: T or _ or space
748             $t = '20051031_171109'; # time separator: : or .
749             $t = '20051031171109'; # separators may be omitted
750             $t = '2005/10/31'; # date-only is okay
751             $t = '17:11:09'; # time-only is okay
752             # But not:
753             $t = '20051031'; # date-only without separators
754             $t = '171109'; # time-only without separators
755             # ...because those look like epoch time numbers.
756              
757             C<%strftime> works like POSIX's C<strftime>, if you like those C<%>-formats.
758              
759             $strftime{$format}
760             $strftime{$format, $unixtime}
761             $strftime{$format, $sec,$min,$hour, $mday,$mon,$year, $wday,$yday,$isdst}
762              
763             print "POSIXish: $strftime{'%A, %B %d, %Y', 0,0,0,12,11,95,2}\n";
764             print "POSIXish: $strftime{'%A, %B %d, %Y', 1054866251}\n";
765             print "POSIXish: $strftime{'%A, %B %d, %Y'}\n"; # current time
766              
767             C<%manip> works like Date::Manip's C<UnixDate> function.
768              
769             $manip{$format};
770             $manip{$format, $when};
771              
772             print "Date::Manip: $manip{'%m/%d/%Y'}\n"; # current time
773             print "Date::Manip: $manip{'%m/%d/%Y','last Tuesday'}\n";
774              
775             These can also be used as standalone functions:
776              
777             use Time::Format qw(time_format time_strftime time_manip);
778              
779             print "Today is ", time_format('yyyy/mm/dd', $some_time), "\n";
780             print "POSIXish: ", time_strftime('%A %B %d, %Y',$some_time), "\n";
781             print "Date::Manip: ", time_manip('%m/%d/%Y',$some_time), "\n";
782              
783             =head1 DESCRIPTION
784              
785             This module creates global pseudovariables which format dates and
786             times, according to formatting codes you pass to them in strings.
787              
788             The C<%time> formatting codes are designed to be easy to remember and
789             use, and to take up just as many characters as the output time value
790             whenever possible. For example, the four-digit year code is
791             "C<yyyy>", the three-letter month abbreviation is "C<Mon>".
792              
793             The nice thing about having a variable-like interface instead
794             of function calls is that the values can be used inside of strings (as
795             well as outside of strings in ordinary expressions). Dates are
796             frequently used within strings (log messages, output, data records,
797             etc.), so having the ability to interpolate them directly is handy.
798              
799             Perl allows arbitrary expressions within curly braces of a hash, even
800             when that hash is being interpolated into a string. This allows you
801             to do computations on the fly while formatting times and inserting
802             them into strings. See the "yesterday" example above.
803              
804             The format strings are designed with programmers in mind. What do you
805             need most frequently? 4-digit year, month, day, 24-based hour,
806             minute, second -- usually with leading zeroes. These six are the
807             easiest formats to use and remember in Time::Format: C<yyyy>, C<mm>,
808             C<dd>, C<hh>, C<mm>, C<ss>. Variants on these formats follow a simple
809             and consistent formula. This module is for everyone who is weary of
810             trying to remember I<strftime(3)>'s arcane codes, or of endlessly
811             writing C<$t[4]++; $t[5]+=1900> as you manually format times or dates.
812              
813             Note that C<mm> (and related codes) are used both for months and
814             minutes. This is a feature. C<%time> resolves the ambiguity by
815             examining other nearby formatting codes. If it's in the context of a
816             year or a day, "month" is assumed. If in the context of an hour or a
817             second, "minute" is assumed.
818              
819             The format strings are not meant to encompass every date/time need
820             ever conceived. But how often do you need the day of the year
821             (strftime's C<%j>) or the week number (strftime's C<%W>)?
822              
823             For capabilities that C<%time> does not provide, C<%strftime> provides
824             an interface to POSIX's C<strftime>, and C<%manip> provides an
825             interface to the Date::Manip module's C<UnixDate> function.
826              
827             If the companion module L<Time::Format_XS> is also installed,
828             Time::Format will detect and use it. This will result in a
829             significant speed increase for C<%time> and C<time_format>.
830              
831             =head1 VARIABLES
832              
833             =over 4
834              
835             =item time
836              
837             $time{$format}
838             $time{$format,$time_value};
839              
840             Formats a unix time number (seconds since the epoch), DateTime object,
841             stringified DateTime, Date::Manip string, or ISO-8601 string,
842             according to the specified format. If the time expression is omitted,
843             the current time is used. The format string may contain any of the
844             following:
845              
846             yyyy 4-digit year
847             yy 2-digit year
848              
849             m 1- or 2-digit month, 1-12
850             mm 2-digit month, 01-12
851             ?m month with leading space if < 10
852              
853             Month full month name, mixed-case
854             MONTH full month name, uppercase
855             month full month name, lowercase
856             Mon 3-letter month abbreviation, mixed-case
857             MON mon ditto, uppercase and lowercase versions
858              
859             d day number, 1-31
860             dd day number, 01-31
861             ?d day with leading space if < 10
862             th day suffix (st, nd, rd, or th)
863             TH uppercase suffix
864              
865             Weekday weekday name, mixed-case
866             WEEKDAY weekday name, uppercase
867             weekday weekday name, lowercase
868             Day 3-letter weekday name, mixed-case
869             DAY day ditto, uppercase and lowercase versions
870              
871             h hour, 0-23
872             hh hour, 00-23
873             ?h hour, 0-23 with leading space if < 10
874              
875             H hour, 1-12
876             HH hour, 01-12
877             ?H hour, 1-12 with leading space if < 10
878              
879             m minute, 0-59
880             mm minute, 00-59
881             ?m minute, 0-59 with leading space if < 10
882              
883             s second, 0-59
884             ss second, 00-59
885             ?s second, 0-59 with leading space if < 10
886             mmm millisecond, 000-999
887             uuuuuu microsecond, 000000-999999
888              
889             am a.m. The string "am" or "pm" (second form with periods)
890             pm p.m. same as "am" or "a.m."
891             AM A.M. same as "am" or "a.m." but uppercase
892             PM P.M. same as "AM" or "A.M."
893              
894             tz time zone abbreviation
895              
896             Millisecond and microsecond require Time::HiRes, otherwise they'll
897             always be zero. Timezone requires POSIX, otherwise it'll be the empty
898             string. The second codes (C<s>, C<ss>, C<?s>) can be 60 or 61 in rare
899             circumstances (leap seconds, if your system supports such).
900              
901             Anything in the format string other than the above patterns is left
902             intact. Any character preceded by a backslash is left alone and
903             not used for any part of a format code. See the L</QUOTING> section
904             for more details.
905              
906             For the most part, each of the above formatting codes takes up as much
907             space as the output string it generates. The exceptions are the codes
908             whose output is variable length: C<Weekday>, C<Month>, time zone, and
909             the single-character codes.
910              
911             The mixed-case "Month", "Mon", "Weekday", and "Day" codes return the
912             name of the month or weekday in the preferred case representation for
913             the locale currently in effect. Thus in an English-speaking locale,
914             the seventh month would be "July" (uppercase first letter, lowercase
915             rest); while in a French-speaking locale, it would be "juillet" (all
916             lowercase). See the L</QUOTING> section for ways to control the case
917             of month/weekday names.
918              
919             Note that the "C<mm>", "C<m>", and "C<?m>" formats are ambiguous.
920             C<%time> tries to guess whether you meant "month" or "minute" based on
921             nearby characters in the format string. Thus, a format of
922             "C<yyyy/mm/dd hh:mm:ss>" is correctly parsed as "year month day, hour
923             minute second". If C<%time> cannot determine whether you meant
924             "month" or "minute", it leaves the C<mm>, C<m>, or C<?m> untranslated.
925             To remove the ambiguity, you can use the following codes:
926              
927             m{on} month, 1-12
928             mm{on} month, 01-12
929             ?m{on} month, 1-12 with leading space if < 10
930              
931             m{in} minute, 0-59
932             mm{in} minute, 00-59
933             ?m{in} minute, 0-59 with leading space if < 10
934              
935             In other words, append "C<{on}>" or "C<{in}>" to make "C<m>", "C<mm>",
936             or "C<?m>" unambiguous.
937              
938             =item strftime
939              
940             $strftime{$format, $sec,$min,$hour, $mday,$mon,$year, $wday,$yday,$isdst}
941             $strftime{$format, $unixtime}
942             $strftime{$format}
943              
944             For those who prefer L<strftime|POSIX/strftime>'s weird % formats, or
945             who need POSIX compliance, or who need week numbers or other features
946             C<%time> does not provide.
947              
948             =item manip
949              
950             $manip{$format};
951             $manip{$format,$when};
952              
953             Provides an interface to the Date::Manip module's C<UnixDate>
954             function. This function is rather slow, but can parse a very wide
955             variety of date input. See the L<Date::Manip> module for details
956             about the inputs accepted.
957              
958             If you want to use the C<%time> codes, but need the input flexibility
959             of C<%manip>, you can use Date::Manip's C<ParseDate> function:
960              
961             print "$time{'yyyymmdd', ParseDate('last sunday')}";
962              
963             =back
964              
965             =head1 FUNCTIONS
966              
967             =over 4
968              
969             =item time_format
970              
971             time_format($format);
972             time_format($format, $unix_time);
973              
974             This is a function interface to C<%time>. It accepts the same
975             formatting codes and everything. This is provided for people who want
976             their function calls to I<look> like function calls, not hashes. :-)
977             The following two are equivalent:
978              
979             $x = $time{'yyyy/mm/dd'};
980             $x = time_format('yyyy/mm/dd');
981              
982             =item time_strftime
983              
984             time_strftime($format, $sec,$min,$hour, $mday,$mon,$year, $wday,$yday,$isdst);
985             time_strftime($format, $unixtime);
986             time_strftime($format);
987              
988             This is a function interface to C<%strftime>. It simply calls
989             POSIX::C<strftime>, but it does provide a bit of an advantage over
990             calling C<strftime> directly, in that you can pass the time as a unix
991             time (seconds since the epoch), or omit it in order to get the current
992             time.
993              
994             =item time_manip
995              
996             manip($format);
997             manip($format,$when);
998              
999             This is a function interface to C<%manip>. It calls
1000             Date::Manip::C<UnixDate> under the hood. It does not provide much of
1001             an advantage over calling C<UnixDate> directly, except that you can
1002             omit the C<$when> parameter in order to get the current time.
1003              
1004             =back
1005              
1006             =head1 QUOTING
1007              
1008             This section applies to the format strings used by C<%time> and
1009             C<time_format> only.
1010              
1011             Sometimes it is necessary to suppress expansion of some format
1012             characters in a format string. For example:
1013              
1014             $time{'Hour: hh; Minute: mm{in}; Second: ss'};
1015              
1016             In the above expression, the "H" in "Hour" would be expanded,
1017             as would the "d" in "Second". The result would be something like:
1018              
1019             8our: 08; Minute: 10; Secon17: 30
1020              
1021             It would not be a good solution to break the above statement out
1022             into three calls to %time:
1023              
1024             "Hour: $time{hh}; Minute: $time{'mm{in}'}; Second: $time{ss}"
1025              
1026             because the time could change from one call to the next, which would
1027             be a problem when the numbers roll over (for example, a split second
1028             after 7:59:59).
1029              
1030             For this reason, you can escape individual format codes with a
1031             backslash:
1032              
1033             $time{'\Hour: hh; Minute: mm{in}; Secon\d: ss'};
1034              
1035             Note that with double-quoted (and qq//) strings, the backslash must be
1036             doubled, because Perl first interpolates the string:
1037              
1038             $time{"\\Hour: hh; Minute: mm{in}; Secon\\d: ss"};
1039              
1040             For added convenience, Time::Format simulates Perl's built-in \Q and
1041             \E inline quoting operators. Anything in a string between a \Q and \E
1042             will not be interpolated as any part of any formatting code:
1043              
1044             $time{'\QHour:\E hh; \QMinute:\E mm{in}; \QSecond:\E ss'};
1045              
1046             Again, within interpolated strings, the backslash must be doubled, or
1047             else Perl will interpret and remove the \Q...\E sequence before
1048             Time::Format gets it:
1049              
1050             $time{"\\QHour:\\E hh; \\QMinute:\\E mm{in}; \\QSecond\\E: ss"};
1051              
1052             Time::Format also recognizes and simulates the \U, \L, \u, and \l
1053             sequences. This is really only useful for finer control of the Month,
1054             Mon, Weekday, and Day formats. For example, in some locales, the
1055             month names are all-lowercase by convention. At the start of a
1056             sentence, you may want to ensure that the first character is
1057             uppercase:
1058              
1059             $time{'\uMonth \Qis the finest month of all.'};
1060              
1061             Again, be sure to use \Q, and be sure to double the backslashes in
1062             interpolated strings, otherwise you'll get something ugly like:
1063              
1064             July i37 ste fine37t july of all.
1065              
1066             =head1 EXAMPLES
1067              
1068             $time{'Weekday Month d, yyyy'} Thursday June 5, 2003
1069             $time{'Day Mon d, yyyy'} Thu Jun 5, 2003
1070             $time{'dd/mm/yyyy'} 05/06/2003
1071             $time{yymmdd} 030605
1072             $time{'yymmdd',time-86400} 030604
1073             $time{'dth of Month'} 5th of June
1074              
1075             $time{'H:mm:ss am'} 1:02:14 pm
1076             $time{'hh:mm:ss.uuuuuu'} 13:02:14.171447
1077              
1078             $time{'yyyy/mm{on}/dd hh:mm{in}:ss.mmm'} 2003/06/05 13:02:14.171
1079             $time{'yyyy/mm/dd hh:mm:ss.mmm'} 2003/06/05 13:02:14.171
1080              
1081             $time{"It's H:mm."} It'14 1:02. # OOPS!
1082             $time{"It'\\s H:mm."} It's 1:02. # Backslash fixes it.
1083             .
1084             .
1085             # Rename a file based on today's date:
1086             rename $file, "$file_$time{yyyymmdd}";
1087              
1088             # Rename a file based on its last-modify date:
1089             rename $file, "$file_$time{'yyyymmdd',(stat $file)[9]}";
1090              
1091             # stftime examples
1092             $strftime{'%A %B %d, %Y'} Thursday June 05, 2003
1093             $strftime{'%A %B %d, %Y',time+86400} Friday June 06, 2003
1094              
1095             # manip examples
1096             $manip{'%m/%d/%Y'} 06/05/2003
1097             $manip{'%m/%d/%Y','yesterday'} 06/04/2003
1098             $manip{'%m/%d/%Y','first monday in November 2000'} 11/06/2000
1099              
1100             =head1 INTERNATIONALIZATION
1101              
1102             If the I18N::Langinfo module is available, Time::Format will return
1103             weekday and month names in the language appropriate for the current
1104             locale. If not, English names will be used.
1105              
1106             Programmers in non-English locales may want to provide an alias to
1107             C<%time> in their own preferred language. This can be done by
1108             assigning C<\%time> to a typeglob:
1109              
1110             # French
1111             use Time::Format;
1112             use vars '%temps'; *temps = \%time;
1113             print "C'est aujourd'hui le $temps{'d Month'}\n";
1114              
1115             # German
1116             use Time::Format;
1117             use vars '%zeit'; *zeit = \%time;
1118             print "Heutiger Tag ist $zeit{'d.m.yyyy'}\n";
1119              
1120             =head1 EXPORTS
1121              
1122             The following symbols are exported into your namespace by default:
1123              
1124             %time
1125             time_format
1126              
1127             The following symbols are available for import into your namespace:
1128              
1129             %strftime
1130             %manip
1131             time_strftime
1132             time_manip
1133              
1134             The C<:all> tag will import all of these into your namespace.
1135             Example:
1136              
1137             use Time::Format ':all';
1138              
1139             =head1 BUGS
1140              
1141             The format string used by C<%time> must not have $; as a substring
1142             anywhere. $; (by default, ASCII character 28, or 1C hex) is used to
1143             separate values passed to the tied hash, and thus Time::Format will
1144             interpret your format string to be two or more arguments if it
1145             contains $;. The C<time_format> function does not have this
1146             limitation.
1147              
1148             =head1 REQUIREMENTS
1149              
1150             Time::Local
1151             I18N::Langinfo, if you want non-English locales to work.
1152             POSIX, if you choose to use %strftime or want the C<tz> format to work.
1153             Time::HiRes, if you want the C<mmm> and C<uuuuuu> time formats to work.
1154             Date::Manip, if you choose to use %manip.
1155              
1156             Time::Format_XS is optional but will make C<%time> and C<time_format>
1157             much faster. The version of Time::Format_XS installed must match
1158             the version of Time::Format installed; otherwise Time::Format will
1159             not use it (and will issue a warning).
1160              
1161             =head1 AUTHOR / COPYRIGHT
1162              
1163             Copyright (c) 2003-2019 by Eric J. Roode, ROODE I<-at-> cpan I<-dot-> org
1164              
1165             All rights reserved.
1166              
1167             To avoid my spam filter, please include "Perl", "module", or this
1168             module's name in the message's subject line, and/or GPG-sign your
1169             message.
1170              
1171             This module is copyrighted only to ensure proper attribution of
1172             authorship and to ensure that it remains available to all. This
1173             module is free, open-source software. This module may be freely used
1174             for any purpose, commercial, public, or private, provided that proper
1175             credit is given, and that no more-restrictive license is applied to
1176             derivative (not dependent) works.
1177              
1178             Substantial efforts have been made to ensure that this software meets
1179             high quality standards; however, no guarantee can be made that there
1180             are no undiscovered bugs, and no warranty is made as to suitability to
1181             any given use, including merchantability. Should this module cause
1182             your house to burn down, your dog to collapse, your heart-lung machine
1183             to fail, your spouse to desert you, or George Bush to be re-elected, I
1184             can offer only my sincere sympathy and apologies, and promise to
1185             endeavor to improve the software.
1186              
1187              
1188             =begin gpg
1189              
1190             -----BEGIN PGP SIGNATURE-----
1191              
1192             iF0EARECAB0WIQTSmjxiQX/QfjsCVJLChJhzmpBWqgUCXTYSngAKCRDChJhzmpBW
1193             qsFsAJ9KgMFSmNmfX0g9DtHvJJjmAz9jygCgkUYdpA4g/pgCo0ejISRR+2qpTwk=
1194             =Ppwj
1195             -----END PGP SIGNATURE-----
1196              
1197             =end gpg