Profile of Time/Local.pm

← Index
NYTProf Performance Profile «line view»
For t/bug-md-11.t
Run on Fri Mar 8 13:27:24 2024
Reported on Fri Mar 8 13:30:23 2024

Filename | /home/micha/.plenv/versions/5.38.2/lib/perl5/site_perl/5.38.2/Time/Local.pm
Statements | Executed 37 statements in 810µs

Subroutines
Calls | P | F | Exclusive Time | Inclusive Time | Subroutine
--- | --- | --- | --- | --- | ---
1 | 1 | 1 | 9µs | 10µs | Time::Local::::BEGIN@3Time::Local::BEGIN@3
1 | 1 | 1 | 8µs | 10µs | Time::Local::::_daygmTime::Local::_daygm
1 | 1 | 1 | 3µs | 24µs | Time::Local::::BEGIN@34Time::Local::BEGIN@34
1 | 1 | 1 | 3µs | 12µs | Time::Local::::BEGIN@6Time::Local::BEGIN@6
1 | 1 | 1 | 3µs | 12µs | Time::Local::::BEGIN@10Time::Local::BEGIN@10
1 | 1 | 1 | 3µs | 19µs | Time::Local::::BEGIN@35Time::Local::BEGIN@35
1 | 1 | 1 | 2µs | 16µs | Time::Local::::BEGIN@36Time::Local::BEGIN@36
1 | 1 | 1 | 2µs | 2µs | Time::Local::::BEGIN@5Time::Local::BEGIN@5
0 | 0 | 0 | 0s | 0s | Time::Local::::_is_leap_yearTime::Local::_is_leap_year
0 | 0 | 0 | 0s | 0s | Time::Local::::_timegmTime::Local::_timegm
0 | 0 | 0 | 0s | 0s | Time::Local::::timegmTime::Local::timegm
0 | 0 | 0 | 0s | 0s | Time::Local::::timegm_modernTime::Local::timegm_modern
0 | 0 | 0 | 0s | 0s | Time::Local::::timegm_nocheckTime::Local::timegm_nocheck
0 | 0 | 0 | 0s | 0s | Time::Local::::timegm_posixTime::Local::timegm_posix
0 | 0 | 0 | 0s | 0s | Time::Local::::timelocalTime::Local::timelocal
0 | 0 | 0 | 0s | 0s | Time::Local::::timelocal_modernTime::Local::timelocal_modern
0 | 0 | 0 | 0s | 0s | Time::Local::::timelocal_nocheckTime::Local::timelocal_nocheck
0 | 0 | 0 | 0s | 0s | Time::Local::::timelocal_posixTime::Local::timelocal_posix

Call graph for these subroutines as a Graphviz dot language file.

Line | State ments | Time on line | Calls | Time in subs | Code
--- | --- | --- | --- | --- | ---
1 |  |  |  |  | package Time::Local;
2 |  |  |  |  |
3 | 2 | 17µs | 2 | 12µs | # spent 10µs (9+2) within Time::Local::BEGIN@3 which was called: # once (9µs+2µs) by Archive::Zip::Member::BEGIN@27 at line 3 use strict; # spent 10µs making 1 call to Time::Local::BEGIN@3 # spent 2µs making 1 call to strict::import
4 |  |  |  |  |
5 | 2 | 15µs | 1 | 2µs | # spent 2µs within Time::Local::BEGIN@5 which was called: # once (2µs+0s) by Archive::Zip::Member::BEGIN@27 at line 5 use Carp (); # spent 2µs making 1 call to Time::Local::BEGIN@5
6 | 2 | 20µs | 2 | 22µs | # spent 12µs (3+9) within Time::Local::BEGIN@6 which was called: # once (3µs+9µs) by Archive::Zip::Member::BEGIN@27 at line 6 use Exporter; # spent 12µs making 1 call to Time::Local::BEGIN@6 # spent 9µs making 1 call to Exporter::import
7 |  |  |  |  |
8 | 1 | 200ns |  |  | our $VERSION = '1.35';
9 |  |  |  |  |
10 | 2 | 60µs | 2 | 21µs | # spent 12µs (3+9) within Time::Local::BEGIN@10 which was called: # once (3µs+9µs) by Archive::Zip::Member::BEGIN@27 at line 10 use parent 'Exporter'; # spent 12µs making 1 call to Time::Local::BEGIN@10 # spent 9µs making 1 call to parent::import
11 |  |  |  |  |
12 | 1 | 700ns |  |  | our @EXPORT = qw( timegm timelocal );
13 | 1 | 500ns |  |  | our @EXPORT_OK = qw(
14 |  |  |  |  | timegm_modern
15 |  |  |  |  | timelocal_modern
16 |  |  |  |  | timegm_nocheck
17 |  |  |  |  | timelocal_nocheck
18 |  |  |  |  | timegm_posix
19 |  |  |  |  | timelocal_posix
20 |  |  |  |  | );
21 |  |  |  |  |
22 | 1 | 500ns |  |  | my @MonthDays = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
23 |  |  |  |  |
24 |  |  |  |  | # Determine breakpoint for rolling century
25 | 1 | 10µs |  |  | my $ThisYear = ( localtime() )[5];
26 | 1 | 900ns |  |  | my $Breakpoint = ( $ThisYear + 50 ) % 100;
27 | 1 | 300ns |  |  | my $NextCentury = $ThisYear - $ThisYear % 100;
28 | 1 | 100ns |  |  | $NextCentury += 100 if $Breakpoint < 50;
29 | 1 | 100ns |  |  | my $Century = $NextCentury - 100;
30 | 1 | 0s |  |  | my $SecOff = 0;
31 |  |  |  |  |
32 | 1 | 100ns |  |  | my ( %Options, %Cheat );
33 |  |  |  |  |
34 | 2 | 18µs | 2 | 45µs | # spent 24µs (3+21) within Time::Local::BEGIN@34 which was called: # once (3µs+21µs) by Archive::Zip::Member::BEGIN@27 at line 34 use constant SECS_PER_MINUTE => 60; # spent 24µs making 1 call to Time::Local::BEGIN@34 # spent 21µs making 1 call to constant::import
35 | 2 | 12µs | 2 | 34µs | # spent 19µs (3+16) within Time::Local::BEGIN@35 which was called: # once (3µs+16µs) by Archive::Zip::Member::BEGIN@27 at line 35 use constant SECS_PER_HOUR => 3600; # spent 19µs making 1 call to Time::Local::BEGIN@35 # spent 16µs making 1 call to constant::import
36 | 2 | 628µs | 2 | 30µs | # spent 16µs (2+14) within Time::Local::BEGIN@36 which was called: # once (2µs+14µs) by Archive::Zip::Member::BEGIN@27 at line 36 use constant SECS_PER_DAY => 86400; # spent 16µs making 1 call to Time::Local::BEGIN@36 # spent 14µs making 1 call to constant::import
37 |  |  |  |  |
38 |  |  |  |  | my $MaxDay;
39 | 1 | 300ns |  |  | if ( $] < 5.012000 ) {
40 |  |  |  |  | require Config;
41 |  |  |  |  | ## no critic (Variables::ProhibitPackageVars)
42 |  |  |  |  |
43 |  |  |  |  | my $MaxInt;
44 |  |  |  |  | if ( $^O eq 'MacOS' ) {
45 |  |  |  |  |
46 |  |  |  |  | # time_t is unsigned...
47 |  |  |  |  | $MaxInt = ( 1 << ( 8 * $Config::Config{ivsize} ) )
48 |  |  |  |  | - 1; ## no critic qw(ProhibitPackageVars)
49 |  |  |  |  | }
50 |  |  |  |  | else {
51 |  |  |  |  | $MaxInt
52 |  |  |  |  | = ( ( 1 << ( 8 * $Config::Config{ivsize} - 2 ) ) - 1 ) * 2
53 |  |  |  |  | + 1; ## no critic qw(ProhibitPackageVars)
54 |  |  |  |  | }
55 |  |  |  |  |
56 |  |  |  |  | $MaxDay = int( ( $MaxInt - ( SECS_PER_DAY / 2 ) ) / SECS_PER_DAY ) - 1;
57 |  |  |  |  | }
58 |  |  |  |  | else {
59 |  |  |  |  | # recent localtime()'s limit is the year 2**31
60 | 1 | 100ns |  |  | $MaxDay = 365 * ( 2**31 );
61 |  |  |  |  |
62 |  |  |  |  | # On (some?) 32-bit platforms this overflows and we end up with a negative
63 |  |  |  |  | # $MaxDay, which totally breaks this module. This is the old calculation
64 |  |  |  |  | # we used from the days before Perl always had 64-bit time_t.
65 | 1 | 100ns |  |  | if ( $MaxDay < 0 ) {
66 |  |  |  |  | require Config;
67 |  |  |  |  | ## no critic (Variables::ProhibitPackageVars)
68 |  |  |  |  | my $max_int
69 |  |  |  |  | = ( ( 1 << ( 8 * $Config::Config{intsize} - 2 ) ) - 1 ) * 2 + 1;
70 |  |  |  |  | $MaxDay
71 |  |  |  |  | = int( ( $max_int - ( SECS_PER_DAY / 2 ) ) / SECS_PER_DAY ) - 1;
72 |  |  |  |  | }
73 |  |  |  |  | }
74 |  |  |  |  |
75 |  |  |  |  | # Determine the EPOC day for this machine
76 | 1 | 100ns |  |  | my $Epoc = 0;
77 | 1 | 1µs |  |  | if ( $^O eq 'vos' ) {
78 |  |  |  |  |
79 |  |  |  |  | # work around posix-977 -- VOS doesn't handle dates in the range
80 |  |  |  |  | # 1970-1980.
81 |  |  |  |  | $Epoc = _daygm( 0, 0, 0, 1, 0, 70, 4, 0 );
82 |  |  |  |  | }
83 |  |  |  |  | elsif ( $^O eq 'MacOS' ) {
84 |  |  |  |  | $MaxDay *= 2; # time_t unsigned ... quick hack?
85 |  |  |  |  | # MacOS time() is seconds since 1 Jan 1904, localtime
86 |  |  |  |  | # so we need to calculate an offset to apply later
87 |  |  |  |  | $Epoc = 693901;
88 |  |  |  |  | $SecOff = timelocal( localtime(0) ) - timelocal( gmtime(0) );
89 |  |  |  |  | $Epoc += _daygm( gmtime(0) );
90 |  |  |  |  | }
91 |  |  |  |  | else {
92 | 1 | 3µs | 1 | 10µs | $Epoc = _daygm( gmtime(0) ); # spent 10µs making 1 call to Time::Local::_daygm
93 |  |  |  |  | }
94 |  |  |  |  |
95 | 1 | 500ns |  |  | %Cheat = (); # clear the cache as epoc has changed
96 |  |  |  |  |
97 |  |  |  |  | # spent 10µs (8+1) within Time::Local::_daygm which was called: # once (8µs+1µs) by Archive::Zip::Member::BEGIN@27 at line 92 sub _daygm {
98 |  |  |  |  |
99 |  |  |  |  | # This is written in such a byzantine way in order to avoid
100 |  |  |  |  | # lexical variables and sub calls, for speed
101 |  |  |  |  | return $_[3] + (
102 | 1 | 8µs | 1 | 1µs | $Cheat{ pack( 'ss', @_[ 4, 5 ] ) } ||= do { # spent 1µs making 1 call to CORE::pack
103 | 1 | 300ns |  |  | my $month = ( $_[4] + 10 ) % 12;
104 | 1 | 700ns |  |  | my $year = $_[5] + 1900 - int( $month / 10 );
105 |  |  |  |  |
106 | 1 | 2µs |  |  | ( ( 365 * $year )
107 |  |  |  |  | + int( $year / 4 )
108 |  |  |  |  | - int( $year / 100 )
109 |  |  |  |  | + int( $year / 400 )
110 |  |  |  |  | + int( ( ( $month * 306 ) + 5 ) / 10 ) )
111 |  |  |  |  | - $Epoc;
112 |  |  |  |  | }
113 |  |  |  |  | );
114 |  |  |  |  | }
115 |  |  |  |  |
116 |  |  |  |  | sub _timegm {
117 |  |  |  |  | my $sec
118 |  |  |  |  | = $SecOff + $_[0]
119 |  |  |  |  | + ( SECS_PER_MINUTE * $_[1] )
120 |  |  |  |  | + ( SECS_PER_HOUR * $_[2] );
121 |  |  |  |  |
122 |  |  |  |  | return $sec + ( SECS_PER_DAY * &_daygm );
123 |  |  |  |  | }
124 |  |  |  |  |
125 |  |  |  |  | sub timegm {
126 |  |  |  |  | my ( $sec, $min, $hour, $mday, $month, $year ) = @_;
127 |  |  |  |  | my $subsec = $sec - int($sec);
128 |  |  |  |  | $sec = int($sec);
129 |  |  |  |  |
130 |  |  |  |  | if ( $Options{no_year_munging} ) {
131 |  |  |  |  | $year -= 1900;
132 |  |  |  |  | }
133 |  |  |  |  | elsif ( !$Options{posix_year} ) {
134 |  |  |  |  | if ( $year >= 1000 ) {
135 |  |  |  |  | $year -= 1900;
136 |  |  |  |  | }
137 |  |  |  |  | elsif ( $year < 100 and $year >= 0 ) {
138 |  |  |  |  | $year += ( $year > $Breakpoint ) ? $Century : $NextCentury;
139 |  |  |  |  | }
140 |  |  |  |  | }
141 |  |  |  |  |
142 |  |  |  |  | unless ( $Options{no_range_check} ) {
143 |  |  |  |  | Carp::croak("Month '$month' out of range 0..11")
144 |  |  |  |  | if $month > 11
145 |  |  |  |  | or $month < 0;
146 |  |  |  |  |
147 |  |  |  |  | my $md = $MonthDays[$month];
148 |  |  |  |  | ++$md
149 |  |  |  |  | if $month == 1 && _is_leap_year( $year + 1900 );
150 |  |  |  |  |
151 |  |  |  |  | Carp::croak("Day '$mday' out of range 1..$md")
152 |  |  |  |  | if $mday > $md or $mday < 1;
153 |  |  |  |  | Carp::croak("Hour '$hour' out of range 0..23")
154 |  |  |  |  | if $hour > 23 or $hour < 0;
155 |  |  |  |  | Carp::croak("Minute '$min' out of range 0..59")
156 |  |  |  |  | if $min > 59 or $min < 0;
157 |  |  |  |  | Carp::croak("Second '$sec' out of range 0..59")
158 |  |  |  |  | if $sec >= 60 or $sec < 0;
159 |  |  |  |  | }
160 |  |  |  |  |
161 |  |  |  |  | my $days = _daygm( undef, undef, undef, $mday, $month, $year );
162 |  |  |  |  |
163 |  |  |  |  | if ( abs($days) > $MaxDay && !$Options{no_range_check} ) {
164 |  |  |  |  | my $msg = "Day too big - abs($days) > $MaxDay\n";
165 |  |  |  |  |
166 |  |  |  |  | $year += 1900;
167 |  |  |  |  | $msg
168 |  |  |  |  | .= "Cannot handle date ($sec, $min, $hour, $mday, $month, $year)";
169 |  |  |  |  |
170 |  |  |  |  | Carp::croak($msg);
171 |  |  |  |  | }
172 |  |  |  |  |
173 |  |  |  |  | # Adding in the $subsec value last seems to prevent floating point errors
174 |  |  |  |  | # from creeping in.
175 |  |  |  |  | return (
176 |  |  |  |  | (
177 |  |  |  |  | $sec + $SecOff
178 |  |  |  |  | + ( SECS_PER_MINUTE * $min )
179 |  |  |  |  | + ( SECS_PER_HOUR * $hour )
180 |  |  |  |  | + ( SECS_PER_DAY * $days )
181 |  |  |  |  | ) + $subsec
182 |  |  |  |  | );
183 |  |  |  |  | }
184 |  |  |  |  |
185 |  |  |  |  | sub _is_leap_year {
186 |  |  |  |  | return 0 if $_[0] % 4;
187 |  |  |  |  | return 1 if $_[0] % 100;
188 |  |  |  |  | return 0 if $_[0] % 400;
189 |  |  |  |  |
190 |  |  |  |  | return 1;
191 |  |  |  |  | }
192 |  |  |  |  |
193 |  |  |  |  | sub timegm_nocheck {
194 |  |  |  |  | local $Options{no_range_check} = 1;
195 |  |  |  |  | return &timegm;
196 |  |  |  |  | }
197 |  |  |  |  |
198 |  |  |  |  | sub timegm_modern {
199 |  |  |  |  | local $Options{no_year_munging} = 1;
200 |  |  |  |  | return &timegm;
201 |  |  |  |  | }
202 |  |  |  |  |
203 |  |  |  |  | sub timegm_posix {
204 |  |  |  |  | local $Options{posix_year} = 1;
205 |  |  |  |  | return &timegm;
206 |  |  |  |  | }
207 |  |  |  |  |
208 |  |  |  |  | sub timelocal {
209 |  |  |  |  | my $sec = shift;
210 |  |  |  |  | my $subsec = $sec - int($sec);
211 |  |  |  |  | $sec = int($sec);
212 |  |  |  |  | unshift @_, $sec;
213 |  |  |  |  |
214 |  |  |  |  | my $ref_t = &timegm;
215 |  |  |  |  | my $loc_for_ref_t = _timegm( localtime($ref_t) );
216 |  |  |  |  |
217 |  |  |  |  | my $zone_off = $loc_for_ref_t - $ref_t
218 |  |  |  |  | or return $loc_for_ref_t + $subsec;
219 |  |  |  |  |
220 |  |  |  |  | # Adjust for timezone
221 |  |  |  |  | my $loc_t = $ref_t - $zone_off;
222 |  |  |  |  |
223 |  |  |  |  | # Are we close to a DST change or are we done
224 |  |  |  |  | my $dst_off = $ref_t - _timegm( localtime($loc_t) );
225 |  |  |  |  |
226 |  |  |  |  | # If this evaluates to true, it means that the value in $loc_t is
227 |  |  |  |  | # the _second_ hour after a DST change where the local time moves
228 |  |  |  |  | # backward.
229 |  |  |  |  | if (
230 |  |  |  |  | !$dst_off
231 |  |  |  |  | && ( ( $ref_t - SECS_PER_HOUR )
232 |  |  |  |  | - _timegm( localtime( $loc_t - SECS_PER_HOUR ) ) < 0 )
233 |  |  |  |  | ) {
234 |  |  |  |  | return ( $loc_t - SECS_PER_HOUR ) + $subsec;
235 |  |  |  |  | }
236 |  |  |  |  |
237 |  |  |  |  | # Adjust for DST change
238 |  |  |  |  | $loc_t += $dst_off;
239 |  |  |  |  |
240 |  |  |  |  | return $loc_t + $subsec if $dst_off > 0;
241 |  |  |  |  |
242 |  |  |  |  | # If the original date was a non-existent gap in a forward DST jump, we
243 |  |  |  |  | # should now have the wrong answer - undo the DST adjustment
244 |  |  |  |  | my ( $s, $m, $h ) = localtime($loc_t);
245 |  |  |  |  | $loc_t -= $dst_off if $s != $_[0] || $m != $_[1] || $h != $_[2];
246 |  |  |  |  |
247 |  |  |  |  | return $loc_t + $subsec;
248 |  |  |  |  | }
249 |  |  |  |  |
250 |  |  |  |  | sub timelocal_nocheck {
251 |  |  |  |  | local $Options{no_range_check} = 1;
252 |  |  |  |  | return &timelocal;
253 |  |  |  |  | }
254 |  |  |  |  |
255 |  |  |  |  | sub timelocal_modern {
256 |  |  |  |  | local $Options{no_year_munging} = 1;
257 |  |  |  |  | return &timelocal;
258 |  |  |  |  | }
259 |  |  |  |  |
260 |  |  |  |  | sub timelocal_posix {
261 |  |  |  |  | local $Options{posix_year} = 1;
262 |  |  |  |  | return &timelocal;
263 |  |  |  |  | }
264 |  |  |  |  |
265 | 1 | 11µs |  |  | 1;
266 |  |  |  |  |
267 |  |  |  |  | # ABSTRACT: Efficiently compute time from local and GMT time
268 |  |  |  |  |
269 |  |  |  |  | __END__