1package Time::Piece;
2
3use strict;
4
5use XSLoader ();
6use Time::Seconds;
7use Carp;
8use Time::Local;
9use Scalar::Util qw/ blessed /;
10
11use Exporter ();
12
13our @EXPORT = qw(
14    localtime
15    gmtime
16);
17
18our %EXPORT_TAGS = (
19    ':override' => 'internal',
20    );
21
22our $VERSION = '1.3401_01';
23
24XSLoader::load( 'Time::Piece', $VERSION );
25
26my $DATE_SEP = '-';
27my $TIME_SEP = ':';
28my @MON_LIST = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
29my @FULLMON_LIST = qw(January February March April May June July
30                      August September October November December);
31my @DAY_LIST = qw(Sun Mon Tue Wed Thu Fri Sat);
32my @FULLDAY_LIST = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday);
33my $IS_WIN32 = ($^O =~ /Win32/);
34
35my $LOCALE;
36
37use constant {
38    'c_sec' => 0,
39    'c_min' => 1,
40    'c_hour' => 2,
41    'c_mday' => 3,
42    'c_mon' => 4,
43    'c_year' => 5,
44    'c_wday' => 6,
45    'c_yday' => 7,
46    'c_isdst' => 8,
47    'c_epoch' => 9,
48    'c_islocal' => 10,
49};
50
51sub localtime {
52    unshift @_, __PACKAGE__ unless eval { $_[0]->isa('Time::Piece') };
53    my $class = shift;
54    my $time  = shift;
55    $time = time if (!defined $time);
56    $class->_mktime($time, 1);
57}
58
59sub gmtime {
60    unshift @_, __PACKAGE__ unless eval { $_[0]->isa('Time::Piece') };
61    my $class = shift;
62    my $time  = shift;
63    $time = time if (!defined $time);
64    $class->_mktime($time, 0);
65}
66
67
68# Check if the supplied param is either a normal array (as returned from
69# localtime in list context) or a Time::Piece-like wrapper around one.
70#
71# We need to differentiate between an array ref that we can interrogate and
72# other blessed objects (like overloaded values).
73sub _is_time_struct {
74    return 1 if ref($_[1]) eq 'ARRAY';
75    return 1 if blessed($_[1]) && $_[1]->isa('Time::Piece');
76
77    return 0;
78}
79
80
81sub new {
82    my $class = shift;
83    my ($time) = @_;
84
85    my $self;
86
87    if ($class->_is_time_struct($time)) {
88        $self = $time->[c_islocal] ? $class->localtime($time) : $class->gmtime($time);
89    }
90    elsif (defined($time)) {
91        $self = $class->localtime($time);
92    }
93    elsif (ref($class) && $class->isa(__PACKAGE__)) {
94        $self = $class->_mktime($class->epoch, $class->[c_islocal]);
95    }
96    else {
97        $self = $class->localtime();
98    }
99
100    return bless $self, ref($class) || $class;
101}
102
103sub parse {
104    my $proto = shift;
105    my $class = ref($proto) || $proto;
106    my @components;
107
108    warnings::warnif("deprecated",
109        "parse() is deprecated, use strptime() instead.");
110
111    if (@_ > 1) {
112        @components = @_;
113    }
114    else {
115        @components = shift =~ /(\d+)$DATE_SEP(\d+)$DATE_SEP(\d+)(?:(?:T|\s+)(\d+)$TIME_SEP(\d+)(?:$TIME_SEP(\d+)))/;
116        @components = reverse(@components[0..5]);
117    }
118    return $class->new( timelocal(@components ));
119}
120
121sub _mktime {
122    my ($class, $time, $islocal) = @_;
123
124    $class = blessed($class) || $class;
125
126    if ($class->_is_time_struct($time)) {
127        my @new_time = @$time;
128        my @tm_parts = (@new_time[c_sec .. c_mon], $new_time[c_year]+1900);
129
130        $new_time[c_epoch] = $islocal ? timelocal(@tm_parts) : timegm(@tm_parts);
131
132        return wantarray ? @new_time : bless [@new_time[0..9], $islocal], $class;
133    }
134    _tzset();
135    my @time = $islocal ?
136            CORE::localtime($time)
137                :
138            CORE::gmtime($time);
139    wantarray ? @time : bless [@time, $time, $islocal], $class;
140}
141
142my %_special_exports = (
143  localtime => sub { my $c = $_[0]; sub { $c->localtime(@_) } },
144  gmtime    => sub { my $c = $_[0]; sub { $c->gmtime(@_)    } },
145);
146
147sub export {
148  my ($class, $to, @methods) = @_;
149  for my $method (@methods) {
150    if (exists $_special_exports{$method}) {
151      no strict 'refs';
152      no warnings 'redefine';
153      *{$to . "::$method"} = $_special_exports{$method}->($class);
154    } else {
155      $class->Exporter::export($to, $method);
156    }
157  }
158}
159
160sub import {
161    # replace CORE::GLOBAL localtime and gmtime if passed :override
162    my $class = shift;
163    my %params;
164    map($params{$_}++,@_,@EXPORT);
165    if (delete $params{':override'}) {
166        $class->export('CORE::GLOBAL', keys %params);
167    }
168    else {
169        $class->export(scalar caller, keys %params);
170    }
171}
172
173## Methods ##
174
175sub sec {
176    my $time = shift;
177    $time->[c_sec];
178}
179
180*second = \&sec;
181
182sub min {
183    my $time = shift;
184    $time->[c_min];
185}
186
187*minute = \&min;
188
189sub hour {
190    my $time = shift;
191    $time->[c_hour];
192}
193
194sub mday {
195    my $time = shift;
196    $time->[c_mday];
197}
198
199*day_of_month = \&mday;
200
201sub mon {
202    my $time = shift;
203    $time->[c_mon] + 1;
204}
205
206sub _mon {
207    my $time = shift;
208    $time->[c_mon];
209}
210
211sub month {
212    my $time = shift;
213    if (@_) {
214        return $_[$time->[c_mon]];
215    }
216    elsif (@MON_LIST) {
217        return $MON_LIST[$time->[c_mon]];
218    }
219    else {
220        return $time->strftime('%b');
221    }
222}
223
224*monname = \&month;
225
226sub fullmonth {
227    my $time = shift;
228    if (@_) {
229        return $_[$time->[c_mon]];
230    }
231    elsif (@FULLMON_LIST) {
232        return $FULLMON_LIST[$time->[c_mon]];
233    }
234    else {
235        return $time->strftime('%B');
236    }
237}
238
239sub year {
240    my $time = shift;
241    $time->[c_year] + 1900;
242}
243
244sub _year {
245    my $time = shift;
246    $time->[c_year];
247}
248
249sub yy {
250    my $time = shift;
251    my $res = $time->[c_year] % 100;
252    return $res > 9 ? $res : "0$res";
253}
254
255sub wday {
256    my $time = shift;
257    $time->[c_wday] + 1;
258}
259
260sub _wday {
261    my $time = shift;
262    $time->[c_wday];
263}
264
265*day_of_week = \&_wday;
266
267sub wdayname {
268    my $time = shift;
269    if (@_) {
270        return $_[$time->[c_wday]];
271    }
272    elsif (@DAY_LIST) {
273        return $DAY_LIST[$time->[c_wday]];
274    }
275    else {
276        return $time->strftime('%a');
277    }
278}
279
280*day = \&wdayname;
281
282sub fullday {
283    my $time = shift;
284    if (@_) {
285        return $_[$time->[c_wday]];
286    }
287    elsif (@FULLDAY_LIST) {
288        return $FULLDAY_LIST[$time->[c_wday]];
289    }
290    else {
291        return $time->strftime('%A');
292    }
293}
294
295sub yday {
296    my $time = shift;
297    $time->[c_yday];
298}
299
300*day_of_year = \&yday;
301
302sub isdst {
303    my $time = shift;
304    $time->[c_isdst];
305}
306
307*daylight_savings = \&isdst;
308
309# Thanks to Tony Olekshy <olekshy@cs.ualberta.ca> for this algorithm
310sub tzoffset {
311    my $time = shift;
312
313    return Time::Seconds->new(0) unless $time->[c_islocal];
314
315    my $epoch = $time->epoch;
316
317    my $j = sub {
318
319        my ($s,$n,$h,$d,$m,$y) = @_; $m += 1; $y += 1900;
320
321        $time->_jd($y, $m, $d, $h, $n, $s);
322
323    };
324
325    # Compute floating offset in hours.
326    #
327    # Note use of crt methods so the tz is properly set...
328    # See: http://perlmonks.org/?node_id=820347
329    my $delta = 24 * ($j->(_crt_localtime($epoch)) - $j->(_crt_gmtime($epoch)));
330
331    # Return value in seconds rounded to nearest minute.
332    return Time::Seconds->new( int($delta * 60 + ($delta >= 0 ? 0.5 : -0.5)) * 60 );
333}
334
335sub epoch {
336    my $time = shift;
337    if (defined($time->[c_epoch])) {
338        return $time->[c_epoch];
339    }
340    else {
341        my $epoch = $time->[c_islocal] ?
342          timelocal(@{$time}[c_sec .. c_mon], $time->[c_year]+1900)
343          :
344          timegm(@{$time}[c_sec .. c_mon], $time->[c_year]+1900);
345        $time->[c_epoch] = $epoch;
346        return $epoch;
347    }
348}
349
350sub hms {
351    my $time = shift;
352    my $sep = @_ ? shift(@_) : $TIME_SEP;
353    sprintf("%02d$sep%02d$sep%02d", $time->[c_hour], $time->[c_min], $time->[c_sec]);
354}
355
356*time = \&hms;
357
358sub ymd {
359    my $time = shift;
360    my $sep = @_ ? shift(@_) : $DATE_SEP;
361    sprintf("%d$sep%02d$sep%02d", $time->year, $time->mon, $time->[c_mday]);
362}
363
364*date = \&ymd;
365
366sub mdy {
367    my $time = shift;
368    my $sep = @_ ? shift(@_) : $DATE_SEP;
369    sprintf("%02d$sep%02d$sep%d", $time->mon, $time->[c_mday], $time->year);
370}
371
372sub dmy {
373    my $time = shift;
374    my $sep = @_ ? shift(@_) : $DATE_SEP;
375    sprintf("%02d$sep%02d$sep%d", $time->[c_mday], $time->mon, $time->year);
376}
377
378sub datetime {
379    my $time = shift;
380    my %seps = (date => $DATE_SEP, T => 'T', time => $TIME_SEP, @_);
381    return join($seps{T}, $time->date($seps{date}), $time->time($seps{time}));
382}
383
384
385
386# Julian Day is always calculated for UT regardless
387# of local time
388sub julian_day {
389    my $time = shift;
390    # Correct for localtime
391    $time = $time->gmtime( $time->epoch ) if $time->[c_islocal];
392
393    # Calculate the Julian day itself
394    my $jd = $time->_jd( $time->year, $time->mon, $time->mday,
395                        $time->hour, $time->min, $time->sec);
396
397    return $jd;
398}
399
400# MJD is defined as JD - 2400000.5 days
401sub mjd {
402    return shift->julian_day - 2_400_000.5;
403}
404
405# Internal calculation of Julian date. Needed here so that
406# both tzoffset and mjd/jd methods can share the code
407# Algorithm from Hatcher 1984 (QJRAS 25, 53-55), and
408#  Hughes et al, 1989, MNRAS, 238, 15
409# See: http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode=1989MNRAS.238.1529H&db_key=AST
410# for more details
411
412sub _jd {
413    my $self = shift;
414    my ($y, $m, $d, $h, $n, $s) = @_;
415
416    # Adjust input parameters according to the month
417    $y = ( $m > 2 ? $y : $y - 1);
418    $m = ( $m > 2 ? $m - 3 : $m + 9);
419
420    # Calculate the Julian Date (assuming Julian calendar)
421    my $J = int( 365.25 *( $y + 4712) )
422      + int( (30.6 * $m) + 0.5)
423        + 59
424          + $d
425            - 0.5;
426
427    # Calculate the Gregorian Correction (since we have Gregorian dates)
428    my $G = 38 - int( 0.75 * int(49+($y/100)));
429
430    # Calculate the actual Julian Date
431    my $JD = $J + $G;
432
433    # Modify to include hours/mins/secs in floating portion.
434    return $JD + ($h + ($n + $s / 60) / 60) / 24;
435}
436
437sub week {
438    my $self = shift;
439
440    my $J  = $self->julian_day;
441    # Julian day is independent of time zone so add on tzoffset
442    # if we are using local time here since we want the week day
443    # to reflect the local time rather than UTC
444    $J += ($self->tzoffset/(24*3600)) if $self->[c_islocal];
445
446    # Now that we have the Julian day including fractions
447    # convert it to an integer Julian Day Number using nearest
448    # int (since the day changes at midday we convert all Julian
449    # dates to following midnight).
450    $J = int($J+0.5);
451
452    use integer;
453    my $d4 = ((($J + 31741 - ($J % 7)) % 146097) % 36524) % 1461;
454    my $L  = $d4 / 1460;
455    my $d1 = (($d4 - $L) % 365) + $L;
456    return $d1 / 7 + 1;
457}
458
459sub _is_leap_year {
460    my $year = shift;
461    return (($year %4 == 0) && !($year % 100 == 0)) || ($year % 400 == 0)
462               ? 1 : 0;
463}
464
465sub is_leap_year {
466    my $time = shift;
467    my $year = $time->year;
468    return _is_leap_year($year);
469}
470
471my @MON_LAST = qw(31 28 31 30 31 30 31 31 30 31 30 31);
472
473sub month_last_day {
474    my $time = shift;
475    my $year = $time->year;
476    my $_mon = $time->_mon;
477    return $MON_LAST[$_mon] + ($_mon == 1 ? _is_leap_year($year) : 0);
478}
479
480my $trans_map_common = {
481
482    'c' => sub {
483        my ( $format ) = @_;
484        if($LOCALE->{PM} && $LOCALE->{AM}){
485            $format =~ s/%c/%a %d %b %Y %I:%M:%S %p/;
486        }
487        else{
488            $format =~ s/%c/%a %d %b %Y %H:%M:%S/;
489        }
490        return $format;
491    },
492    'r' => sub {
493        my ( $format ) = @_;
494        if($LOCALE->{PM} && $LOCALE->{AM}){
495            $format =~ s/%r/%I:%M:%S %p/;
496        }
497        else{
498            $format =~ s/%r/%H:%M:%S/;
499        }
500        return $format;
501    },
502    'X' => sub {
503        my ( $format ) = @_;
504        if($LOCALE->{PM} && $LOCALE->{AM}){
505            $format =~ s/%X/%I:%M:%S %p/;
506        }
507        else{
508            $format =~ s/%X/%H:%M:%S/;
509        }
510        return $format;
511    },
512};
513
514my $strftime_trans_map = {
515    %{$trans_map_common},
516
517    'e' => sub {
518        my ( $format, $time ) = @_;
519        $format =~ s/%e/%d/ if $IS_WIN32;
520        return $format;
521    },
522    'D' => sub {
523        my ( $format, $time ) = @_;
524        $format =~ s/%D/%m\/%d\/%y/;
525        return $format;
526    },
527    'F' => sub {
528        my ( $format, $time ) = @_;
529        $format =~ s/%F/%Y-%m-%d/;
530        return $format;
531    },
532    'R' => sub {
533        my ( $format, $time ) = @_;
534        $format =~ s/%R/%H:%M/;
535        return $format;
536    },
537    's' => sub {
538        #%s not portable if time parts are from gmtime since %s will
539        #cause a call to native mktime (and thus uses local TZ)
540        my ( $format, $time ) = @_;
541        $format =~ s/%s/$time->[c_epoch]/;
542        return $format;
543    },
544    'T' => sub {
545        my ( $format, $time ) = @_;
546        $format =~ s/%T/%H:%M:%S/ if $IS_WIN32;
547        return $format;
548    },
549    'u' => sub {
550        my ( $format, $time ) = @_;
551        $format =~ s/%u/%w/ if $IS_WIN32;
552        return $format;
553    },
554    'V' => sub {
555        my ( $format, $time ) = @_;
556        my $week = sprintf( "%02d", $time->week() );
557        $format =~ s/%V/$week/ if $IS_WIN32;
558        return $format;
559    },
560    'x' => sub {
561        my ( $format, $time ) = @_;
562        $format =~ s/%x/%a %d %b %Y/;
563        return $format;
564    },
565    'z' => sub {    #%[zZ] not portable if time parts are from gmtime
566        my ( $format, $time ) = @_;
567        $format =~ s/%z/+0000/ if not $time->[c_islocal];
568        return $format;
569    },
570    'Z' => sub {
571        my ( $format, $time ) = @_;
572        $format =~ s/%Z/UTC/ if not $time->[c_islocal];
573        return $format;
574    },
575};
576
577sub strftime {
578    my $time = shift;
579    my $format = @_ ? shift(@_) : '%a, %d %b %Y %H:%M:%S %Z';
580    $format = _translate_format($format, $strftime_trans_map, $time);
581
582    return $format unless $format =~ /%/; #if translate removes everything
583
584    return _strftime($format, $time->epoch, $time->[c_islocal]);
585}
586
587my $strptime_trans_map = {
588    %{$trans_map_common},
589};
590
591sub strptime {
592    my $time = shift;
593    my $string = shift;
594    my $format = @_ ? shift(@_) : "%a, %d %b %Y %H:%M:%S %Z";
595    my $islocal = (ref($time) ? $time->[c_islocal] : 0);
596    my $locales = $LOCALE || &Time::Piece::_default_locale();
597    $format = _translate_format($format, $strptime_trans_map);
598    my @vals = _strptime($string, $format, $islocal, $locales);
599#    warn(sprintf("got vals: %d-%d-%d %d:%d:%d\n", reverse(@vals[c_sec..c_year])));
600    return scalar $time->_mktime(\@vals, $islocal);
601}
602
603sub day_list {
604    shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method
605    my @old = @DAY_LIST;
606    if (@_) {
607        @DAY_LIST = @_;
608        &Time::Piece::_default_locale();
609    }
610    return @old;
611}
612
613sub mon_list {
614    shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method
615    my @old = @MON_LIST;
616    if (@_) {
617        @MON_LIST = @_;
618        &Time::Piece::_default_locale();
619    }
620    return @old;
621}
622
623sub time_separator {
624    shift if ref($_[0]) && $_[0]->isa(__PACKAGE__);
625    my $old = $TIME_SEP;
626    if (@_) {
627        $TIME_SEP = $_[0];
628    }
629    return $old;
630}
631
632sub date_separator {
633    shift if ref($_[0]) && $_[0]->isa(__PACKAGE__);
634    my $old = $DATE_SEP;
635    if (@_) {
636        $DATE_SEP = $_[0];
637    }
638    return $old;
639}
640
641use overload '""' => \&cdate,
642             'cmp' => \&str_compare,
643             'fallback' => undef;
644
645sub cdate {
646    my $time = shift;
647    if ($time->[c_islocal]) {
648        return scalar(CORE::localtime($time->epoch));
649    }
650    else {
651        return scalar(CORE::gmtime($time->epoch));
652    }
653}
654
655sub str_compare {
656    my ($lhs, $rhs, $reverse) = @_;
657
658    if (blessed($rhs) && $rhs->isa('Time::Piece')) {
659        $rhs = "$rhs";
660    }
661    return $reverse ? $rhs cmp $lhs->cdate : $lhs->cdate cmp $rhs;
662}
663
664use overload
665        '-' => \&subtract,
666        '+' => \&add;
667
668sub subtract {
669    my $time = shift;
670    my $rhs = shift;
671
672    if (shift)
673    {
674	# SWAPED is set (so someone tried an expression like NOTDATE - DATE).
675	# Imitate Perl's standard behavior and return the result as if the
676	# string $time resolves to was subtracted from NOTDATE.  This way,
677	# classes which override this one and which have a stringify function
678	# that resolves to something that looks more like a number don't need
679	# to override this function.
680	return $rhs - "$time";
681    }
682
683    if (blessed($rhs) && $rhs->isa('Time::Piece')) {
684        return Time::Seconds->new($time->epoch - $rhs->epoch);
685    }
686    else {
687        # rhs is seconds.
688        return $time->_mktime(($time->epoch - $rhs), $time->[c_islocal]);
689    }
690}
691
692sub add {
693    my $time = shift;
694    my $rhs = shift;
695
696    return $time->_mktime(($time->epoch + $rhs), $time->[c_islocal]);
697}
698
699use overload
700        '<=>' => \&compare;
701
702sub get_epochs {
703    my ($lhs, $rhs, $reverse) = @_;
704    unless (blessed($rhs) && $rhs->isa('Time::Piece')) {
705        $rhs = $lhs->new($rhs);
706    }
707    if ($reverse) {
708        return $rhs->epoch, $lhs->epoch;
709    }
710    return $lhs->epoch, $rhs->epoch;
711}
712
713sub compare {
714    my ($lhs, $rhs) = get_epochs(@_);
715    return $lhs <=> $rhs;
716}
717
718sub add_months {
719    my ($time, $num_months) = @_;
720
721    croak("add_months requires a number of months") unless defined($num_months);
722
723    my $final_month = $time->_mon + $num_months;
724    my $num_years = 0;
725    if ($final_month > 11 || $final_month < 0) {
726        # these two ops required because we have no POSIX::floor and don't
727        # want to load POSIX.pm
728        if ($final_month < 0 && $final_month % 12 == 0) {
729            $num_years = int($final_month / 12) + 1;
730        }
731        else {
732            $num_years = int($final_month / 12);
733        }
734        $num_years-- if ($final_month < 0);
735
736        $final_month = $final_month % 12;
737    }
738
739    my @vals = _mini_mktime($time->sec, $time->min, $time->hour,
740                            $time->mday, $final_month, $time->year - 1900 + $num_years);
741    # warn(sprintf("got %d vals: %d-%d-%d %d:%d:%d [%d]\n", scalar(@vals), reverse(@vals), $time->[c_islocal]));
742    return scalar $time->_mktime(\@vals, $time->[c_islocal]);
743}
744
745sub add_years {
746    my ($time, $years) = @_;
747    $time->add_months($years * 12);
748}
749
750sub truncate {
751    my ($time, %params) = @_;
752    return $time unless exists $params{to};
753    #if ($params{to} eq 'week') { return $time->_truncate_week; }
754    my %units = (
755        second   => 0,
756        minute   => 1,
757        hour     => 2,
758        day      => 3,
759        month    => 4,
760        quarter  => 5,
761        year     => 5
762    );
763    my $to = $units{$params{to}};
764    croak "Invalid value of 'to' parameter: $params{to}" unless defined $to;
765    my $start_month = 0;
766    if ($params{to} eq 'quarter') {
767        $start_month = int( $time->_mon / 3 ) * 3;
768    }
769    my @down_to = (0, 0, 0, 1, $start_month, $time->year);
770    return $time->_mktime([@down_to[0..$to-1], @$time[$to..c_isdst]],
771        $time->[c_islocal]);
772}
773
774#Given a format and a translate map, replace format flags in
775#accordance with the logic from the translation map subroutines
776sub _translate_format {
777    my ( $format, $trans_map, $time ) = @_;
778
779    $format =~ s/%%/\e\e/g; #escape the escape
780    my $lexer = _build_format_lexer($format);
781
782	while(my $flag = $lexer->() ){
783        next unless exists $trans_map->{$flag};
784		$format = $trans_map->{$flag}($format, $time);
785	}
786
787    $format =~ s/\e\e/%%/g;
788    return $format;
789}
790
791sub _build_format_lexer {
792    my $format = shift();
793
794    #Higher Order Perl p.359 (or thereabouts)
795    return sub {
796        LABEL: {
797        return $1 if $format =~ m/\G%([a-zA-Z])/gc; #return single char flags
798
799        redo LABEL if $format =~ m/\G(.)/gc;
800        return; #return at empty string
801        }
802    };
803}
804
805sub use_locale {
806    #get locale month/day names from posix strftime (from Piece.xs)
807    my $locales = _get_localization();
808
809    #If AM and PM are the same, set both to ''
810    if (   !$locales->{PM}
811        || !$locales->{AM}
812        || ( $locales->{PM} eq $locales->{AM} ) )
813    {
814        $locales->{PM} = '';
815        $locales->{AM} = '';
816    }
817
818    $locales->{pm} = lc $locales->{PM};
819    $locales->{am} = lc $locales->{AM};
820    #should probably figure out how to get a
821    #region specific format for %c someday
822    $locales->{c_fmt} = '';
823
824    #Set globals. If anything is
825    #weird just use original
826    if( @{$locales->{weekday}} < 7 ){
827        @{$locales->{weekday}} = @FULLDAY_LIST;
828    }
829    else {
830        @FULLDAY_LIST = @{$locales->{weekday}};
831    }
832
833    if( @{$locales->{wday}} < 7 ){
834        @{$locales->{wday}} = @DAY_LIST;
835    }
836    else {
837        @DAY_LIST = @{$locales->{wday}};
838    }
839
840    if( @{$locales->{month}} < 12 ){
841        @{$locales->{month}} = @FULLMON_LIST;
842    }else {
843        @FULLMON_LIST = @{$locales->{month}};
844    }
845
846    if( @{$locales->{mon}} < 12 ){
847        @{$locales->{mon}} = @MON_LIST;
848    }
849    else{
850        @MON_LIST= @{$locales->{mon}};
851    }
852
853    $LOCALE = $locales;
854}
855
856#$Time::Piece::LOCALE is used by strptime and thus needs to be
857#in sync with what ever users change to via day_list() and mon_list().
858#Should probably deprecate this use of gloabl state, but oh well...
859sub _default_locale {
860    my $locales = {};
861
862    @{ $locales->{weekday} } = @FULLDAY_LIST;
863    @{ $locales->{wday} }    = @DAY_LIST;
864    @{ $locales->{month} }   = @FULLMON_LIST;
865    @{ $locales->{mon} }     = @MON_LIST;
866    $locales->{alt_month} = $locales->{month};
867
868    $locales->{PM}    = 'PM';
869    $locales->{AM}    = 'AM';
870    $locales->{pm}    = 'pm';
871    $locales->{am}    = 'am';
872    $locales->{c_fmt} = '';
873
874    $LOCALE = $locales;
875}
876
877sub _locale {
878    return $LOCALE;
879}
880
881
8821;
883__END__
884
885=head1 NAME
886
887Time::Piece - Object Oriented time objects
888
889=head1 SYNOPSIS
890
891    use Time::Piece;
892
893    my $t = localtime;
894    print "Time is $t\n";
895    print "Year is ", $t->year, "\n";
896
897=head1 DESCRIPTION
898
899This module replaces the standard C<localtime> and C<gmtime> functions with
900implementations that return objects. It does so in a backwards
901compatible manner, so that using localtime/gmtime in the way documented
902in perlfunc will still return what you expect.
903
904The module actually implements most of an interface described by
905Larry Wall on the perl5-porters mailing list here:
906L<https://www.nntp.perl.org/group/perl.perl5.porters/2000/01/msg5283.html>
907
908=head1 USAGE
909
910After importing this module, when you use localtime or gmtime in a scalar
911context, rather than getting an ordinary scalar string representing the
912date and time, you get a Time::Piece object, whose stringification happens
913to produce the same effect as the localtime and gmtime functions. There is
914also a new() constructor provided, which is the same as localtime(), except
915when passed a Time::Piece object, in which case it's a copy constructor. The
916following methods are available on the object:
917
918    $t->sec                 # also available as $t->second
919    $t->min                 # also available as $t->minute
920    $t->hour                # 24 hour
921    $t->mday                # also available as $t->day_of_month
922    $t->mon                 # 1 = January
923    $t->_mon                # 0 = January
924    $t->monname             # Feb
925    $t->month               # same as $t->monname
926    $t->fullmonth           # February
927    $t->year                # based at 0 (year 0 AD is, of course 1 BC)
928    $t->_year               # year minus 1900
929    $t->yy                  # 2 digit year
930    $t->wday                # 1 = Sunday
931    $t->_wday               # 0 = Sunday
932    $t->day_of_week         # 0 = Sunday
933    $t->wdayname            # Tue
934    $t->day                 # same as wdayname
935    $t->fullday             # Tuesday
936    $t->yday                # also available as $t->day_of_year, 0 = Jan 01
937    $t->isdst               # also available as $t->daylight_savings
938
939    $t->hms                 # 12:34:56
940    $t->hms(".")            # 12.34.56
941    $t->time                # same as $t->hms
942
943    $t->ymd                 # 2000-02-29
944    $t->date                # same as $t->ymd
945    $t->mdy                 # 02-29-2000
946    $t->mdy("/")            # 02/29/2000
947    $t->dmy                 # 29-02-2000
948    $t->dmy(".")            # 29.02.2000
949    $t->datetime            # 2000-02-29T12:34:56 (ISO 8601)
950    $t->cdate               # Tue Feb 29 12:34:56 2000
951    "$t"                    # same as $t->cdate
952
953    $t->epoch               # seconds since the epoch
954    $t->tzoffset            # timezone offset in a Time::Seconds object
955
956    $t->julian_day          # number of days since Julian period began
957    $t->mjd                 # modified Julian date (JD-2400000.5 days)
958
959    $t->week                # week number (ISO 8601)
960
961    $t->is_leap_year        # true if it's a leap year
962    $t->month_last_day      # 28-31
963
964    $t->time_separator($s)  # set the default separator (default ":")
965    $t->date_separator($s)  # set the default separator (default "-")
966    $t->day_list(@days)     # set the default weekdays
967    $t->mon_list(@days)     # set the default months
968
969    $t->strftime(FORMAT)    # same as POSIX::strftime (without the overhead
970                            # of the full POSIX extension)
971    $t->strftime()          # "Tue, 29 Feb 2000 12:34:56 GMT"
972
973    Time::Piece->strptime(STRING, FORMAT)
974                            # see strptime man page. Creates a new
975                            # Time::Piece object
976
977Note that C<localtime> and C<gmtime> are not listed above.  If called as
978methods on a Time::Piece object, they act as constructors, returning a new
979Time::Piece object for the current time.  In other words: they're not useful as
980methods.
981
982=head2 Local Locales
983
984Both wdayname (day) and monname (month) allow passing in a list to use
985to index the name of the days against. This can be useful if you need
986to implement some form of localisation without actually installing or
987using locales. Note that this is a global override and will affect
988all Time::Piece instances.
989
990  my @days = qw( Dimanche Lundi Merdi Mercredi Jeudi Vendredi Samedi );
991
992  my $french_day = localtime->day(@days);
993
994These settings can be overridden globally too:
995
996  Time::Piece::day_list(@days);
997
998Or for months:
999
1000  Time::Piece::mon_list(@months);
1001
1002And locally for months:
1003
1004  print localtime->month(@months);
1005
1006Or to populate with your current system locale call:
1007    Time::Piece->use_locale();
1008
1009=head2 Date Calculations
1010
1011It's possible to use simple addition and subtraction of objects:
1012
1013    use Time::Seconds;
1014
1015    my $seconds = $t1 - $t2;
1016    $t1 += ONE_DAY; # add 1 day (constant from Time::Seconds)
1017
1018The following are valid ($t1 and $t2 are Time::Piece objects):
1019
1020    $t1 - $t2; # returns Time::Seconds object
1021    $t1 - 42; # returns Time::Piece object
1022    $t1 + 533; # returns Time::Piece object
1023
1024However adding a Time::Piece object to another Time::Piece object
1025will cause a runtime error.
1026
1027Note that the first of the above returns a Time::Seconds object, so
1028while examining the object will print the number of seconds (because
1029of the overloading), you can also get the number of minutes, hours,
1030days, weeks and years in that delta, using the Time::Seconds API.
1031
1032In addition to adding seconds, there are two APIs for adding months and
1033years:
1034
1035    $t = $t->add_months(6);
1036    $t = $t->add_years(5);
1037
1038The months and years can be negative for subtractions. Note that there
1039is some "strange" behaviour when adding and subtracting months at the
1040ends of months. Generally when the resulting month is shorter than the
1041starting month then the number of overlap days is added. For example
1042subtracting a month from 2008-03-31 will not result in 2008-02-31 as this
1043is an impossible date. Instead you will get 2008-03-02. This appears to
1044be consistent with other date manipulation tools.
1045
1046=head2 Truncation
1047
1048Calling the C<truncate> method returns a copy of the object but with the
1049time truncated to the start of the supplied unit.
1050
1051    $t = $t->truncate(to => 'day');
1052
1053This example will set the time to midnight on the same date which C<$t>
1054had previously. Allowed values for the "to" parameter are: "year",
1055"quarter", "month", "day", "hour", "minute" and "second".
1056
1057=head2 Date Comparisons
1058
1059Date comparisons are also possible, using the full suite of "<", ">",
1060"<=", ">=", "<=>", "==" and "!=".
1061
1062=head2 Date Parsing
1063
1064Time::Piece has a built-in strptime() function (from FreeBSD), allowing
1065you incredibly flexible date parsing routines. For example:
1066
1067  my $t = Time::Piece->strptime("Sunday 3rd Nov, 1943",
1068                                "%A %drd %b, %Y");
1069
1070  print $t->strftime("%a, %d %b %Y");
1071
1072Outputs:
1073
1074  Wed, 03 Nov 1943
1075
1076(see, it's even smart enough to fix my obvious date bug)
1077
1078For more information see "man strptime", which should be on all unix
1079systems.
1080
1081Alternatively look here: L<http://www.unix.com/man-page/FreeBSD/3/strftime/>
1082
1083=head3 CAVEAT %A, %a, %B, %b, and friends
1084
1085Time::Piece::strptime by default can only parse American English date names.
1086Meanwhile, Time::Piece->strftime() will return date names that use the current
1087configured system locale. This means dates returned by strftime might not be
1088able to be parsed by strptime. This is the default behavior and can be
1089overridden by calling Time::Piece->use_locale(). This builds a list of the
1090current locale's day and month names which strptime will use to parse with.
1091Note this is a global override and will affect all Time::Piece instances.
1092
1093For instance with a German locale:
1094
1095    localtime->day_list();
1096
1097Returns
1098
1099    ( 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' )
1100
1101While:
1102
1103    Time::Piece->use_locale();
1104    localtime->day_list();
1105
1106Returns
1107
1108    ( 'So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa' )
1109
1110=head2 YYYY-MM-DDThh:mm:ss
1111
1112The ISO 8601 standard defines the date format to be YYYY-MM-DD, and
1113the time format to be hh:mm:ss (24 hour clock), and if combined, they
1114should be concatenated with date first and with a capital 'T' in front
1115of the time.
1116
1117=head2 Week Number
1118
1119The I<week number> may be an unknown concept to some readers.  The ISO
11208601 standard defines that weeks begin on a Monday and week 1 of the
1121year is the week that includes both January 4th and the first Thursday
1122of the year.  In other words, if the first Monday of January is the
11232nd, 3rd, or 4th, the preceding days of the January are part of the
1124last week of the preceding year.  Week numbers range from 1 to 53.
1125
1126=head2 Global Overriding
1127
1128Finally, it's possible to override localtime and gmtime everywhere, by
1129including the ':override' tag in the import list:
1130
1131    use Time::Piece ':override';
1132
1133=head1 CAVEATS
1134
1135=head2 Setting $ENV{TZ} in Threads on Win32
1136
1137Note that when using perl in the default build configuration on Win32
1138(specifically, when perl is built with PERL_IMPLICIT_SYS), each perl
1139interpreter maintains its own copy of the environment and only the main
1140interpreter will update the process environment seen by strftime.
1141
1142Therefore, if you make changes to $ENV{TZ} from inside a thread other than
1143the main thread then those changes will not be seen by strftime if you
1144subsequently call that with the %Z formatting code. You must change $ENV{TZ}
1145in the main thread to have the desired effect in this case (and you must
1146also call _tzset() in the main thread to register the environment change).
1147
1148Furthermore, remember that this caveat also applies to fork(), which is
1149emulated by threads on Win32.
1150
1151=head2 Use of epoch seconds
1152
1153This module internally uses the epoch seconds system that is provided via
1154the perl C<time()> function and supported by C<gmtime()> and C<localtime()>.
1155
1156If your perl does not support times larger than C<2^31> seconds then this
1157module is likely to fail at processing dates beyond the year 2038. There are
1158moves afoot to fix that in perl. Alternatively use 64 bit perl. Or if none
1159of those are options, use the L<DateTime> module which has support for years
1160well into the future and past.
1161
1162Also, the internal representation of Time::Piece->strftime deviates from the
1163standard POSIX implementation in that is uses the epoch (instead of separate
1164year, month, day parts). This change was added in version 1.30. If you must
1165have a more traditional strftime (which will normally never calculate day
1166light saving times correctly), you can pass the date parts from Time::Piece
1167into the strftime function provided by the POSIX module
1168(see strftime in L<POSIX> ).
1169
1170=head1 AUTHOR
1171
1172Matt Sergeant, matt@sergeant.org
1173Jarkko Hietaniemi, jhi@iki.fi (while creating Time::Piece for core perl)
1174
1175=head1 COPYRIGHT AND LICENSE
1176
1177Copyright 2001, Larry Wall.
1178
1179This module is free software, you may distribute it under the same terms
1180as Perl.
1181
1182=head1 SEE ALSO
1183
1184The excellent Calendar FAQ at L<http://www.tondering.dk/claus/calendar.html>
1185
1186=head1 BUGS
1187
1188The test harness leaves much to be desired. Patches welcome.
1189
1190=cut
1191