xref: /openbsd-src/gnu/usr.bin/perl/cpan/Time-Piece/Piece.pm (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1package Time::Piece;
2
3use strict;
4
5require Exporter;
6require DynaLoader;
7use Time::Seconds;
8use Carp;
9use Time::Local;
10
11our @ISA = qw(Exporter DynaLoader);
12
13our @EXPORT = qw(
14    localtime
15    gmtime
16);
17
18our %EXPORT_TAGS = (
19    ':override' => 'internal',
20    );
21
22our $VERSION = '1.27';
23
24bootstrap 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);
33
34use constant 'c_sec' => 0;
35use constant 'c_min' => 1;
36use constant 'c_hour' => 2;
37use constant 'c_mday' => 3;
38use constant 'c_mon' => 4;
39use constant 'c_year' => 5;
40use constant 'c_wday' => 6;
41use constant 'c_yday' => 7;
42use constant 'c_isdst' => 8;
43use constant 'c_epoch' => 9;
44use constant 'c_islocal' => 10;
45
46sub localtime {
47    unshift @_, __PACKAGE__ unless eval { $_[0]->isa('Time::Piece') };
48    my $class = shift;
49    my $time  = shift;
50    $time = time if (!defined $time);
51    $class->_mktime($time, 1);
52}
53
54sub gmtime {
55    unshift @_, __PACKAGE__ unless eval { $_[0]->isa('Time::Piece') };
56    my $class = shift;
57    my $time  = shift;
58    $time = time if (!defined $time);
59    $class->_mktime($time, 0);
60}
61
62sub new {
63    my $class = shift;
64    my ($time) = @_;
65
66    my $self;
67
68    if (defined($time)) {
69        $self = $class->localtime($time);
70    }
71    elsif (ref($class) && $class->isa(__PACKAGE__)) {
72        $self = $class->_mktime($class->epoch, $class->[c_islocal]);
73    }
74    else {
75        $self = $class->localtime();
76    }
77
78    return bless $self, ref($class) || $class;
79}
80
81sub parse {
82    my $proto = shift;
83    my $class = ref($proto) || $proto;
84    my @components;
85    if (@_ > 1) {
86        @components = @_;
87    }
88    else {
89        @components = shift =~ /(\d+)$DATE_SEP(\d+)$DATE_SEP(\d+)(?:(?:T|\s+)(\d+)$TIME_SEP(\d+)(?:$TIME_SEP(\d+)))/;
90        @components = reverse(@components[0..5]);
91    }
92    return $class->new(_strftime("%s", @components));
93}
94
95sub _mktime {
96    my ($class, $time, $islocal) = @_;
97    $class = eval { (ref $class) && (ref $class)->isa('Time::Piece') }
98           ? ref $class
99           : $class;
100    if (ref($time)) {
101        $time->[c_epoch] = undef;
102        return wantarray ? @$time : bless [@$time[0..9], $islocal], $class;
103    }
104    _tzset();
105    my @time = $islocal ?
106            CORE::localtime($time)
107                :
108            CORE::gmtime($time);
109    wantarray ? @time : bless [@time, $time, $islocal], $class;
110}
111
112my %_special_exports = (
113  localtime => sub { my $c = $_[0]; sub { $c->localtime(@_) } },
114  gmtime    => sub { my $c = $_[0]; sub { $c->gmtime(@_)    } },
115);
116
117sub export {
118  my ($class, $to, @methods) = @_;
119  for my $method (@methods) {
120    if (exists $_special_exports{$method}) {
121      no strict 'refs';
122      no warnings 'redefine';
123      *{$to . "::$method"} = $_special_exports{$method}->($class);
124    } else {
125      $class->SUPER::export($to, $method);
126    }
127  }
128}
129
130sub import {
131    # replace CORE::GLOBAL localtime and gmtime if required
132    my $class = shift;
133    my %params;
134    map($params{$_}++,@_,@EXPORT);
135    if (delete $params{':override'}) {
136        $class->export('CORE::GLOBAL', keys %params);
137    }
138    else {
139        $class->export((caller)[0], keys %params);
140    }
141}
142
143## Methods ##
144
145sub sec {
146    my $time = shift;
147    $time->[c_sec];
148}
149
150*second = \&sec;
151
152sub min {
153    my $time = shift;
154    $time->[c_min];
155}
156
157*minute = \&min;
158
159sub hour {
160    my $time = shift;
161    $time->[c_hour];
162}
163
164sub mday {
165    my $time = shift;
166    $time->[c_mday];
167}
168
169*day_of_month = \&mday;
170
171sub mon {
172    my $time = shift;
173    $time->[c_mon] + 1;
174}
175
176sub _mon {
177    my $time = shift;
178    $time->[c_mon];
179}
180
181sub month {
182    my $time = shift;
183    if (@_) {
184        return $_[$time->[c_mon]];
185    }
186    elsif (@MON_LIST) {
187        return $MON_LIST[$time->[c_mon]];
188    }
189    else {
190        return $time->strftime('%b');
191    }
192}
193
194*monname = \&month;
195
196sub fullmonth {
197    my $time = shift;
198    if (@_) {
199        return $_[$time->[c_mon]];
200    }
201    elsif (@FULLMON_LIST) {
202        return $FULLMON_LIST[$time->[c_mon]];
203    }
204    else {
205        return $time->strftime('%B');
206    }
207}
208
209sub year {
210    my $time = shift;
211    $time->[c_year] + 1900;
212}
213
214sub _year {
215    my $time = shift;
216    $time->[c_year];
217}
218
219sub yy {
220    my $time = shift;
221    my $res = $time->[c_year] % 100;
222    return $res > 9 ? $res : "0$res";
223}
224
225sub wday {
226    my $time = shift;
227    $time->[c_wday] + 1;
228}
229
230sub _wday {
231    my $time = shift;
232    $time->[c_wday];
233}
234
235*day_of_week = \&_wday;
236
237sub wdayname {
238    my $time = shift;
239    if (@_) {
240        return $_[$time->[c_wday]];
241    }
242    elsif (@DAY_LIST) {
243        return $DAY_LIST[$time->[c_wday]];
244    }
245    else {
246        return $time->strftime('%a');
247    }
248}
249
250*day = \&wdayname;
251
252sub fullday {
253    my $time = shift;
254    if (@_) {
255        return $_[$time->[c_wday]];
256    }
257    elsif (@FULLDAY_LIST) {
258        return $FULLDAY_LIST[$time->[c_wday]];
259    }
260    else {
261        return $time->strftime('%A');
262    }
263}
264
265sub yday {
266    my $time = shift;
267    $time->[c_yday];
268}
269
270*day_of_year = \&yday;
271
272sub isdst {
273    my $time = shift;
274    $time->[c_isdst];
275}
276
277*daylight_savings = \&isdst;
278
279# Thanks to Tony Olekshy <olekshy@cs.ualberta.ca> for this algorithm
280sub tzoffset {
281    my $time = shift;
282
283    return Time::Seconds->new(0) unless $time->[c_islocal];
284
285    my $epoch = $time->epoch;
286
287    my $j = sub {
288
289        my ($s,$n,$h,$d,$m,$y) = @_; $m += 1; $y += 1900;
290
291        $time->_jd($y, $m, $d, $h, $n, $s);
292
293    };
294
295    # Compute floating offset in hours.
296    #
297    # Note use of crt methods so the tz is properly set...
298    # See: http://perlmonks.org/?node_id=820347
299    my $delta = 24 * ($j->(_crt_localtime($epoch)) - $j->(_crt_gmtime($epoch)));
300
301    # Return value in seconds rounded to nearest minute.
302    return Time::Seconds->new( int($delta * 60 + ($delta >= 0 ? 0.5 : -0.5)) * 60 );
303}
304
305sub epoch {
306    my $time = shift;
307    if (defined($time->[c_epoch])) {
308        return $time->[c_epoch];
309    }
310    else {
311        my $epoch = $time->[c_islocal] ?
312          timelocal(@{$time}[c_sec .. c_mon], $time->[c_year]+1900)
313          :
314          timegm(@{$time}[c_sec .. c_mon], $time->[c_year]+1900);
315        $time->[c_epoch] = $epoch;
316        return $epoch;
317    }
318}
319
320sub hms {
321    my $time = shift;
322    my $sep = @_ ? shift(@_) : $TIME_SEP;
323    sprintf("%02d$sep%02d$sep%02d", $time->[c_hour], $time->[c_min], $time->[c_sec]);
324}
325
326*time = \&hms;
327
328sub ymd {
329    my $time = shift;
330    my $sep = @_ ? shift(@_) : $DATE_SEP;
331    sprintf("%d$sep%02d$sep%02d", $time->year, $time->mon, $time->[c_mday]);
332}
333
334*date = \&ymd;
335
336sub mdy {
337    my $time = shift;
338    my $sep = @_ ? shift(@_) : $DATE_SEP;
339    sprintf("%02d$sep%02d$sep%d", $time->mon, $time->[c_mday], $time->year);
340}
341
342sub dmy {
343    my $time = shift;
344    my $sep = @_ ? shift(@_) : $DATE_SEP;
345    sprintf("%02d$sep%02d$sep%d", $time->[c_mday], $time->mon, $time->year);
346}
347
348sub datetime {
349    my $time = shift;
350    my %seps = (date => $DATE_SEP, T => 'T', time => $TIME_SEP, @_);
351    return join($seps{T}, $time->date($seps{date}), $time->time($seps{time}));
352}
353
354
355
356# Julian Day is always calculated for UT regardless
357# of local time
358sub julian_day {
359    my $time = shift;
360    # Correct for localtime
361    $time = $time->gmtime( $time->epoch ) if $time->[c_islocal];
362
363    # Calculate the Julian day itself
364    my $jd = $time->_jd( $time->year, $time->mon, $time->mday,
365                        $time->hour, $time->min, $time->sec);
366
367    return $jd;
368}
369
370# MJD is defined as JD - 2400000.5 days
371sub mjd {
372    return shift->julian_day - 2_400_000.5;
373}
374
375# Internal calculation of Julian date. Needed here so that
376# both tzoffset and mjd/jd methods can share the code
377# Algorithm from Hatcher 1984 (QJRAS 25, 53-55), and
378#  Hughes et al, 1989, MNRAS, 238, 15
379# See: http://adsabs.harvard.edu/cgi-bin/nph-bib_query?bibcode=1989MNRAS.238.1529H&db_key=AST
380# for more details
381
382sub _jd {
383    my $self = shift;
384    my ($y, $m, $d, $h, $n, $s) = @_;
385
386    # Adjust input parameters according to the month
387    $y = ( $m > 2 ? $y : $y - 1);
388    $m = ( $m > 2 ? $m - 3 : $m + 9);
389
390    # Calculate the Julian Date (assuming Julian calendar)
391    my $J = int( 365.25 *( $y + 4712) )
392      + int( (30.6 * $m) + 0.5)
393        + 59
394          + $d
395            - 0.5;
396
397    # Calculate the Gregorian Correction (since we have Gregorian dates)
398    my $G = 38 - int( 0.75 * int(49+($y/100)));
399
400    # Calculate the actual Julian Date
401    my $JD = $J + $G;
402
403    # Modify to include hours/mins/secs in floating portion.
404    return $JD + ($h + ($n + $s / 60) / 60) / 24;
405}
406
407sub week {
408    my $self = shift;
409
410    my $J  = $self->julian_day;
411    # Julian day is independent of time zone so add on tzoffset
412    # if we are using local time here since we want the week day
413    # to reflect the local time rather than UTC
414    $J += ($self->tzoffset/(24*3600)) if $self->[c_islocal];
415
416    # Now that we have the Julian day including fractions
417    # convert it to an integer Julian Day Number using nearest
418    # int (since the day changes at midday we convert all Julian
419    # dates to following midnight).
420    $J = int($J+0.5);
421
422    use integer;
423    my $d4 = ((($J + 31741 - ($J % 7)) % 146097) % 36524) % 1461;
424    my $L  = $d4 / 1460;
425    my $d1 = (($d4 - $L) % 365) + $L;
426    return $d1 / 7 + 1;
427}
428
429sub _is_leap_year {
430    my $year = shift;
431    return (($year %4 == 0) && !($year % 100 == 0)) || ($year % 400 == 0)
432               ? 1 : 0;
433}
434
435sub is_leap_year {
436    my $time = shift;
437    my $year = $time->year;
438    return _is_leap_year($year);
439}
440
441my @MON_LAST = qw(31 28 31 30 31 30 31 31 30 31 30 31);
442
443sub month_last_day {
444    my $time = shift;
445    my $year = $time->year;
446    my $_mon = $time->_mon;
447    return $MON_LAST[$_mon] + ($_mon == 1 ? _is_leap_year($year) : 0);
448}
449
450sub strftime {
451    my $time = shift;
452    my $tzname = $time->[c_islocal] ? '%Z' : 'UTC';
453    my $format = @_ ? shift(@_) : "%a, %d %b %Y %H:%M:%S $tzname";
454    if (!defined $time->[c_wday]) {
455        if ($time->[c_islocal]) {
456            return _strftime($format, CORE::localtime($time->epoch));
457        }
458        else {
459            return _strftime($format, CORE::gmtime($time->epoch));
460        }
461    }
462    return _strftime($format, (@$time)[c_sec..c_isdst]);
463}
464
465sub strptime {
466    my $time = shift;
467    my $string = shift;
468    my $format = @_ ? shift(@_) : "%a, %d %b %Y %H:%M:%S %Z";
469    my @vals = _strptime($string, $format);
470#    warn(sprintf("got vals: %d-%d-%d %d:%d:%d\n", reverse(@vals)));
471    return scalar $time->_mktime(\@vals, (ref($time) ? $time->[c_islocal] : 0));
472}
473
474sub day_list {
475    shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method
476    my @old = @DAY_LIST;
477    if (@_) {
478        @DAY_LIST = @_;
479    }
480    return @old;
481}
482
483sub mon_list {
484    shift if ref($_[0]) && $_[0]->isa(__PACKAGE__); # strip first if called as a method
485    my @old = @MON_LIST;
486    if (@_) {
487        @MON_LIST = @_;
488    }
489    return @old;
490}
491
492sub time_separator {
493    shift if ref($_[0]) && $_[0]->isa(__PACKAGE__);
494    my $old = $TIME_SEP;
495    if (@_) {
496        $TIME_SEP = $_[0];
497    }
498    return $old;
499}
500
501sub date_separator {
502    shift if ref($_[0]) && $_[0]->isa(__PACKAGE__);
503    my $old = $DATE_SEP;
504    if (@_) {
505        $DATE_SEP = $_[0];
506    }
507    return $old;
508}
509
510use overload '""' => \&cdate,
511             'cmp' => \&str_compare,
512             'fallback' => undef;
513
514sub cdate {
515    my $time = shift;
516    if ($time->[c_islocal]) {
517        return scalar(CORE::localtime($time->epoch));
518    }
519    else {
520        return scalar(CORE::gmtime($time->epoch));
521    }
522}
523
524sub str_compare {
525    my ($lhs, $rhs, $reverse) = @_;
526    if (UNIVERSAL::isa($rhs, 'Time::Piece')) {
527        $rhs = "$rhs";
528    }
529    return $reverse ? $rhs cmp $lhs->cdate : $lhs->cdate cmp $rhs;
530}
531
532use overload
533        '-' => \&subtract,
534        '+' => \&add;
535
536sub subtract {
537    my $time = shift;
538    my $rhs = shift;
539    if (UNIVERSAL::isa($rhs, 'Time::Seconds')) {
540        $rhs = $rhs->seconds;
541    }
542
543    if (shift)
544    {
545	# SWAPED is set (so someone tried an expression like NOTDATE - DATE).
546	# Imitate Perl's standard behavior and return the result as if the
547	# string $time resolves to was subtracted from NOTDATE.  This way,
548	# classes which override this one and which have a stringify function
549	# that resolves to something that looks more like a number don't need
550	# to override this function.
551	return $rhs - "$time";
552    }
553
554    if (UNIVERSAL::isa($rhs, 'Time::Piece')) {
555        return Time::Seconds->new($time->epoch - $rhs->epoch);
556    }
557    else {
558        # rhs is seconds.
559        return $time->_mktime(($time->epoch - $rhs), $time->[c_islocal]);
560    }
561}
562
563sub add {
564    my $time = shift;
565    my $rhs = shift;
566    if (UNIVERSAL::isa($rhs, 'Time::Seconds')) {
567        $rhs = $rhs->seconds;
568    }
569    croak "Invalid rhs of addition: $rhs" if ref($rhs);
570
571    return $time->_mktime(($time->epoch + $rhs), $time->[c_islocal]);
572}
573
574use overload
575        '<=>' => \&compare;
576
577sub get_epochs {
578    my ($lhs, $rhs, $reverse) = @_;
579    if (!UNIVERSAL::isa($rhs, 'Time::Piece')) {
580        $rhs = $lhs->new($rhs);
581    }
582    if ($reverse) {
583        return $rhs->epoch, $lhs->epoch;
584    }
585    return $lhs->epoch, $rhs->epoch;
586}
587
588sub compare {
589    my ($lhs, $rhs) = get_epochs(@_);
590    return $lhs <=> $rhs;
591}
592
593sub add_months {
594    my ($time, $num_months) = @_;
595
596    croak("add_months requires a number of months") unless defined($num_months);
597
598    my $final_month = $time->_mon + $num_months;
599    my $num_years = 0;
600    if ($final_month > 11 || $final_month < 0) {
601        # these two ops required because we have no POSIX::floor and don't
602        # want to load POSIX.pm
603        if ($final_month < 0 && $final_month % 12 == 0) {
604            $num_years = int($final_month / 12) + 1;
605        }
606        else {
607            $num_years = int($final_month / 12);
608        }
609        $num_years-- if ($final_month < 0);
610
611        $final_month = $final_month % 12;
612    }
613
614    my @vals = _mini_mktime($time->sec, $time->min, $time->hour,
615                            $time->mday, $final_month, $time->year - 1900 + $num_years);
616    # warn(sprintf("got %d vals: %d-%d-%d %d:%d:%d [%d]\n", scalar(@vals), reverse(@vals), $time->[c_islocal]));
617    return scalar $time->_mktime(\@vals, $time->[c_islocal]);
618}
619
620sub add_years {
621    my ($time, $years) = @_;
622    $time->add_months($years * 12);
623}
624
6251;
626__END__
627
628=head1 NAME
629
630Time::Piece - Object Oriented time objects
631
632=head1 SYNOPSIS
633
634    use Time::Piece;
635
636    my $t = localtime;
637    print "Time is $t\n";
638    print "Year is ", $t->year, "\n";
639
640=head1 DESCRIPTION
641
642This module replaces the standard C<localtime> and C<gmtime> functions with
643implementations that return objects. It does so in a backwards
644compatible manner, so that using localtime/gmtime in the way documented
645in perlfunc will still return what you expect.
646
647The module actually implements most of an interface described by
648Larry Wall on the perl5-porters mailing list here:
649http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2000-01/msg00241.html
650
651=head1 USAGE
652
653After importing this module, when you use localtime or gmtime in a scalar
654context, rather than getting an ordinary scalar string representing the
655date and time, you get a Time::Piece object, whose stringification happens
656to produce the same effect as the localtime and gmtime functions. There is
657also a new() constructor provided, which is the same as localtime(), except
658when passed a Time::Piece object, in which case it's a copy constructor. The
659following methods are available on the object:
660
661    $t->sec                 # also available as $t->second
662    $t->min                 # also available as $t->minute
663    $t->hour                # 24 hour
664    $t->mday                # also available as $t->day_of_month
665    $t->mon                 # 1 = January
666    $t->_mon                # 0 = January
667    $t->monname             # Feb
668    $t->month               # same as $t->monname
669    $t->fullmonth           # February
670    $t->year                # based at 0 (year 0 AD is, of course 1 BC)
671    $t->_year               # year minus 1900
672    $t->yy                  # 2 digit year
673    $t->wday                # 1 = Sunday
674    $t->_wday               # 0 = Sunday
675    $t->day_of_week         # 0 = Sunday
676    $t->wdayname            # Tue
677    $t->day                 # same as wdayname
678    $t->fullday             # Tuesday
679    $t->yday                # also available as $t->day_of_year, 0 = Jan 01
680    $t->isdst               # also available as $t->daylight_savings
681
682    $t->hms                 # 12:34:56
683    $t->hms(".")            # 12.34.56
684    $t->time                # same as $t->hms
685
686    $t->ymd                 # 2000-02-29
687    $t->date                # same as $t->ymd
688    $t->mdy                 # 02-29-2000
689    $t->mdy("/")            # 02/29/2000
690    $t->dmy                 # 29-02-2000
691    $t->dmy(".")            # 29.02.2000
692    $t->datetime            # 2000-02-29T12:34:56 (ISO 8601)
693    $t->cdate               # Tue Feb 29 12:34:56 2000
694    "$t"                    # same as $t->cdate
695
696    $t->epoch               # seconds since the epoch
697    $t->tzoffset            # timezone offset in a Time::Seconds object
698
699    $t->julian_day          # number of days since Julian period began
700    $t->mjd                 # modified Julian date (JD-2400000.5 days)
701
702    $t->week                # week number (ISO 8601)
703
704    $t->is_leap_year        # true if it its
705    $t->month_last_day      # 28-31
706
707    $t->time_separator($s)  # set the default separator (default ":")
708    $t->date_separator($s)  # set the default separator (default "-")
709    $t->day_list(@days)     # set the default weekdays
710    $t->mon_list(@days)     # set the default months
711
712    $t->strftime(FORMAT)    # same as POSIX::strftime (without the overhead
713                            # of the full POSIX extension)
714    $t->strftime()          # "Tue, 29 Feb 2000 12:34:56 GMT"
715
716    Time::Piece->strptime(STRING, FORMAT)
717                            # see strptime man page. Creates a new
718                            # Time::Piece object
719
720Note that C<localtime> and C<gmtime> are not listed above.  If called as
721methods on a Time::Piece object, they act as constructors, returning a new
722Time::Piece object for the current time.  In other words: they're not useful as
723methods.
724
725=head2 Local Locales
726
727Both wdayname (day) and monname (month) allow passing in a list to use
728to index the name of the days against. This can be useful if you need
729to implement some form of localisation without actually installing or
730using locales.
731
732  my @days = qw( Dimanche Lundi Merdi Mercredi Jeudi Vendredi Samedi );
733
734  my $french_day = localtime->day(@days);
735
736These settings can be overridden globally too:
737
738  Time::Piece::day_list(@days);
739
740Or for months:
741
742  Time::Piece::mon_list(@months);
743
744And locally for months:
745
746  print localtime->month(@months);
747
748=head2 Date Calculations
749
750It's possible to use simple addition and subtraction of objects:
751
752    use Time::Seconds;
753
754    my $seconds = $t1 - $t2;
755    $t1 += ONE_DAY; # add 1 day (constant from Time::Seconds)
756
757The following are valid ($t1 and $t2 are Time::Piece objects):
758
759    $t1 - $t2; # returns Time::Seconds object
760    $t1 - 42; # returns Time::Piece object
761    $t1 + 533; # returns Time::Piece object
762
763However adding a Time::Piece object to another Time::Piece object
764will cause a runtime error.
765
766Note that the first of the above returns a Time::Seconds object, so
767while examining the object will print the number of seconds (because
768of the overloading), you can also get the number of minutes, hours,
769days, weeks and years in that delta, using the Time::Seconds API.
770
771In addition to adding seconds, there are two APIs for adding months and
772years:
773
774    $t->add_months(6);
775    $t->add_years(5);
776
777The months and years can be negative for subtractions. Note that there
778is some "strange" behaviour when adding and subtracting months at the
779ends of months. Generally when the resulting month is shorter than the
780starting month then the number of overlap days is added. For example
781subtracting a month from 2008-03-31 will not result in 2008-02-31 as this
782is an impossible date. Instead you will get 2008-03-02. This appears to
783be consistent with other date manipulation tools.
784
785=head2 Date Comparisons
786
787Date comparisons are also possible, using the full suite of "<", ">",
788"<=", ">=", "<=>", "==" and "!=".
789
790=head2 Date Parsing
791
792Time::Piece has a built-in strptime() function (from FreeBSD), allowing
793you incredibly flexible date parsing routines. For example:
794
795  my $t = Time::Piece->strptime("Sunday 3rd Nov, 1943",
796                                "%A %drd %b, %Y");
797
798  print $t->strftime("%a, %d %b %Y");
799
800Outputs:
801
802  Wed, 03 Nov 1943
803
804(see, it's even smart enough to fix my obvious date bug)
805
806For more information see "man strptime", which should be on all unix
807systems.
808
809Alternatively look here: http://www.unix.com/man-page/FreeBSD/3/strftime/
810
811=head2 YYYY-MM-DDThh:mm:ss
812
813The ISO 8601 standard defines the date format to be YYYY-MM-DD, and
814the time format to be hh:mm:ss (24 hour clock), and if combined, they
815should be concatenated with date first and with a capital 'T' in front
816of the time.
817
818=head2 Week Number
819
820The I<week number> may be an unknown concept to some readers.  The ISO
8218601 standard defines that weeks begin on a Monday and week 1 of the
822year is the week that includes both January 4th and the first Thursday
823of the year.  In other words, if the first Monday of January is the
8242nd, 3rd, or 4th, the preceding days of the January are part of the
825last week of the preceding year.  Week numbers range from 1 to 53.
826
827=head2 Global Overriding
828
829Finally, it's possible to override localtime and gmtime everywhere, by
830including the ':override' tag in the import list:
831
832    use Time::Piece ':override';
833
834=head1 CAVEATS
835
836=head2 Setting $ENV{TZ} in Threads on Win32
837
838Note that when using perl in the default build configuration on Win32
839(specifically, when perl is built with PERL_IMPLICIT_SYS), each perl
840interpreter maintains its own copy of the environment and only the main
841interpreter will update the process environment seen by strftime.
842
843Therefore, if you make changes to $ENV{TZ} from inside a thread other than
844the main thread then those changes will not be seen by strftime if you
845subsequently call that with the %Z formatting code. You must change $ENV{TZ}
846in the main thread to have the desired effect in this case (and you must
847also call _tzset() in the main thread to register the environment change).
848
849Furthermore, remember that this caveat also applies to fork(), which is
850emulated by threads on Win32.
851
852=head2 Use of epoch seconds
853
854This module internally uses the epoch seconds system that is provided via
855the perl C<time()> function and supported by C<gmtime()> and C<localtime()>.
856
857If your perl does not support times larger than C<2^31> seconds then this
858module is likely to fail at processing dates beyond the year 2038. There are
859moves afoot to fix that in perl. Alternatively use 64 bit perl. Or if none
860of those are options, use the L<DateTime> module which has support for years
861well into the future and past.
862
863=head1 AUTHOR
864
865Matt Sergeant, matt@sergeant.org
866Jarkko Hietaniemi, jhi@iki.fi (while creating Time::Piece for core perl)
867
868=head1 COPYRIGHT AND LICENSE
869
870Copyright 2001, Larry Wall.
871
872This module is free software, you may distribute it under the same terms
873as Perl.
874
875=head1 SEE ALSO
876
877The excellent Calendar FAQ at http://www.tondering.dk/claus/calendar.html
878
879=head1 BUGS
880
881The test harness leaves much to be desired. Patches welcome.
882
883=cut
884