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