——# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
# (C) Paul Evans, 2012 -- leonerd@leonerd.org.uk
package
Time::timegm;
use
strict;
use
warnings;
our
$VERSION
=
'0.01'
;
our
@EXPORT_OK
=
qw(
timegm
)
;
unless
(
eval
{
XSLoader::load( __PACKAGE__,
$VERSION
);
defined
Time::timegm::timegm( 0, 0, 0, 0, 1, 70 )
} ) {
# Fallback on pureperl implementation
no
warnings
'redefine'
;
*timegm
= \
&timegm_pp
;
}
use
Carp;
# Number of seconds in a POSIX day
=head1 NAME
C<Time::timegm> - a UTC version of C<mktime()>
=head1 SYNOPSIS
use Time::timegm qw( timegm );
my $epoch = timegm( 0, 0, 0, 14, 6-1, 2012-1900 );
print "2012-06-14 00:00:00 UTC happened at ",
scalar localtime($epoch), " localtime\n";
=head1 DESCRIPTION
The L<POSIX> standard provides three functions for converting between integer
epoch values and 6-component "broken-down" time representations. C<localtime>
and C<gmtime> convert an epoch into the 6 components of seconds, minutes,
hours, day of month, month and year, in either local timezone or UTC. The
C<mktime> function converts a local broken-down time into an epoch value.
However, C<POSIX> does not provide a UTC version of this.
This module provides a function C<timegm> which has this ability.
Unlike some other CPAN implementations of this behaviour, this version does
not re-implement the time handling logic internally. It reuses the C<mktime>
and C<gmtime> functions provided by the system to ensure its results are
always consistent with the other functions.
=cut
=head1 FUNCTIONS
=cut
=head2 $epoch = timegm( $sec, $min, $hour, $mday, $mon, $year )
Returns the epoch integer value representing the time given by the 6
broken-down components.
As with C<POSIX::mktime> it is I<not> required that these values be within
their "valid" ranges. This function will normalise values out of range. For
example, the 25th hour of a day is normalised to the 1st hour of the following
day; or the 0th month is normalised to the 12th month of the preceeding year.
=cut
# Cache "$year/$mon" => $epoch of the time that month begins
my
%start_of_month
;
sub
timegm_pp
{
my
(
$sec
,
$min
,
$hour
,
$mday
,
$mon
,
$year
) =
@_
;
# Epoch times + UTC always align day boundaries at multiples of 86400. The
# structure is mathematically regular within a month. Therefore we can
# calculate the epoch time for a given time in UTC by finding the start of
# the month then adding seconds
$mon
-=12,
$year
++
while
$mon
>= 12;
$mon
+=12,
$year
--
while
$mon
< 0;
my
$monstart
=
$start_of_month
{
"$year/$mon"
};
unless
(
defined
$monstart
) {
$monstart
= mktime( 0, 0, 0, 1,
$mon
,
$year
);
$monstart
-=
$monstart
% DAY;
my
@gmtime
=
gmtime
$monstart
;
$gmtime
[
$_
] == 0 or croak
"Expected midnight GMT, did not get it - "
.
scalar
(
gmtime
$monstart
)
for
0 .. 2;
# Might have to round forward rather than backward
$monstart
+= DAY,
@gmtime
=
gmtime
$monstart
if
$gmtime
[3] > 1;
$gmtime
[3] == 1 or croak
"Expected 1st of month GMT, did not get it - "
.
scalar
(
gmtime
$monstart
);
$start_of_month
{
"$year/$mon"
} =
$monstart
;
}
return
$monstart
+ (
$mday
-1)
*DAY
+
$hour
*HOUR
+
$min
*MIN
+
$sec
;
}
=head1 COMPARISON WITH Time::Local
The L<Time::Local> module also provides a function called C<timegm()> with
similar behaviour to this one. The differences are:
=over 2
=item *
C<Time::timegm::timegm()> handles denormalised values (that is, seconds or
minutes outside of the range 0 to 59, hours outside 0 to 23, etc..) by
adjusting the next largest unit (such that 61 seconds is 1 second of the next
minute, etc). C<Time::Local::timegm()> croaks on out-of-range input.
C<Time::Local> also provides a function C<timegm_nocheck()> which does not
croak but it is documented that the behavior is unspecified on out-of-range
values.
=item *
C<Time::timegm::timegm()> is implemented by a light XS wrapper around the
C<timegm(3)> or C<_mkgmtime(3)> function provided by the platform's C library
if such a function is provided, so its behaviour is consistent with the rest
of the platform. C<Time::Local> re-implements the logic in perl code.
C<Time::timegm> will fall back to a perl implementation only if the XS one
cannot be used.
=back
=head1 AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
=cut
0x55AA;