Skip to content

Commit 4ec6c39

Browse files
committed
implemented @ppkarwasz & @vy chamges regarding FixedDateFormat.FixedFormat
1 parent 890ba62 commit 4ec6c39

File tree

5 files changed

+115
-119
lines changed

5 files changed

+115
-119
lines changed

log4j-core-test/src/test/java/org/apache/logging/log4j/core/pattern/DatePatternConverterTestBase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ void testNewInstanceAllowsNullParameter() {
331331
}
332332

333333
private static final String[] PATTERN_NAMES =
334-
Stream.of(NamedDatePattern.values()).map(Enum::name).toArray(String[]::new);
334+
Stream.of(NamedInstantPattern.values()).map(Enum::name).toArray(String[]::new);
335335

336336
@Test
337337
void testPredefinedFormatWithoutTimezone() {

log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/DatePatternConverter.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ private static InstantFormatter createFormatter(@Nullable final String[] options
6363
logOptionReadFailure(options, error, "failed for options: {}, falling back to the default instance");
6464
}
6565
return InstantPatternFormatter.newBuilder()
66-
.setPattern(NamedDatePattern.DEFAULT.getPattern())
66+
.setPattern(NamedInstantPattern.DEFAULT.getPattern())
6767
.build();
6868
}
6969

@@ -94,7 +94,7 @@ private static InstantFormatter createFormatterUnsafely(@Nullable final String[]
9494
private static String readPattern(@Nullable final String[] options) {
9595
return options != null && options.length > 0 && options[0] != null
9696
? decodeNamedPattern(options[0])
97-
: NamedDatePattern.DEFAULT.getPattern();
97+
: NamedInstantPattern.DEFAULT.getPattern();
9898
}
9999

100100
/**
@@ -109,8 +109,40 @@ private static String readPattern(@Nullable final String[] options) {
109109
* @since 2.25.0
110110
*/
111111
static String decodeNamedPattern(final String pattern) {
112+
// If legacy formatters are enabled, we need to produce output aimed for `FixedDateFormat` and `FastDateFormat`.
113+
// Otherwise, we need to produce output aimed for `DateTimeFormatter`.
114+
// In conclusion, we need to check if legacy formatters enabled and apply following transformations.
115+
//
116+
// | Microseconds | Nanoseconds | Time-zone
117+
// ------------------------------+--------------+-------------+-----------
118+
// Legacy formatter directive | nnnnnn | nnnnnnnnn | X, XX, XXX
119+
// `DateTimeFormatter` directive | SSSSSS | SSSSSSSSS | x, xx, xxx
120+
//
121+
// Enabling legacy formatters mean that user requests the pattern to be formatted using deprecated
122+
// `FixedDateFormat` and `FastDateFormat`.
123+
// These two have, let's not say _bogus_, but an _interesting_ way of handling certain pattern directives:
124+
//
125+
// - They say they adhere to `SimpleDateFormat` specification, but use `n` directive.
126+
// `n` is neither defined by `SimpleDateFormat`, nor `SimpleDateFormat` supports sub-millisecond precisions.
127+
// `n` is probably manually introduced by Log4j to support sub-millisecond precisions.
128+
//
129+
// - `n` denotes nano-of-second for `DateTimeFormatter`.
130+
// In Java 17, `n` and `N` (nano-of-day) always output nanosecond precision.
131+
// This is independent of how many times they occur consequently.
132+
// Yet legacy formatters use repeated `n` to denote sub-milliseconds precision of certain length.
133+
// This doesn't work for `DateTimeFormatter`, which needs
134+
//
135+
// - `SSSSSS` for 6-digit microsecond precision
136+
// - `SSSSSSSSS` for 9-digit nanosecond precision
137+
//
138+
// - Legacy formatters use `X`, `XX,` and `XXX` to choose between `+00`, `+0000`, or `+00:00`.
139+
// This is the correct behaviour for `SimpleDateFormat`.
140+
// Though `X` in `DateTimeFormatter` produces `Z` for zero-offset.
141+
// To avoid the `Z` output, one needs to use `x` with `DateTimeFormatter`.
112142
try {
113-
return NamedDatePattern.valueOf(pattern).getPattern();
143+
return InstantPatternFormatter.LEGACY_FORMATTERS_ENABLED
144+
? FixedDateFormat.FixedFormat.valueOf(pattern).getPattern()
145+
: NamedInstantPattern.valueOf(pattern).getPattern();
114146
} catch (IllegalArgumentException ignored) {
115147
return pattern;
116148
}

log4j-core/src/main/java/org/apache/logging/log4j/core/pattern/NamedDatePattern.java

Lines changed: 0 additions & 114 deletions
This file was deleted.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to you under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.logging.log4j.core.pattern;
18+
19+
/**
20+
* Represents named date & time patterns for formatting log timestamps.
21+
*
22+
* @see DatePatternConverter
23+
* @since 2.26.0
24+
*/
25+
public enum NamedInstantPattern {
26+
27+
ABSOLUTE("HH:mm:ss,SSS"),
28+
29+
ABSOLUTE_MICROS("HH:mm:ss,SSSSSS"),
30+
31+
ABSOLUTE_NANOS("HH:mm:ss,SSSSSSSSS"),
32+
33+
ABSOLUTE_PERIOD("HH:mm:ss.SSS"),
34+
35+
COMPACT("yyyyMMddHHmmssSSS"),
36+
37+
DATE("dd MMM yyyy HH:mm:ss,SSS"),
38+
39+
DATE_PERIOD("dd MMM yyyy HH:mm:ss.SSS"),
40+
41+
DEFAULT("yyyy-MM-dd HH:mm:ss,SSS"),
42+
43+
DEFAULT_MICROS("yyyy-MM-dd HH:mm:ss,SSSSSS"),
44+
45+
DEFAULT_NANOS("yyyy-MM-dd HH:mm:ss,SSSSSSSSS"),
46+
47+
DEFAULT_PERIOD("yyyy-MM-dd HH:mm:ss.SSS"),
48+
49+
ISO8601_BASIC("yyyyMMdd'T'HHmmss,SSS"),
50+
51+
ISO8601_BASIC_PERIOD("yyyyMMdd'T'HHmmss.SSS"),
52+
53+
ISO8601("yyyy-MM-dd'T'HH:mm:ss,SSS"),
54+
55+
ISO8601_OFFSET_DATE_TIME_HH("yyyy-MM-dd'T'HH:mm:ss,SSSx"),
56+
57+
ISO8601_OFFSET_DATE_TIME_HHMM("yyyy-MM-dd'T'HH:mm:ss,SSSxx"),
58+
59+
ISO8601_OFFSET_DATE_TIME_HHCMM("yyyy-MM-dd'T'HH:mm:ss,SSSxxx"),
60+
61+
ISO8601_PERIOD("yyyy-MM-dd'T'HH:mm:ss.SSS"),
62+
63+
ISO8601_PERIOD_MICROS("yyyy-MM-dd'T'HH:mm:ss.SSSSSS"),
64+
65+
US_MONTH_DAY_YEAR2_TIME("dd/MM/yy HH:mm:ss.SSS"),
66+
67+
US_MONTH_DAY_YEAR4_TIME("dd/MM/yyyy HH:mm:ss.SSS");
68+
69+
private final String pattern;
70+
71+
NamedInstantPattern(String pattern) {
72+
this.pattern = pattern;
73+
}
74+
75+
public String getPattern() {
76+
return pattern;
77+
}
78+
}

src/changelog/.2.x.x/exported_named_patterns_into_public_enum.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
xsi:schemaLocation="https://logging.apache.org/xml/ns https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
55
type="added">
66
<issue id="3789" link="https://github.com/apache/logging-log4j2/pull/3789"/>
7-
<description format="asciidoc">Add and export `org.apache.logging.log4j.core.pattern.NamedDatePattern` enabling users to programmatically access named date &amp; time patterns supported by Pattern Layout</description>
7+
<description format="asciidoc">Add and export `org.apache.logging.log4j.core.pattern.NamedInstantPattern` enabling users to programmatically access named date &amp; time patterns supported by Pattern Layout</description>
88
</entry>

0 commit comments

Comments
 (0)