| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
########################################### |
|
2
|
|
|
|
|
|
|
########################################### |
|
3
|
|
|
|
|
|
|
use warnings; |
|
4
|
70
|
|
|
70
|
|
363
|
use strict; |
|
|
70
|
|
|
|
|
111
|
|
|
|
70
|
|
|
|
|
1729
|
|
|
5
|
70
|
|
|
70
|
|
341
|
|
|
|
70
|
|
|
|
|
115
|
|
|
|
70
|
|
|
|
|
1301
|
|
|
6
|
|
|
|
|
|
|
use Carp qw( croak ); |
|
7
|
70
|
|
|
70
|
|
278
|
|
|
|
70
|
|
|
|
|
130
|
|
|
|
70
|
|
|
|
|
84706
|
|
|
8
|
|
|
|
|
|
|
our $GMTIME = 0; |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
my @MONTH_NAMES = qw( |
|
11
|
|
|
|
|
|
|
January February March April May June July |
|
12
|
|
|
|
|
|
|
August September October November December); |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
my @WEEK_DAYS = qw( |
|
15
|
|
|
|
|
|
|
Sunday Monday Tuesday Wednesday Thursday Friday Saturday); |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
########################################### |
|
18
|
|
|
|
|
|
|
########################################### |
|
19
|
|
|
|
|
|
|
my($class, $format) = @_; |
|
20
|
|
|
|
|
|
|
|
|
21
|
78
|
|
|
78
|
0
|
5979
|
my $self = { |
|
22
|
|
|
|
|
|
|
stack => [], |
|
23
|
78
|
|
|
|
|
218
|
fmt => undef, |
|
24
|
|
|
|
|
|
|
}; |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
bless $self, $class; |
|
27
|
|
|
|
|
|
|
|
|
28
|
78
|
|
|
|
|
315
|
# Predefined formats |
|
29
|
|
|
|
|
|
|
if($format eq "ABSOLUTE") { |
|
30
|
|
|
|
|
|
|
$format = "HH:mm:ss,SSS"; |
|
31
|
78
|
100
|
|
|
|
334
|
} elsif($format eq "DATE") { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
32
|
1
|
|
|
|
|
2
|
$format = "dd MMM yyyy HH:mm:ss,SSS"; |
|
33
|
|
|
|
|
|
|
} elsif($format eq "ISO8601") { |
|
34
|
1
|
|
|
|
|
2
|
$format = "yyyy-MM-dd HH:mm:ss,SSS"; |
|
35
|
|
|
|
|
|
|
} elsif($format eq "APACHE") { |
|
36
|
1
|
|
|
|
|
2
|
$format = "[EEE MMM dd HH:mm:ss yyyy]"; |
|
37
|
|
|
|
|
|
|
} |
|
38
|
1
|
|
|
|
|
3
|
|
|
39
|
|
|
|
|
|
|
if($format) { |
|
40
|
|
|
|
|
|
|
$self->prepare($format); |
|
41
|
78
|
50
|
|
|
|
158
|
} |
|
42
|
78
|
|
|
|
|
163
|
|
|
43
|
|
|
|
|
|
|
return $self; |
|
44
|
|
|
|
|
|
|
} |
|
45
|
77
|
|
|
|
|
292
|
|
|
46
|
|
|
|
|
|
|
########################################### |
|
47
|
|
|
|
|
|
|
########################################### |
|
48
|
|
|
|
|
|
|
my($self, $format) = @_; |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# the actual DateTime spec allows for literal text delimited by |
|
51
|
78
|
|
|
78
|
0
|
160
|
# single quotes; a single quote can be embedded in the literal |
|
52
|
|
|
|
|
|
|
# text by using two single quotes. |
|
53
|
|
|
|
|
|
|
# |
|
54
|
|
|
|
|
|
|
# my strategy here is to split the format into active and literal |
|
55
|
|
|
|
|
|
|
# "chunks"; active chunks are prepared using $self->rep() as |
|
56
|
|
|
|
|
|
|
# before, while literal chunks get transformed to accommodate |
|
57
|
|
|
|
|
|
|
# single quotes and to protect percent signs. |
|
58
|
|
|
|
|
|
|
# |
|
59
|
|
|
|
|
|
|
# motivation: the "recommended" ISO-8601 date spec for a time in |
|
60
|
|
|
|
|
|
|
# UTC is actually: |
|
61
|
|
|
|
|
|
|
# |
|
62
|
|
|
|
|
|
|
# YYYY-mm-dd'T'hh:mm:ss.SSS'Z' |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
my $fmt = ""; |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
foreach my $chunk ( split /('(?:''|[^'])*')/, $format ) { |
|
67
|
78
|
|
|
|
|
106
|
if ( $chunk =~ /\A'(.*)'\z/ ) { |
|
68
|
|
|
|
|
|
|
# literal text |
|
69
|
78
|
|
|
|
|
266
|
my $literal = $1; |
|
70
|
94
|
100
|
|
|
|
288
|
$literal =~ s/''/'/g; |
|
|
|
100
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
$literal =~ s/\%/\%\%/g; |
|
72
|
9
|
|
|
|
|
19
|
$fmt .= $literal; |
|
73
|
9
|
|
|
|
|
16
|
} elsif ( $chunk =~ /'/ ) { |
|
74
|
9
|
|
|
|
|
12
|
# single quotes should always be in a literal |
|
75
|
9
|
|
|
|
|
17
|
croak "bad date format \"$format\": " . |
|
76
|
|
|
|
|
|
|
"unmatched single quote in chunk \"$chunk\""; |
|
77
|
|
|
|
|
|
|
} else { |
|
78
|
1
|
|
|
|
|
148
|
# handle active chunks just like before |
|
79
|
|
|
|
|
|
|
$chunk =~ s/(([GyMdhHmsSEeDFwWakKzZ])\2*)/$self->rep($1)/ge; |
|
80
|
|
|
|
|
|
|
$fmt .= $chunk; |
|
81
|
|
|
|
|
|
|
} |
|
82
|
84
|
|
|
|
|
386
|
} |
|
|
405
|
|
|
|
|
845
|
|
|
83
|
84
|
|
|
|
|
257
|
|
|
84
|
|
|
|
|
|
|
return $self->{fmt} = $fmt; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
77
|
|
|
|
|
206
|
########################################### |
|
88
|
|
|
|
|
|
|
########################################### |
|
89
|
|
|
|
|
|
|
my ($self, $string) = @_; |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
my $first = substr $string, 0, 1; |
|
92
|
|
|
|
|
|
|
my $len = length $string; |
|
93
|
405
|
|
|
405
|
0
|
975
|
|
|
94
|
|
|
|
|
|
|
my $time=time(); |
|
95
|
405
|
|
|
|
|
666
|
my @g = gmtime($time); |
|
96
|
405
|
|
|
|
|
499
|
my @t = localtime($time); |
|
97
|
|
|
|
|
|
|
my $z = $t[1]-$g[1]+($t[2]-$g[2])*60+($t[7]-$g[7])*1440+ |
|
98
|
405
|
|
|
|
|
464
|
($t[5]-$g[5])*(525600+(abs($t[7]-$g[7])>364)*1440); |
|
99
|
405
|
|
|
|
|
1266
|
my $offset = sprintf("%+.2d%.2d", $z/60, "00"); |
|
100
|
405
|
|
|
|
|
6053
|
|
|
101
|
405
|
|
|
|
|
1172
|
#my ($s,$mi,$h,$d,$mo,$y,$wd,$yd,$dst) = localtime($time); |
|
102
|
|
|
|
|
|
|
|
|
103
|
405
|
|
|
|
|
1245
|
# Here's how this works: |
|
104
|
|
|
|
|
|
|
# Detect what kind of parameter we're dealing with and determine |
|
105
|
|
|
|
|
|
|
# what type of sprintf-placeholder to return (%d, %02d, %s or whatever). |
|
106
|
|
|
|
|
|
|
# Then, we're setting up an array, specific to the current format, |
|
107
|
|
|
|
|
|
|
# that can be used later on to compute the components of the placeholders |
|
108
|
|
|
|
|
|
|
# one by one when we get the components of the current time later on |
|
109
|
|
|
|
|
|
|
# via localtime. |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# So, we're parsing the "yyyy/MM" format once, replace it by, say |
|
112
|
|
|
|
|
|
|
# "%04d:%02d" and store an array that says "for the first placeholder, |
|
113
|
|
|
|
|
|
|
# get the localtime-parameter on index #5 (which is years since the |
|
114
|
|
|
|
|
|
|
# epoch), add 1900 to it and pass it on to sprintf(). For the 2nd |
|
115
|
|
|
|
|
|
|
# placeholder, get the localtime component at index #2 (which is hours) |
|
116
|
|
|
|
|
|
|
# and pass it on unmodified to sprintf. |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
# So, the array to compute the time format at logtime contains |
|
119
|
|
|
|
|
|
|
# as many elements as the original SimpleDateFormat contained. Each |
|
120
|
|
|
|
|
|
|
# entry is a array ref, holding an array with 2 elements: The index |
|
121
|
|
|
|
|
|
|
# into the localtime to obtain the value and a reference to a subroutine |
|
122
|
|
|
|
|
|
|
# to do computations eventually. The subroutine expects the original |
|
123
|
|
|
|
|
|
|
# localtime() time component (like year since the epoch) and returns |
|
124
|
|
|
|
|
|
|
# the desired value for sprintf (like y+1900). |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# This way, we're parsing the original format only once (during system |
|
127
|
|
|
|
|
|
|
# startup) and during runtime all we do is call localtime *once* and |
|
128
|
|
|
|
|
|
|
# run a number of blazingly fast computations, according to the number |
|
129
|
|
|
|
|
|
|
# of placeholders in the format. |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
########### |
|
132
|
|
|
|
|
|
|
#G - epoch# |
|
133
|
|
|
|
|
|
|
########### |
|
134
|
|
|
|
|
|
|
if($first eq "G") { |
|
135
|
|
|
|
|
|
|
# Always constant |
|
136
|
|
|
|
|
|
|
return "AD"; |
|
137
|
|
|
|
|
|
|
|
|
138
|
405
|
50
|
|
|
|
1775
|
################### |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
#e - epoch seconds# |
|
140
|
0
|
|
|
|
|
0
|
################### |
|
141
|
|
|
|
|
|
|
} elsif($first eq "e") { |
|
142
|
|
|
|
|
|
|
# index (0) irrelevant, but we return time() which |
|
143
|
|
|
|
|
|
|
# comes in as 2nd parameter |
|
144
|
|
|
|
|
|
|
push @{$self->{stack}}, [0, sub { return $_[1] }]; |
|
145
|
|
|
|
|
|
|
return "%d"; |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
########## |
|
148
|
1
|
|
|
1
|
|
2
|
#y - year# |
|
|
1
|
|
|
|
|
5
|
|
|
|
1
|
|
|
|
|
2
|
|
|
149
|
1
|
|
|
|
|
5
|
########## |
|
150
|
|
|
|
|
|
|
} elsif($first eq "y") { |
|
151
|
|
|
|
|
|
|
if($len >= 4) { |
|
152
|
|
|
|
|
|
|
# 4-digit year |
|
153
|
|
|
|
|
|
|
push @{$self->{stack}}, [5, sub { return $_[0] + 1900 }]; |
|
154
|
|
|
|
|
|
|
return "%04d"; |
|
155
|
61
|
100
|
|
|
|
188
|
} else { |
|
156
|
|
|
|
|
|
|
# 2-digit year |
|
157
|
60
|
|
|
115
|
|
150
|
push @{$self->{stack}}, [5, sub { $_[0] % 100 }]; |
|
|
60
|
|
|
|
|
390
|
|
|
|
115
|
|
|
|
|
354
|
|
|
158
|
60
|
|
|
|
|
357
|
return "%02d"; |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
|
|
161
|
1
|
|
|
1
|
|
2
|
########### |
|
|
1
|
|
|
|
|
5
|
|
|
|
1
|
|
|
|
|
3
|
|
|
162
|
1
|
|
|
|
|
7
|
#M - month# |
|
163
|
|
|
|
|
|
|
########### |
|
164
|
|
|
|
|
|
|
} elsif($first eq "M") { |
|
165
|
|
|
|
|
|
|
if($len >= 3) { |
|
166
|
|
|
|
|
|
|
# Use month name |
|
167
|
|
|
|
|
|
|
push @{$self->{stack}}, [4, sub { return $MONTH_NAMES[$_[0]] }]; |
|
168
|
|
|
|
|
|
|
if($len >= 4) { |
|
169
|
59
|
100
|
|
|
|
161
|
return "%s"; |
|
|
|
100
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
} else { |
|
171
|
5
|
|
|
4
|
|
6
|
return "%.3s"; |
|
|
5
|
|
|
|
|
23
|
|
|
|
4
|
|
|
|
|
9
|
|
|
172
|
5
|
100
|
|
|
|
11
|
} |
|
173
|
1
|
|
|
|
|
5
|
} elsif($len == 2) { |
|
174
|
|
|
|
|
|
|
# Use zero-padded month number |
|
175
|
4
|
|
|
|
|
21
|
push @{$self->{stack}}, [4, sub { $_[0]+1 }]; |
|
176
|
|
|
|
|
|
|
return "%02d"; |
|
177
|
|
|
|
|
|
|
} else { |
|
178
|
|
|
|
|
|
|
# Use zero-padded month number |
|
179
|
53
|
|
|
109
|
|
79
|
push @{$self->{stack}}, [4, sub { $_[0]+1 }]; |
|
|
53
|
|
|
|
|
269
|
|
|
|
109
|
|
|
|
|
200
|
|
|
180
|
53
|
|
|
|
|
311
|
return "%d"; |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
|
|
183
|
1
|
|
|
1
|
|
2
|
################## |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
2
|
|
|
184
|
1
|
|
|
|
|
6
|
#d - day of month# |
|
185
|
|
|
|
|
|
|
################## |
|
186
|
|
|
|
|
|
|
} elsif($first eq "d") { |
|
187
|
|
|
|
|
|
|
push @{$self->{stack}}, [3, sub { return $_[0] }]; |
|
188
|
|
|
|
|
|
|
return "%0" . $len . "d"; |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
################## |
|
191
|
58
|
|
|
113
|
|
91
|
#h - am/pm hour# |
|
|
58
|
|
|
|
|
274
|
|
|
|
113
|
|
|
|
|
167
|
|
|
192
|
58
|
|
|
|
|
434
|
################## |
|
193
|
|
|
|
|
|
|
} elsif($first eq "h") { |
|
194
|
|
|
|
|
|
|
push @{$self->{stack}}, [2, sub { ($_[0] % 12) || 12 }]; |
|
195
|
|
|
|
|
|
|
return "%0" . $len . "d"; |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
################## |
|
198
|
6
|
50
|
|
4
|
|
10
|
#H - 24 hour# |
|
|
6
|
|
|
|
|
26
|
|
|
|
4
|
|
|
|
|
11
|
|
|
199
|
6
|
|
|
|
|
35
|
################## |
|
200
|
|
|
|
|
|
|
} elsif($first eq "H") { |
|
201
|
|
|
|
|
|
|
push @{$self->{stack}}, [2, sub { return $_[0] }]; |
|
202
|
|
|
|
|
|
|
return "%0" . $len . "d"; |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
################## |
|
205
|
63
|
|
|
115
|
|
84
|
#m - minute# |
|
|
63
|
|
|
|
|
309
|
|
|
|
115
|
|
|
|
|
164
|
|
|
206
|
63
|
|
|
|
|
367
|
################## |
|
207
|
|
|
|
|
|
|
} elsif($first eq "m") { |
|
208
|
|
|
|
|
|
|
push @{$self->{stack}}, [1, sub { return $_[0] }]; |
|
209
|
|
|
|
|
|
|
return "%0" . $len . "d"; |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
################## |
|
212
|
63
|
|
|
115
|
|
85
|
#s - second# |
|
|
63
|
|
|
|
|
312
|
|
|
|
115
|
|
|
|
|
178
|
|
|
213
|
63
|
|
|
|
|
390
|
################## |
|
214
|
|
|
|
|
|
|
} elsif($first eq "s") { |
|
215
|
|
|
|
|
|
|
push @{$self->{stack}}, [0, sub { return $_[0] }]; |
|
216
|
|
|
|
|
|
|
return "%0" . $len . "d"; |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
################## |
|
219
|
63
|
|
|
115
|
|
83
|
#E - day of week # |
|
|
63
|
|
|
|
|
324
|
|
|
|
115
|
|
|
|
|
209
|
|
|
220
|
63
|
|
|
|
|
310
|
################## |
|
221
|
|
|
|
|
|
|
} elsif($first eq "E") { |
|
222
|
|
|
|
|
|
|
push @{$self->{stack}}, [6, sub { $WEEK_DAYS[$_[0]] }]; |
|
223
|
|
|
|
|
|
|
if($len >= 4) { |
|
224
|
|
|
|
|
|
|
return "%${len}s"; |
|
225
|
|
|
|
|
|
|
} else { |
|
226
|
5
|
|
|
29
|
|
5
|
return "%.3s"; |
|
|
5
|
|
|
|
|
22
|
|
|
|
29
|
|
|
|
|
45
|
|
|
227
|
5
|
100
|
|
|
|
9
|
} |
|
228
|
1
|
|
|
|
|
6
|
|
|
229
|
|
|
|
|
|
|
###################### |
|
230
|
4
|
|
|
|
|
21
|
#D - day of the year # |
|
231
|
|
|
|
|
|
|
###################### |
|
232
|
|
|
|
|
|
|
} elsif($first eq "D") { |
|
233
|
|
|
|
|
|
|
push @{$self->{stack}}, [7, sub { $_[0] + 1}]; |
|
234
|
|
|
|
|
|
|
return "%0" . $len . "d"; |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
###################### |
|
237
|
6
|
|
|
6
|
|
9
|
#a - am/pm marker # |
|
|
6
|
|
|
|
|
26
|
|
|
|
6
|
|
|
|
|
10
|
|
|
238
|
6
|
|
|
|
|
33
|
###################### |
|
239
|
|
|
|
|
|
|
} elsif($first eq "a") { |
|
240
|
|
|
|
|
|
|
push @{$self->{stack}}, [2, sub { $_[0] < 12 ? "AM" : "PM" }]; |
|
241
|
|
|
|
|
|
|
return "%${len}s"; |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
###################### |
|
244
|
3
|
50
|
|
2
|
|
5
|
#S - milliseconds # |
|
|
3
|
|
|
|
|
15
|
|
|
|
2
|
|
|
|
|
7
|
|
|
245
|
3
|
|
|
|
|
16
|
###################### |
|
246
|
|
|
|
|
|
|
} elsif($first eq "S") { |
|
247
|
|
|
|
|
|
|
push @{$self->{stack}}, |
|
248
|
|
|
|
|
|
|
[9, sub { substr sprintf("%06d", $_[0]), 0, $len }]; |
|
249
|
|
|
|
|
|
|
return "%s"; |
|
250
|
|
|
|
|
|
|
|
|
251
|
16
|
|
|
|
|
65
|
############################### |
|
252
|
16
|
|
|
9
|
|
19
|
#Z - RFC 822 time zone -0800 # |
|
|
9
|
|
|
|
|
25
|
|
|
253
|
16
|
|
|
|
|
66
|
############################### |
|
254
|
|
|
|
|
|
|
} elsif($first eq "Z") { |
|
255
|
|
|
|
|
|
|
push @{$self->{stack}}, [10, sub { $offset }]; |
|
256
|
|
|
|
|
|
|
return "%s"; |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
############################# |
|
259
|
0
|
|
|
0
|
|
0
|
#Something that's not defined |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
260
|
0
|
|
|
|
|
0
|
#(F=day of week in month |
|
261
|
|
|
|
|
|
|
# w=week in year W=week in month |
|
262
|
|
|
|
|
|
|
# k=hour in day K=hour in am/pm |
|
263
|
|
|
|
|
|
|
# z=timezone |
|
264
|
|
|
|
|
|
|
############################# |
|
265
|
|
|
|
|
|
|
} else { |
|
266
|
|
|
|
|
|
|
return "-- '$first' not (yet) implemented --"; |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
return $string; |
|
270
|
1
|
|
|
|
|
6
|
} |
|
271
|
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
########################################### |
|
273
|
0
|
|
|
|
|
0
|
########################################### |
|
274
|
|
|
|
|
|
|
my($self, $secs, $msecs) = @_; |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
$msecs = 0 unless defined $msecs; |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
my @time; |
|
279
|
134
|
|
|
134
|
0
|
287
|
|
|
280
|
|
|
|
|
|
|
if($GMTIME) { |
|
281
|
134
|
100
|
|
|
|
261
|
@time = gmtime($secs); |
|
282
|
|
|
|
|
|
|
} else { |
|
283
|
134
|
|
|
|
|
162
|
@time = localtime($secs); |
|
284
|
|
|
|
|
|
|
} |
|
285
|
134
|
100
|
|
|
|
243
|
|
|
286
|
26
|
|
|
|
|
83
|
# add milliseconds |
|
287
|
|
|
|
|
|
|
push @time, $msecs; |
|
288
|
108
|
|
|
|
|
2254
|
|
|
289
|
|
|
|
|
|
|
my @values = (); |
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
for(@{$self->{stack}}) { |
|
292
|
134
|
|
|
|
|
321
|
my($val, $code) = @$_; |
|
293
|
|
|
|
|
|
|
if($code) { |
|
294
|
134
|
|
|
|
|
181
|
push @values, $code->($time[$val], $secs); |
|
295
|
|
|
|
|
|
|
} else { |
|
296
|
134
|
|
|
|
|
168
|
push @values, $time[$val]; |
|
|
134
|
|
|
|
|
344
|
|
|
297
|
739
|
|
|
|
|
976
|
} |
|
298
|
739
|
50
|
|
|
|
1056
|
} |
|
299
|
739
|
|
|
|
|
1137
|
|
|
300
|
|
|
|
|
|
|
return sprintf($self->{fmt}, @values); |
|
301
|
0
|
|
|
|
|
0
|
} |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
1; |
|
304
|
|
|
|
|
|
|
|
|
305
|
134
|
|
|
|
|
889
|
|
|
306
|
|
|
|
|
|
|
=encoding utf8 |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=head1 NAME |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
Log::Log4perl::DateFormat - Log4perl advanced date formatter helper class |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
# Either in a log4j.conf file ... |
|
316
|
|
|
|
|
|
|
log4perl.appender.Logfile.layout = \ |
|
317
|
|
|
|
|
|
|
Log::Log4perl::Layout::PatternLayout |
|
318
|
|
|
|
|
|
|
log4perl.appender.Logfile.layout.ConversionPattern = %d{MM/dd HH:mm} %m |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
# ... or via the PatternLayout class ... |
|
321
|
|
|
|
|
|
|
use Log::Log4perl::Layout::PatternLayout; |
|
322
|
|
|
|
|
|
|
my $layout = Log::Log4perl::Layout::PatternLayout->new( |
|
323
|
|
|
|
|
|
|
"%d{HH:mm:ss,SSS} %m"); |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# ... or even directly with this helper class: |
|
326
|
|
|
|
|
|
|
use Log::Log4perl::DateFormat; |
|
327
|
|
|
|
|
|
|
my $format = Log::Log4perl::DateFormat->new("HH:mm:ss,SSS"); |
|
328
|
|
|
|
|
|
|
my $time = time(); |
|
329
|
|
|
|
|
|
|
print $format->format($time), "\n"; |
|
330
|
|
|
|
|
|
|
# => "17:02:39,000" |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
C<Log::Log4perl::DateFormat> is a helper class for the |
|
335
|
|
|
|
|
|
|
advanced date formatting functions in C<Log::Log4perl::Layout::PatternLayout>, |
|
336
|
|
|
|
|
|
|
and adheres (mostly) to the log4j SimpleDateFormat spec available on |
|
337
|
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
http://download.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html |
|
339
|
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
It supports the following placeholders: |
|
341
|
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
Symbol Meaning Presentation Example |
|
343
|
|
|
|
|
|
|
------ ------- ------------ ------- |
|
344
|
|
|
|
|
|
|
G era designator (Text) AD |
|
345
|
|
|
|
|
|
|
e epoch seconds (Number) 1315011604 |
|
346
|
|
|
|
|
|
|
y year (Number) 1996 |
|
347
|
|
|
|
|
|
|
M month in year (Text & Number) July & 07 |
|
348
|
|
|
|
|
|
|
d day in month (Number) 10 |
|
349
|
|
|
|
|
|
|
h hour in am/pm (1~12) (Number) 12 |
|
350
|
|
|
|
|
|
|
H hour in day (0~23) (Number) 0 |
|
351
|
|
|
|
|
|
|
m minute in hour (Number) 30 |
|
352
|
|
|
|
|
|
|
s second in minute (Number) 55 |
|
353
|
|
|
|
|
|
|
S millisecond (Number) 978 |
|
354
|
|
|
|
|
|
|
E day in week (Text) Tuesday |
|
355
|
|
|
|
|
|
|
D day in year (Number) 189 |
|
356
|
|
|
|
|
|
|
F day of week in month (Number) 2 (2nd Wed in July) |
|
357
|
|
|
|
|
|
|
w week in year (Number) 27 |
|
358
|
|
|
|
|
|
|
W week in month (Number) 2 |
|
359
|
|
|
|
|
|
|
a am/pm marker (Text) PM |
|
360
|
|
|
|
|
|
|
k hour in day (1~24) (Number) 24 |
|
361
|
|
|
|
|
|
|
K hour in am/pm (0~11) (Number) 0 |
|
362
|
|
|
|
|
|
|
z time zone (Text) Pacific Standard Time |
|
363
|
|
|
|
|
|
|
Z RFC 822 time zone (Text) -0800 |
|
364
|
|
|
|
|
|
|
' escape for text (Delimiter) |
|
365
|
|
|
|
|
|
|
'' single quote (Literal) ' |
|
366
|
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
Presentation explanation: |
|
368
|
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
(Text): 4 or more pattern letters--use full form, < 4--use short or |
|
370
|
|
|
|
|
|
|
abbreviated form if one exists. |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
(Number): the minimum number of digits. Shorter numbers are |
|
373
|
|
|
|
|
|
|
zero-padded to this amount. Year is handled |
|
374
|
|
|
|
|
|
|
specially; that is, if the count of 'y' is 2, the |
|
375
|
|
|
|
|
|
|
Year will be truncated to 2 digits. |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
(Text & Number): 3 or over, use text, otherwise use number. |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
For example, if you want to format the current Unix time in C<"MM/dd HH:mm"> |
|
380
|
|
|
|
|
|
|
format, all you have to do is specify it in the %d{...} section of the |
|
381
|
|
|
|
|
|
|
PatternLayout in a Log4perl configuration file: |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
# log4j.conf |
|
384
|
|
|
|
|
|
|
# ... |
|
385
|
|
|
|
|
|
|
log4perl.appender.Logfile.layout = \ |
|
386
|
|
|
|
|
|
|
Log::Log4perl::Layout::PatternLayout |
|
387
|
|
|
|
|
|
|
log4perl.appender.Logfile.layout.ConversionPattern = %d{MM/dd HH:mm} %m |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
Same goes for Perl code defining a PatternLayout for Log4perl: |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
use Log::Log4perl::Layout::PatternLayout; |
|
392
|
|
|
|
|
|
|
my $layout = Log::Log4perl::Layout::PatternLayout->new( |
|
393
|
|
|
|
|
|
|
"%d{MM/dd HH:mm} %m"); |
|
394
|
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
Or, on a lower level, you can use the class directly: |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
use Log::Log4perl::DateFormat; |
|
398
|
|
|
|
|
|
|
my $format = Log::Log4perl::DateFormat->new("MM/dd HH:mm"); |
|
399
|
|
|
|
|
|
|
my $time = time(); |
|
400
|
|
|
|
|
|
|
print $format->format($time), "\n"; |
|
401
|
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
While the C<new()> method is expensive, because it parses the format |
|
403
|
|
|
|
|
|
|
strings and sets up all kinds of structures behind the scenes, |
|
404
|
|
|
|
|
|
|
followup calls to C<format()> are fast, because C<DateFormat> will |
|
405
|
|
|
|
|
|
|
just call C<localtime()> and C<sprintf()> once to return the formatted |
|
406
|
|
|
|
|
|
|
date/time string. |
|
407
|
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
So, typically, you would initialize the formatter once and then reuse |
|
409
|
|
|
|
|
|
|
it over and over again to display all kinds of time values. |
|
410
|
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
Also, for your convenience, |
|
412
|
|
|
|
|
|
|
the following predefined formats are available, just as outlined in the |
|
413
|
|
|
|
|
|
|
log4j spec: |
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
Format Equivalent Example |
|
416
|
|
|
|
|
|
|
ABSOLUTE "HH:mm:ss,SSS" "15:49:37,459" |
|
417
|
|
|
|
|
|
|
DATE "dd MMM yyyy HH:mm:ss,SSS" "06 Nov 1994 15:49:37,459" |
|
418
|
|
|
|
|
|
|
ISO8601 "yyyy-MM-dd HH:mm:ss,SSS" "1999-11-27 15:49:37,459" |
|
419
|
|
|
|
|
|
|
APACHE "[EEE MMM dd HH:mm:ss yyyy]" "[Wed Mar 16 15:49:37 2005]" |
|
420
|
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
So, instead of passing |
|
422
|
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
Log::Log4perl::DateFormat->new("HH:mm:ss,SSS"); |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
you could just as well say |
|
426
|
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
Log::Log4perl::DateFormat->new("ABSOLUTE"); |
|
428
|
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
and get the same result later on. |
|
430
|
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=head2 Known Shortcomings |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
The following placeholders are currently I<not> recognized, unless |
|
434
|
|
|
|
|
|
|
someone (and that could be you :) implements them: |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
F day of week in month |
|
437
|
|
|
|
|
|
|
w week in year |
|
438
|
|
|
|
|
|
|
W week in month |
|
439
|
|
|
|
|
|
|
k hour in day |
|
440
|
|
|
|
|
|
|
K hour in am/pm |
|
441
|
|
|
|
|
|
|
z timezone (but we got 'Z' for the numeric time zone value) |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
Also, C<Log::Log4perl::DateFormat> just knows about English week and |
|
444
|
|
|
|
|
|
|
month names, internationalization support has to be added. |
|
445
|
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=head1 Millisecond Times |
|
447
|
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
More granular timestamps down to the millisecond are also supported, |
|
449
|
|
|
|
|
|
|
just provide the millsecond count as a second argument: |
|
450
|
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
# Advanced time, resultion in milliseconds |
|
452
|
|
|
|
|
|
|
use Time::HiRes; |
|
453
|
|
|
|
|
|
|
my ($secs, $msecs) = Time::HiRes::gettimeofday(); |
|
454
|
|
|
|
|
|
|
print $format->format($secs, $msecs), "\n"; |
|
455
|
|
|
|
|
|
|
# => "17:02:39,959" |
|
456
|
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=head1 LICENSE |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
Copyright 2002-2016 by Mike Schilli E<lt>m@perlmeister.comE<gt> |
|
460
|
|
|
|
|
|
|
and Kevin Goess E<lt>cpan@goess.orgE<gt>. |
|
461
|
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
|
463
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=head1 AUTHOR |
|
466
|
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
Please contribute patches to the project on Github: |
|
468
|
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
http://github.com/mschilli/log4perl |
|
470
|
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
Send bug reports or requests for enhancements to the authors via our |
|
472
|
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
MAILING LIST (questions, bug reports, suggestions/patches): |
|
474
|
|
|
|
|
|
|
log4perl-devel@lists.sourceforge.net |
|
475
|
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
Authors (please contact them via the list above, not directly): |
|
477
|
|
|
|
|
|
|
Mike Schilli <m@perlmeister.com>, |
|
478
|
|
|
|
|
|
|
Kevin Goess <cpan@goess.org> |
|
479
|
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
Contributors (in alphabetical order): |
|
481
|
|
|
|
|
|
|
Ateeq Altaf, Cory Bennett, Jens Berthold, Jeremy Bopp, Hutton |
|
482
|
|
|
|
|
|
|
Davidson, Chris R. Donnelly, Matisse Enzer, Hugh Esco, Anthony |
|
483
|
|
|
|
|
|
|
Foiani, James FitzGibbon, Carl Franks, Dennis Gregorovic, Andy |
|
484
|
|
|
|
|
|
|
Grundman, Paul Harrington, Alexander Hartmaier David Hull, |
|
485
|
|
|
|
|
|
|
Robert Jacobson, Jason Kohles, Jeff Macdonald, Markus Peter, |
|
486
|
|
|
|
|
|
|
Brett Rann, Peter Rabbitson, Erik Selberg, Aaron Straup Cope, |
|
487
|
|
|
|
|
|
|
Lars Thegler, David Viner, Mac Yang. |
|
488
|
|
|
|
|
|
|
|