File Coverage

blib/lib/Time/timegm.pm
Criterion Covered Total %
statement 40 40 100.0
branch 4 6 66.6
condition 1 3 33.3
subroutine 10 10 100.0
pod 0 1 0.0
total 55 60 91.6


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2012 -- leonerd@leonerd.org.uk
5              
6             package Time::timegm;
7              
8 2     2   25551 use strict;
  2         4  
  2         71  
9 2     2   11 use warnings;
  2         4  
  2         88  
10              
11             our $VERSION = '0.01';
12              
13 2     2   22 use Exporter 'import';
  2         3  
  2         197  
14              
15             our @EXPORT_OK = qw(
16             timegm
17             );
18              
19             unless( eval {
20             require XSLoader;
21             XSLoader::load( __PACKAGE__, $VERSION );
22             defined Time::timegm::timegm( 0, 0, 0, 0, 1, 70 )
23             } ) {
24             # Fallback on pureperl implementation
25             require POSIX;
26 2     2   9 no warnings 'redefine';
  2         10  
  2         93  
27             *timegm = \&timegm_pp;
28             }
29              
30 2     2   14 use Carp;
  2         2  
  2         199  
31              
32 2     2   1845 use POSIX qw( mktime );
  2         22734  
  2         17  
33              
34             # Number of seconds in a POSIX day
35 2     2   2383 use constant DAY => 24*60*60;
  2         5  
  2         179  
36 2     2   11 use constant HOUR => 60*60;
  2         5  
  2         99  
37 2     2   11 use constant MIN => 60;
  2         4  
  2         757  
38              
39             =head1 NAME
40              
41             C - a UTC version of C
42              
43             =head1 SYNOPSIS
44              
45             use Time::timegm qw( timegm );
46              
47             my $epoch = timegm( 0, 0, 0, 14, 6-1, 2012-1900 );
48              
49             print "2012-06-14 00:00:00 UTC happened at ",
50             scalar localtime($epoch), " localtime\n";
51              
52             =head1 DESCRIPTION
53              
54             The L standard provides three functions for converting between integer
55             epoch values and 6-component "broken-down" time representations. C
56             and C convert an epoch into the 6 components of seconds, minutes,
57             hours, day of month, month and year, in either local timezone or UTC. The
58             C function converts a local broken-down time into an epoch value.
59             However, C does not provide a UTC version of this.
60              
61             This module provides a function C which has this ability.
62              
63             Unlike some other CPAN implementations of this behaviour, this version does
64             not re-implement the time handling logic internally. It reuses the C
65             and C functions provided by the system to ensure its results are
66             always consistent with the other functions.
67              
68             =cut
69              
70             =head1 FUNCTIONS
71              
72             =cut
73              
74             =head2 $epoch = timegm( $sec, $min, $hour, $mday, $mon, $year )
75              
76             Returns the epoch integer value representing the time given by the 6
77             broken-down components.
78              
79             As with C it is I required that these values be within
80             their "valid" ranges. This function will normalise values out of range. For
81             example, the 25th hour of a day is normalised to the 1st hour of the following
82             day; or the 0th month is normalised to the 12th month of the preceeding year.
83              
84             =cut
85              
86             # Cache "$year/$mon" => $epoch of the time that month begins
87             my %start_of_month;
88              
89             sub timegm_pp
90             {
91 14     14 0 34 my ( $sec, $min, $hour, $mday, $mon, $year ) = @_;
92              
93             # Epoch times + UTC always align day boundaries at multiples of 86400. The
94             # structure is mathematically regular within a month. Therefore we can
95             # calculate the epoch time for a given time in UTC by finding the start of
96             # the month then adding seconds
97              
98 14         42 $mon-=12, $year++ while $mon >= 12;
99 14         34 $mon+=12, $year-- while $mon < 0;
100              
101 14         46 my $monstart = $start_of_month{"$year/$mon"};
102 14 100       31 unless( defined $monstart ) {
103 9         474 $monstart = mktime( 0, 0, 0, 1, $mon, $year );
104 9         19 $monstart -= $monstart % DAY;
105              
106 9         49 my @gmtime = gmtime $monstart;
107 9   33     57 $gmtime[$_] == 0 or croak "Expected midnight GMT, did not get it - " . scalar( gmtime $monstart ) for 0 .. 2;
108              
109             # Might have to round forward rather than backward
110 9 50       23 $monstart += DAY, @gmtime = gmtime $monstart if $gmtime[3] > 1;
111              
112 9 50       21 $gmtime[3] == 1 or croak "Expected 1st of month GMT, did not get it - " . scalar( gmtime $monstart );
113              
114 9         31 $start_of_month{"$year/$mon"} = $monstart;
115             }
116              
117 14         69 return $monstart + ($mday-1)*DAY + $hour*HOUR + $min*MIN + $sec;
118             }
119              
120             =head1 COMPARISON WITH Time::Local
121              
122             The L module also provides a function called C with
123             similar behaviour to this one. The differences are:
124              
125             =over 2
126              
127             =item *
128              
129             C handles denormalised values (that is, seconds or
130             minutes outside of the range 0 to 59, hours outside 0 to 23, etc..) by
131             adjusting the next largest unit (such that 61 seconds is 1 second of the next
132             minute, etc). C croaks on out-of-range input.
133             C also provides a function C which does not
134             croak but it is documented that the behavior is unspecified on out-of-range
135             values.
136              
137             =item *
138              
139             C is implemented by a light XS wrapper around the
140             C or C<_mkgmtime(3)> function provided by the platform's C library
141             if such a function is provided, so its behaviour is consistent with the rest
142             of the platform. C re-implements the logic in perl code.
143             C will fall back to a perl implementation only if the XS one
144             cannot be used.
145              
146             =back
147              
148             =head1 AUTHOR
149              
150             Paul Evans
151              
152             =cut
153              
154             0x55AA;