# 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'; use Exporter 'import'; our @EXPORT_OK = qw( timegm ); unless( eval { require XSLoader; XSLoader::load( __PACKAGE__, $VERSION ); defined Time::timegm::timegm( 0, 0, 0, 0, 1, 70 ) } ) { # Fallback on pureperl implementation require POSIX; no warnings 'redefine'; *timegm = \&timegm_pp; } use Carp; use POSIX qw( mktime ); # Number of seconds in a POSIX day use constant DAY => 24*60*60; use constant HOUR => 60*60; use constant MIN => 60; =head1 NAME C - a UTC version of C =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 standard provides three functions for converting between integer epoch values and 6-component "broken-down" time representations. C and C 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 function converts a local broken-down time into an epoch value. However, C does not provide a UTC version of this. This module provides a function C 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 and C 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 it is I 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 module also provides a function called C with similar behaviour to this one. The differences are: =over 2 =item * C 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 croaks on out-of-range input. C also provides a function C which does not croak but it is documented that the behavior is unspecified on out-of-range values. =item * C is implemented by a light XS wrapper around the C 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 re-implements the logic in perl code. C will fall back to a perl implementation only if the XS one cannot be used. =back =head1 AUTHOR Paul Evans =cut 0x55AA;