line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
########################################### |
2
|
|
|
|
|
|
|
########################################### |
3
|
|
|
|
|
|
|
use warnings; |
4
|
70
|
|
|
70
|
|
493
|
use strict; |
|
70
|
|
|
|
|
186
|
|
|
70
|
|
|
|
|
2331
|
|
5
|
70
|
|
|
70
|
|
389
|
|
|
70
|
|
|
|
|
163
|
|
|
70
|
|
|
|
|
1615
|
|
6
|
|
|
|
|
|
|
use Carp qw( croak ); |
7
|
70
|
|
|
70
|
|
342
|
|
|
70
|
|
|
|
|
144
|
|
|
70
|
|
|
|
|
113321
|
|
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
|
7371
|
my $self = { |
22
|
|
|
|
|
|
|
stack => [], |
23
|
78
|
|
|
|
|
311
|
fmt => undef, |
24
|
|
|
|
|
|
|
}; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
bless $self, $class; |
27
|
|
|
|
|
|
|
|
28
|
78
|
|
|
|
|
322
|
# Predefined formats |
29
|
|
|
|
|
|
|
if($format eq "ABSOLUTE") { |
30
|
|
|
|
|
|
|
$format = "HH:mm:ss,SSS"; |
31
|
78
|
100
|
|
|
|
363
|
} elsif($format eq "DATE") { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
32
|
1
|
|
|
|
|
3
|
$format = "dd MMM yyyy HH:mm:ss,SSS"; |
33
|
|
|
|
|
|
|
} elsif($format eq "ISO8601") { |
34
|
1
|
|
|
|
|
3
|
$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
|
|
|
|
182
|
} |
42
|
78
|
|
|
|
|
211
|
|
43
|
|
|
|
|
|
|
return $self; |
44
|
|
|
|
|
|
|
} |
45
|
77
|
|
|
|
|
366
|
|
46
|
|
|
|
|
|
|
########################################### |
47
|
|
|
|
|
|
|
########################################### |
48
|
|
|
|
|
|
|
my($self, $format) = @_; |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# the actual DateTime spec allows for literal text delimited by |
51
|
78
|
|
|
78
|
0
|
172
|
# 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
|
|
|
|
|
138
|
if ( $chunk =~ /\A'(.*)'\z/ ) { |
68
|
|
|
|
|
|
|
# literal text |
69
|
78
|
|
|
|
|
328
|
my $literal = $1; |
70
|
94
|
100
|
|
|
|
354
|
$literal =~ s/''/'/g; |
|
|
100
|
|
|
|
|
|
71
|
|
|
|
|
|
|
$literal =~ s/\%/\%\%/g; |
72
|
9
|
|
|
|
|
22
|
$fmt .= $literal; |
73
|
9
|
|
|
|
|
24
|
} elsif ( $chunk =~ /'/ ) { |
74
|
9
|
|
|
|
|
14
|
# 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
|
|
|
|
|
198
|
# handle active chunks just like before |
79
|
|
|
|
|
|
|
$chunk =~ s/(([GyMdhHmsSEeDFwWakKzZ])\2*)/$self->rep($1)/ge; |
80
|
|
|
|
|
|
|
$fmt .= $chunk; |
81
|
|
|
|
|
|
|
} |
82
|
84
|
|
|
|
|
514
|
} |
|
405
|
|
|
|
|
1105
|
|
83
|
84
|
|
|
|
|
384
|
|
84
|
|
|
|
|
|
|
return $self->{fmt} = $fmt; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
77
|
|
|
|
|
267
|
########################################### |
88
|
|
|
|
|
|
|
########################################### |
89
|
|
|
|
|
|
|
my ($self, $string) = @_; |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
my $first = substr $string, 0, 1; |
92
|
|
|
|
|
|
|
my $len = length $string; |
93
|
405
|
|
|
405
|
0
|
1282
|
|
94
|
|
|
|
|
|
|
my $time=time(); |
95
|
405
|
|
|
|
|
855
|
my @g = gmtime($time); |
96
|
405
|
|
|
|
|
631
|
my @t = localtime($time); |
97
|
|
|
|
|
|
|
my $z = $t[1]-$g[1]+($t[2]-$g[2])*60+($t[7]-$g[7])*1440+ |
98
|
405
|
|
|
|
|
591
|
($t[5]-$g[5])*(525600+(abs($t[7]-$g[7])>364)*1440); |
99
|
405
|
|
|
|
|
1530
|
my $offset = sprintf("%+.2d%.2d", $z/60, "00"); |
100
|
405
|
|
|
|
|
7906
|
|
101
|
405
|
|
|
|
|
1523
|
#my ($s,$mi,$h,$d,$mo,$y,$wd,$yd,$dst) = localtime($time); |
102
|
|
|
|
|
|
|
|
103
|
405
|
|
|
|
|
1604
|
# 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
|
|
|
|
2346
|
################### |
|
|
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
|
|
3
|
#y - year# |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
3
|
|
149
|
1
|
|
|
|
|
7
|
########## |
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
|
|
|
|
231
|
} else { |
156
|
|
|
|
|
|
|
# 2-digit year |
157
|
60
|
|
|
115
|
|
167
|
push @{$self->{stack}}, [5, sub { $_[0] % 100 }]; |
|
60
|
|
|
|
|
452
|
|
|
115
|
|
|
|
|
405
|
|
158
|
60
|
|
|
|
|
499
|
return "%02d"; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
1
|
|
|
1
|
|
3
|
########### |
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
6
|
|
162
|
1
|
|
|
|
|
8
|
#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
|
|
|
|
214
|
return "%s"; |
|
|
100
|
|
|
|
|
|
170
|
|
|
|
|
|
|
} else { |
171
|
5
|
|
|
4
|
|
8
|
return "%.3s"; |
|
5
|
|
|
|
|
27
|
|
|
4
|
|
|
|
|
11
|
|
172
|
5
|
100
|
|
|
|
42
|
} |
173
|
1
|
|
|
|
|
8
|
} elsif($len == 2) { |
174
|
|
|
|
|
|
|
# Use zero-padded month number |
175
|
4
|
|
|
|
|
47
|
push @{$self->{stack}}, [4, sub { $_[0]+1 }]; |
176
|
|
|
|
|
|
|
return "%02d"; |
177
|
|
|
|
|
|
|
} else { |
178
|
|
|
|
|
|
|
# Use zero-padded month number |
179
|
53
|
|
|
109
|
|
93
|
push @{$self->{stack}}, [4, sub { $_[0]+1 }]; |
|
53
|
|
|
|
|
391
|
|
|
109
|
|
|
|
|
259
|
|
180
|
53
|
|
|
|
|
386
|
return "%d"; |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
1
|
|
|
1
|
|
2
|
################## |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
3
|
|
184
|
1
|
|
|
|
|
8
|
#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
|
|
106
|
#h - am/pm hour# |
|
58
|
|
|
|
|
372
|
|
|
113
|
|
|
|
|
238
|
|
192
|
58
|
|
|
|
|
469
|
################## |
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
|
|
9
|
#H - 24 hour# |
|
6
|
|
|
|
|
37
|
|
|
4
|
|
|
|
|
14
|
|
199
|
6
|
|
|
|
|
43
|
################## |
200
|
|
|
|
|
|
|
} elsif($first eq "H") { |
201
|
|
|
|
|
|
|
push @{$self->{stack}}, [2, sub { return $_[0] }]; |
202
|
|
|
|
|
|
|
return "%0" . $len . "d"; |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
################## |
205
|
63
|
|
|
115
|
|
121
|
#m - minute# |
|
63
|
|
|
|
|
402
|
|
|
115
|
|
|
|
|
226
|
|
206
|
63
|
|
|
|
|
472
|
################## |
207
|
|
|
|
|
|
|
} elsif($first eq "m") { |
208
|
|
|
|
|
|
|
push @{$self->{stack}}, [1, sub { return $_[0] }]; |
209
|
|
|
|
|
|
|
return "%0" . $len . "d"; |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
################## |
212
|
63
|
|
|
115
|
|
100
|
#s - second# |
|
63
|
|
|
|
|
418
|
|
|
115
|
|
|
|
|
238
|
|
213
|
63
|
|
|
|
|
487
|
################## |
214
|
|
|
|
|
|
|
} elsif($first eq "s") { |
215
|
|
|
|
|
|
|
push @{$self->{stack}}, [0, sub { return $_[0] }]; |
216
|
|
|
|
|
|
|
return "%0" . $len . "d"; |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
################## |
219
|
63
|
|
|
115
|
|
106
|
#E - day of week # |
|
63
|
|
|
|
|
381
|
|
|
115
|
|
|
|
|
262
|
|
220
|
63
|
|
|
|
|
392
|
################## |
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
|
|
9
|
return "%.3s"; |
|
5
|
|
|
|
|
27
|
|
|
29
|
|
|
|
|
60
|
|
227
|
5
|
100
|
|
|
|
14
|
} |
228
|
1
|
|
|
|
|
9
|
|
229
|
|
|
|
|
|
|
###################### |
230
|
4
|
|
|
|
|
27
|
#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
|
|
11
|
#a - am/pm marker # |
|
6
|
|
|
|
|
35
|
|
|
6
|
|
|
|
|
15
|
|
238
|
6
|
|
|
|
|
41
|
###################### |
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
|
|
|
|
|
18
|
|
|
2
|
|
|
|
|
7
|
|
245
|
3
|
|
|
|
|
21
|
###################### |
246
|
|
|
|
|
|
|
} elsif($first eq "S") { |
247
|
|
|
|
|
|
|
push @{$self->{stack}}, |
248
|
|
|
|
|
|
|
[9, sub { substr sprintf("%06d", $_[0]), 0, $len }]; |
249
|
|
|
|
|
|
|
return "%s"; |
250
|
|
|
|
|
|
|
|
251
|
16
|
|
|
|
|
85
|
############################### |
252
|
16
|
|
|
9
|
|
28
|
#Z - RFC 822 time zone -0800 # |
|
9
|
|
|
|
|
37
|
|
253
|
16
|
|
|
|
|
87
|
############################### |
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
|
|
|
|
|
8
|
} |
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
|
381
|
|
280
|
|
|
|
|
|
|
if($GMTIME) { |
281
|
134
|
100
|
|
|
|
309
|
@time = gmtime($secs); |
282
|
|
|
|
|
|
|
} else { |
283
|
134
|
|
|
|
|
219
|
@time = localtime($secs); |
284
|
|
|
|
|
|
|
} |
285
|
134
|
100
|
|
|
|
309
|
|
286
|
26
|
|
|
|
|
100
|
# add milliseconds |
287
|
|
|
|
|
|
|
push @time, $msecs; |
288
|
108
|
|
|
|
|
2716
|
|
289
|
|
|
|
|
|
|
my @values = (); |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
for(@{$self->{stack}}) { |
292
|
134
|
|
|
|
|
425
|
my($val, $code) = @$_; |
293
|
|
|
|
|
|
|
if($code) { |
294
|
134
|
|
|
|
|
234
|
push @values, $code->($time[$val], $secs); |
295
|
|
|
|
|
|
|
} else { |
296
|
134
|
|
|
|
|
217
|
push @values, $time[$val]; |
|
134
|
|
|
|
|
390
|
|
297
|
739
|
|
|
|
|
1283
|
} |
298
|
739
|
50
|
|
|
|
1374
|
} |
299
|
739
|
|
|
|
|
1404
|
|
300
|
|
|
|
|
|
|
return sprintf($self->{fmt}, @values); |
301
|
0
|
|
|
|
|
0
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
1; |
304
|
|
|
|
|
|
|
|
305
|
134
|
|
|
|
|
1021
|
|
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
|
|
|
|
|
|
|
|