File Coverage

blib/lib/Time/Format.pm
Criterion Covered Total %
statement 79 84 94.0
branch 28 40 70.0
condition 4 6 66.6
subroutine 13 13 100.0
pod 2 2 100.0
total 126 145 86.9


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