line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Time::Precise;
|
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
require Exporter;
|
4
|
2
|
|
|
2
|
|
44237
|
use Carp;
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
155
|
|
5
|
2
|
|
|
2
|
|
10
|
use Config;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
71
|
|
6
|
2
|
|
|
2
|
|
9
|
use strict;
|
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
50
|
|
7
|
2
|
|
|
2
|
|
1706
|
use Time::HiRes;
|
|
2
|
|
|
|
|
3253
|
|
|
2
|
|
|
|
|
9
|
|
8
|
|
|
|
|
|
|
|
9
|
2
|
|
|
2
|
|
206
|
use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK $PRECISION );
|
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
168
|
|
10
|
2
|
|
|
2
|
|
1581
|
use subs qw(localtime gmtime time sleep );
|
|
2
|
|
|
|
|
79
|
|
|
2
|
|
|
|
|
11
|
|
11
|
|
|
|
|
|
|
$VERSION = '1.0006';
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
@ISA = qw(Exporter);
|
14
|
|
|
|
|
|
|
@EXPORT = qw(time localtime gmtime sleep timegm timelocal is_valid_date is_leap_year time_hashref gmtime_hashref get_time_from get_gmtime_from);
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
$PRECISION = 7;
|
17
|
|
|
|
|
|
|
my @MonthDays = ( 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
|
18
|
|
|
|
|
|
|
my $month_duration = {
|
19
|
|
|
|
|
|
|
1 => 31,
|
20
|
|
|
|
|
|
|
2 => 28,
|
21
|
|
|
|
|
|
|
3 => 31,
|
22
|
|
|
|
|
|
|
4 => 30,
|
23
|
|
|
|
|
|
|
5 => 31,
|
24
|
|
|
|
|
|
|
6 => 30,
|
25
|
|
|
|
|
|
|
7 => 31,
|
26
|
|
|
|
|
|
|
8 => 31,
|
27
|
|
|
|
|
|
|
9 => 30,
|
28
|
|
|
|
|
|
|
10 => 31,
|
29
|
|
|
|
|
|
|
11 => 30,
|
30
|
|
|
|
|
|
|
12 => 31,
|
31
|
|
|
|
|
|
|
};
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Determine breakpoint for rolling century
|
34
|
|
|
|
|
|
|
#my $ThisYear = ( localtime() )[5];
|
35
|
|
|
|
|
|
|
#my $Breakpoint = ( $ThisYear + 50 ) % 100;
|
36
|
|
|
|
|
|
|
#my $NextCentury = $ThisYear - $ThisYear % 100;
|
37
|
|
|
|
|
|
|
#$NextCentury += 100 if $Breakpoint < 50;
|
38
|
|
|
|
|
|
|
#my $Century = $NextCentury - 100;
|
39
|
|
|
|
|
|
|
my $SecOff = 0;
|
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
my ( %Options, %Cheat );
|
42
|
|
|
|
|
|
|
|
43
|
2
|
|
|
2
|
|
265
|
use constant SECS_PER_MINUTE => 60;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
206
|
|
44
|
2
|
|
|
2
|
|
10
|
use constant SECS_PER_HOUR => 3600;
|
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
91
|
|
45
|
2
|
|
|
2
|
|
12
|
use constant SECS_PER_DAY => 86400;
|
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
4924
|
|
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
my $MaxDay;
|
48
|
|
|
|
|
|
|
if ($] < 5.012000) {
|
49
|
|
|
|
|
|
|
my $MaxInt;
|
50
|
|
|
|
|
|
|
if ( $^O eq 'MacOS' ) {
|
51
|
|
|
|
|
|
|
# time_t is unsigned...
|
52
|
|
|
|
|
|
|
$MaxInt = ( 1 << ( 8 * $Config{ivsize} ) ) - 1;
|
53
|
|
|
|
|
|
|
}
|
54
|
|
|
|
|
|
|
else {
|
55
|
|
|
|
|
|
|
$MaxInt = ( ( 1 << ( 8 * $Config{ivsize} - 2 ) ) - 1 ) * 2 + 1;
|
56
|
|
|
|
|
|
|
}
|
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
$MaxDay = int( ( $MaxInt - ( SECS_PER_DAY / 2 ) ) / SECS_PER_DAY ) - 1;
|
59
|
|
|
|
|
|
|
}
|
60
|
|
|
|
|
|
|
else {
|
61
|
|
|
|
|
|
|
# recent localtime()'s limit is the year 2**31
|
62
|
|
|
|
|
|
|
$MaxDay = 365 * (2**47); # Supported at least on 5.014 x64
|
63
|
|
|
|
|
|
|
}
|
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
# Determine the EPOC day for this machine
|
66
|
|
|
|
|
|
|
my $Epoc = 0;
|
67
|
|
|
|
|
|
|
if ( $^O eq 'vos' ) {
|
68
|
|
|
|
|
|
|
# work around posix-977 -- VOS doesn't handle dates in the range
|
69
|
|
|
|
|
|
|
# 1970-1980.
|
70
|
|
|
|
|
|
|
$Epoc = _daygm( 0, 0, 0, 1, 0, 70, 4, 0 );
|
71
|
|
|
|
|
|
|
}
|
72
|
|
|
|
|
|
|
elsif ( $^O eq 'MacOS' ) {
|
73
|
|
|
|
|
|
|
$MaxDay *=2 if $^O eq 'MacOS'; # time_t unsigned ... quick hack?
|
74
|
|
|
|
|
|
|
# MacOS time() is seconds since 1 Jan 1904, localtime
|
75
|
|
|
|
|
|
|
# so we need to calculate an offset to apply later
|
76
|
|
|
|
|
|
|
$Epoc = 693901;
|
77
|
|
|
|
|
|
|
$SecOff = timelocal( localtime(0)) - timelocal( gmtime(0) ) ;
|
78
|
|
|
|
|
|
|
$Epoc += _daygm( gmtime(0) );
|
79
|
|
|
|
|
|
|
}
|
80
|
|
|
|
|
|
|
else {
|
81
|
|
|
|
|
|
|
$Epoc = _daygm( gmtime(0) );
|
82
|
|
|
|
|
|
|
}
|
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
%Cheat = (); # clear the cache as epoc has changed
|
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
sub time () {
|
87
|
4
|
|
|
4
|
|
129
|
sprintf '%0.'.$PRECISION.'f', Time::HiRes::time();
|
88
|
|
|
|
|
|
|
}
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub _localtime {
|
91
|
9
|
|
|
9
|
|
14
|
my $gm = shift;
|
92
|
9
|
|
|
|
|
16
|
my $arg = $_[0];
|
93
|
9
|
50
|
|
|
|
30
|
$arg = time unless defined $arg;
|
94
|
9
|
|
|
|
|
98
|
$arg = sprintf '%.'.$PRECISION.'f', $arg;
|
95
|
9
|
|
|
|
|
39
|
my ($seconds, $microseconds) = split /\./, $arg;
|
96
|
9
|
100
|
|
|
|
26
|
if (wantarray) {
|
97
|
5
|
50
|
|
|
|
72
|
my @lt = $gm ? CORE::gmtime($arg) : CORE::localtime($arg);
|
98
|
5
|
50
|
|
|
|
28
|
$lt[0] .= ".$microseconds" if $PRECISION;
|
99
|
5
|
|
|
|
|
12
|
$lt[5] += 1900;
|
100
|
5
|
|
|
|
|
35
|
return @lt;
|
101
|
|
|
|
|
|
|
} else {
|
102
|
4
|
50
|
|
|
|
42
|
my $str = $gm ? scalar CORE::gmtime($arg) : scalar CORE::localtime($arg);
|
103
|
4
|
50
|
|
|
|
25
|
$str =~ s/(\d{2}:\d{2}:\d{2}) (\d{4})/$PRECISION ? "$1.$microseconds $2" : "$1 $2"/e;
|
|
4
|
|
|
|
|
25
|
|
104
|
4
|
|
|
|
|
19
|
$str;
|
105
|
|
|
|
|
|
|
}
|
106
|
|
|
|
|
|
|
}
|
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
sub localtime (;$) { # Precise localtime: always use full year format.
|
109
|
0
|
|
|
0
|
|
0
|
unshift @_, 0;
|
110
|
0
|
|
|
|
|
0
|
goto &_localtime;
|
111
|
|
|
|
|
|
|
}
|
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub gmtime (;$) { # Precise localtime: always use full year format.
|
114
|
9
|
|
|
9
|
|
1756
|
unshift @_, 1;
|
115
|
9
|
|
|
|
|
34
|
goto &_localtime;
|
116
|
|
|
|
|
|
|
}
|
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub sleep {
|
119
|
1
|
|
|
1
|
|
6
|
my $t = shift;
|
120
|
1
|
|
|
|
|
500219
|
Time::HiRes::sleep($t);
|
121
|
|
|
|
|
|
|
}
|
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
sub _daygm {
|
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# This is written in such a byzantine way in order to avoid
|
126
|
|
|
|
|
|
|
# lexical variables and sub calls, for speed
|
127
|
|
|
|
|
|
|
return $_[3] + (
|
128
|
4
|
|
66
|
4
|
|
43
|
$Cheat{ pack( 'ss', @_[ 4, 5 ] ) } ||= do {
|
129
|
3
|
|
|
|
|
10
|
my $month = ( $_[4] + 10 ) % 12;
|
130
|
3
|
|
|
|
|
10
|
my $year = $_[5] - int($month / 10);
|
131
|
|
|
|
|
|
|
(
|
132
|
3
|
|
|
|
|
28
|
( 365 * $year )
|
133
|
|
|
|
|
|
|
+ int( $year / 4 )
|
134
|
|
|
|
|
|
|
- int( $year / 100 )
|
135
|
|
|
|
|
|
|
+ int( $year / 400 )
|
136
|
|
|
|
|
|
|
+ int( ( ( $month * 306 ) + 5 ) / 10 )
|
137
|
|
|
|
|
|
|
) - $Epoc;
|
138
|
|
|
|
|
|
|
}
|
139
|
|
|
|
|
|
|
);
|
140
|
|
|
|
|
|
|
}
|
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub _timegm {
|
143
|
0
|
|
|
0
|
|
0
|
my $sec =
|
144
|
|
|
|
|
|
|
$SecOff + $_[0] + ( SECS_PER_MINUTE * $_[1] ) + ( SECS_PER_HOUR * $_[2] );
|
145
|
|
|
|
|
|
|
|
146
|
0
|
|
|
|
|
0
|
return $sec + ( SECS_PER_DAY * &_daygm );
|
147
|
|
|
|
|
|
|
}
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub timegm {
|
150
|
2
|
|
|
2
|
1
|
13
|
my ( $sec, $min, $hour, $mday, $month, $year ) = @_;
|
151
|
2
|
|
|
|
|
24
|
($sec, my $microsec) = split /\./, sprintf '%.'.$PRECISION.'f', $sec;
|
152
|
2
|
50
|
|
|
|
12
|
unless ( $Options{no_range_check} ) {
|
153
|
2
|
50
|
33
|
|
|
18
|
croak "Month '$month' out of range 0..11"
|
154
|
|
|
|
|
|
|
if $month > 11
|
155
|
|
|
|
|
|
|
or $month < 0;
|
156
|
|
|
|
|
|
|
|
157
|
2
|
|
|
|
|
11
|
my $md = $MonthDays[$month];
|
158
|
2
|
50
|
33
|
|
|
11
|
++$md
|
159
|
|
|
|
|
|
|
if $month == 1 && _is_leap_year( $year );
|
160
|
|
|
|
|
|
|
|
161
|
2
|
50
|
33
|
|
|
16
|
croak "Day '$mday' out of range 1..$md" if $mday > $md or $mday < 1;
|
162
|
2
|
50
|
33
|
|
|
15
|
croak "Hour '$hour' out of range 0..23" if $hour > 23 or $hour < 0;
|
163
|
2
|
50
|
33
|
|
|
14
|
croak "Minute '$min' out of range 0..59" if $min > 59 or $min < 0;
|
164
|
2
|
50
|
33
|
|
|
17
|
croak "Second '$sec' out of range 0..59" if $sec > 59 or $sec < 0;
|
165
|
|
|
|
|
|
|
}
|
166
|
|
|
|
|
|
|
|
167
|
2
|
|
|
|
|
7
|
my $days = _daygm( undef, undef, undef, $mday, $month, $year );
|
168
|
|
|
|
|
|
|
|
169
|
2
|
50
|
33
|
|
|
18
|
unless ($Options{no_range_check} or abs($days) < $MaxDay) {
|
170
|
0
|
|
|
|
|
0
|
my $msg = '';
|
171
|
0
|
0
|
|
|
|
0
|
$msg .= "Day too big - $days > $MaxDay\n" if $days > $MaxDay;
|
172
|
|
|
|
|
|
|
|
173
|
0
|
|
|
|
|
0
|
$msg .= "Cannot handle date ($sec, $min, $hour, $mday, $month, $year)";
|
174
|
|
|
|
|
|
|
|
175
|
0
|
|
|
|
|
0
|
croak $msg;
|
176
|
|
|
|
|
|
|
}
|
177
|
|
|
|
|
|
|
|
178
|
2
|
|
|
|
|
4
|
my $fix = 0;
|
179
|
2
|
50
|
33
|
|
|
16
|
$fix -= 60*60*24 if ($year < 0 and not _is_leap_year($year));
|
180
|
2
|
|
|
|
|
24
|
return ($sec
|
181
|
|
|
|
|
|
|
+ $SecOff
|
182
|
|
|
|
|
|
|
+ ( SECS_PER_MINUTE * $min )
|
183
|
|
|
|
|
|
|
+ ( SECS_PER_HOUR * $hour )
|
184
|
|
|
|
|
|
|
+ ( SECS_PER_DAY * $days )
|
185
|
|
|
|
|
|
|
+ $fix).".$microsec";
|
186
|
|
|
|
|
|
|
}
|
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
sub _is_leap_year {
|
189
|
4
|
100
|
|
4
|
|
46
|
return 0 if $_[0] % 4;
|
190
|
1
|
50
|
|
|
|
5
|
return 1 if $_[0] % 100;
|
191
|
1
|
50
|
|
|
|
5
|
return 0 if $_[0] % 400;
|
192
|
1
|
|
|
|
|
5
|
return 1;
|
193
|
|
|
|
|
|
|
}
|
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
sub timegm_nocheck {
|
196
|
0
|
|
|
0
|
0
|
0
|
local $Options{no_range_check} = 1;
|
197
|
0
|
|
|
|
|
0
|
return &timegm;
|
198
|
|
|
|
|
|
|
}
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub timelocal {
|
201
|
0
|
|
|
0
|
1
|
0
|
my ($ref_t, $microsec) = split /\./, &timegm;
|
202
|
0
|
0
|
0
|
|
|
0
|
$ref_t += 60*60*24 if ($_[5] < 0 and not _is_leap_year($_[5]));
|
203
|
0
|
|
|
|
|
0
|
my $loc_for_ref_t = _timegm( localtime($ref_t) );
|
204
|
|
|
|
|
|
|
|
205
|
0
|
0
|
|
|
|
0
|
my $zone_off = $loc_for_ref_t - $ref_t
|
206
|
|
|
|
|
|
|
or return "$loc_for_ref_t.$microsec";
|
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# Adjust for timezone
|
209
|
0
|
|
|
|
|
0
|
my $loc_t = $ref_t - $zone_off;
|
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# Are we close to a DST change or are we done
|
212
|
0
|
|
|
|
|
0
|
my $dst_off = $ref_t - _timegm( localtime($loc_t) );
|
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
# If this evaluates to true, it means that the value in $loc_t is
|
215
|
|
|
|
|
|
|
# the _second_ hour after a DST change where the local time moves
|
216
|
|
|
|
|
|
|
# backward.
|
217
|
0
|
0
|
0
|
|
|
0
|
if ( ! $dst_off &&
|
218
|
|
|
|
|
|
|
( ( $ref_t - SECS_PER_HOUR ) - _timegm( localtime( $loc_t - SECS_PER_HOUR ) ) < 0 )
|
219
|
|
|
|
|
|
|
) {
|
220
|
0
|
|
|
|
|
0
|
return ''.($loc_t - SECS_PER_HOUR).".$microsec";
|
221
|
|
|
|
|
|
|
}
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# Adjust for DST change
|
224
|
0
|
|
|
|
|
0
|
$loc_t += $dst_off;
|
225
|
|
|
|
|
|
|
|
226
|
0
|
0
|
|
|
|
0
|
return "$loc_t.$microsec" if $dst_off > 0;
|
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# If the original date was a non-extent gap in a forward DST jump,
|
229
|
|
|
|
|
|
|
# we should now have the wrong answer - undo the DST adjustment
|
230
|
0
|
|
|
|
|
0
|
my ( $s, $m, $h ) = localtime($loc_t);
|
231
|
0
|
0
|
0
|
|
|
0
|
$loc_t -= $dst_off if $s != $_[0] || $m != $_[1] || $h != $_[2];
|
|
|
|
0
|
|
|
|
|
232
|
|
|
|
|
|
|
|
233
|
0
|
|
|
|
|
0
|
return "$loc_t.$microsec";
|
234
|
|
|
|
|
|
|
}
|
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
sub timelocal_nocheck {
|
237
|
0
|
|
|
0
|
0
|
0
|
local $Options{no_range_check} = 1;
|
238
|
0
|
|
|
|
|
0
|
return &timelocal;
|
239
|
|
|
|
|
|
|
}
|
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
sub is_valid_date {
|
242
|
6
|
|
|
6
|
1
|
22
|
my ($year, $month, $day) = @_;
|
243
|
6
|
50
|
33
|
|
|
122
|
return 0 unless ($year =~ /^\d+$/ and $month =~ /^\d+$/ and $day =~ /^\d+$/);
|
|
|
|
33
|
|
|
|
|
244
|
6
|
|
|
|
|
15
|
$year += 0;
|
245
|
6
|
|
|
|
|
12
|
$month += 0;
|
246
|
6
|
|
|
|
|
14
|
$day += 0;
|
247
|
6
|
50
|
|
|
|
21
|
return 0 unless $year;
|
248
|
6
|
50
|
33
|
|
|
39
|
return 0 if ($month < 1 or $month > 12);
|
249
|
6
|
50
|
|
|
|
20
|
return 0 if $day < 1;
|
250
|
6
|
100
|
|
|
|
20
|
if ($month == 2) {
|
251
|
2
|
100
|
|
|
|
11
|
if (is_leap_year($year)) {
|
252
|
1
|
50
|
|
|
|
18
|
return 0 if $day > 29;
|
253
|
|
|
|
|
|
|
} else {
|
254
|
1
|
50
|
|
|
|
11
|
return 0 if $day > 28;
|
255
|
|
|
|
|
|
|
}
|
256
|
|
|
|
|
|
|
} else {
|
257
|
4
|
100
|
|
|
|
35
|
return 0 if $day > $month_duration->{$month};
|
258
|
|
|
|
|
|
|
}
|
259
|
3
|
|
|
|
|
19
|
return 1;
|
260
|
|
|
|
|
|
|
}
|
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
sub is_leap_year {
|
263
|
4
|
|
|
4
|
1
|
15
|
_is_leap_year(shift);
|
264
|
|
|
|
|
|
|
}
|
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
sub time_hashref (;$) {
|
267
|
0
|
|
|
0
|
1
|
0
|
_time_hashref(shift);
|
268
|
|
|
|
|
|
|
}
|
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub gmtime_hashref {
|
271
|
2
|
|
|
2
|
1
|
11
|
_time_hashref(shift, 1);
|
272
|
|
|
|
|
|
|
}
|
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
sub _time_hashref {
|
275
|
2
|
|
|
2
|
|
6
|
my $time = shift;
|
276
|
2
|
|
|
|
|
4
|
my $gmt = shift;
|
277
|
2
|
100
|
|
|
|
13
|
$time = time() unless defined $time;
|
278
|
2
|
50
|
|
|
|
19
|
my @lt = $gmt ? gmtime(int $time) : localtime(int $time);
|
279
|
2
|
|
|
|
|
34
|
(my $microseconds = sprintf '%0.'.$PRECISION.'f', ($time - int $time)) =~ s/^.+\.//;
|
280
|
|
|
|
|
|
|
return {
|
281
|
2
|
|
|
|
|
32
|
second => sprintf("%02d.$microseconds", $lt[0]),
|
282
|
|
|
|
|
|
|
minute => sprintf("%02d", $lt[1]),
|
283
|
|
|
|
|
|
|
hour => sprintf("%02d", $lt[2]),
|
284
|
|
|
|
|
|
|
day => sprintf("%02d", $lt[3]),
|
285
|
|
|
|
|
|
|
month => sprintf("%02d", ($lt[4] + 1)),
|
286
|
|
|
|
|
|
|
year => sprintf("%04d", $lt[5]),
|
287
|
|
|
|
|
|
|
wday => $lt[6],
|
288
|
|
|
|
|
|
|
yday => $lt[7],
|
289
|
|
|
|
|
|
|
isdst => $lt[8],
|
290
|
|
|
|
|
|
|
is_leap_year => is_leap_year($lt[5]),
|
291
|
|
|
|
|
|
|
};
|
292
|
|
|
|
|
|
|
}
|
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub get_time_from {
|
295
|
0
|
|
|
0
|
1
|
0
|
_get_time_from('', @_);
|
296
|
|
|
|
|
|
|
}
|
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
sub get_gmtime_from {
|
299
|
1
|
|
|
1
|
1
|
3249
|
_get_time_from(1, @_);
|
300
|
|
|
|
|
|
|
}
|
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
sub _get_time_from {
|
303
|
1
|
|
|
1
|
|
7
|
my @call = caller;
|
304
|
1
|
|
|
|
|
2
|
my $gm = shift;
|
305
|
1
|
50
|
|
|
|
6
|
die("get_time_from expects name => value optional parameters (day, month, year, hour, minute, second) at $call[1] line $call[2]\n") if @_ % 2;
|
306
|
1
|
50
|
|
|
|
5
|
my $time = $gm ? gmtime_hashref : time_hashref;
|
307
|
|
|
|
|
|
|
my $p = {
|
308
|
|
|
|
|
|
|
day => $time->{day},
|
309
|
|
|
|
|
|
|
month => $time->{month},
|
310
|
|
|
|
|
|
|
year => $time->{year},
|
311
|
1
|
|
|
|
|
7
|
minute => 0,
|
312
|
|
|
|
|
|
|
hour => 0,
|
313
|
|
|
|
|
|
|
second => 0,
|
314
|
|
|
|
|
|
|
@_,
|
315
|
|
|
|
|
|
|
};
|
316
|
1
|
|
|
|
|
4
|
for my $i (qw(day month year minute hour second)) {
|
317
|
6
|
50
|
|
|
|
34
|
die("Parameter $i must be numeric at $call[1] line $call[2]\n") unless $p->{$i} =~ /^(-){0,1}\d+(\.\d+){0,1}$/;
|
318
|
|
|
|
|
|
|
}
|
319
|
1
|
50
|
33
|
|
|
21
|
die("Invalid parameter month, out of range 1..12 at $call[1] line $call[2]\n") if ($p->{month} < 1 or $p->{month} > 12);
|
320
|
1
|
|
|
|
|
2
|
for my $i (qw(minute hour second)) {
|
321
|
3
|
50
|
33
|
|
|
19
|
die("Invalid parameter $i, out of range '>= 0' and '< 60' at $call[1] line $call[2]\n") unless $p->{$i} >= 0 and $p->{$i} < 60;
|
322
|
|
|
|
|
|
|
}
|
323
|
1
|
0
|
|
|
|
5
|
my $max_day = $month_duration->{int $p->{month}} + ((int($p->{month}) == 2) ? is_leap_year($p->{year}) ? 1 : 0 : 0);
|
|
|
50
|
|
|
|
|
|
324
|
1
|
50
|
33
|
|
|
7
|
die("Invalid parameter day, out of range 1-$max_day at $call[1] line $call[2]\n") unless $p->{day} >= 1 and $p->{day} <= $max_day;
|
325
|
1
|
50
|
|
|
|
7
|
$gm ? timegm($p->{second}, $p->{minute}, $p->{hour}, $p->{day}, $p->{month}-1, $p->{year}) : timelocal($p->{second}, $p->{minute}, $p->{hour}, $p->{day}, $p->{month}-1, $p->{year});
|
326
|
|
|
|
|
|
|
}
|
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
1;
|
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
__END__
|