9
9
package org .elasticsearch .common .time ;
10
10
11
11
import org .elasticsearch .common .Strings ;
12
- import org .elasticsearch .common .util .Maps ;
13
12
14
13
import java .text .ParsePosition ;
15
14
import java .time .ZoneId ;
18
17
import java .time .format .DateTimeParseException ;
19
18
import java .time .temporal .ChronoField ;
20
19
import java .time .temporal .TemporalAccessor ;
21
- import java .time .temporal .TemporalField ;
22
20
import java .util .ArrayList ;
23
- import java .util .Arrays ;
24
- import java .util .Collection ;
25
21
import java .util .Collections ;
26
22
import java .util .List ;
27
23
import java .util .Locale ;
28
- import java .util .Map ;
29
24
import java .util .Objects ;
30
25
import java .util .function .Consumer ;
26
+ import java .util .function .UnaryOperator ;
31
27
32
28
class JavaDateFormatter implements DateFormatter {
33
29
34
- // base fields which should be used for default parsing, when we round up for date math
35
- private static final Map <TemporalField , Long > ROUND_UP_BASE_FIELDS = Maps .newMapWithExpectedSize (6 );
36
-
37
- {
38
- ROUND_UP_BASE_FIELDS .put (ChronoField .MONTH_OF_YEAR , 1L );
39
- ROUND_UP_BASE_FIELDS .put (ChronoField .DAY_OF_MONTH , 1L );
40
- ROUND_UP_BASE_FIELDS .put (ChronoField .HOUR_OF_DAY , 23L );
41
- ROUND_UP_BASE_FIELDS .put (ChronoField .MINUTE_OF_HOUR , 59L );
42
- ROUND_UP_BASE_FIELDS .put (ChronoField .SECOND_OF_MINUTE , 59L );
43
- ROUND_UP_BASE_FIELDS .put (ChronoField .NANO_OF_SECOND , 999_999_999L );
44
- }
45
-
46
30
private final String format ;
47
31
private final DateTimeFormatter printer ;
48
- private final List < DateTimeFormatter > parsers ;
49
- private final JavaDateFormatter roundupParser ;
32
+ private final DateTimeFormatter [] parsers ;
33
+ private final RoundUpFormatter roundupParser ;
50
34
51
- static class RoundUpFormatter extends JavaDateFormatter {
35
+ private static final class RoundUpFormatter extends JavaDateFormatter {
52
36
53
- RoundUpFormatter (String format , List <DateTimeFormatter > roundUpParsers ) {
54
- super (format , firstFrom (roundUpParsers ), null , roundUpParsers );
55
- }
56
-
57
- private static DateTimeFormatter firstFrom (List <DateTimeFormatter > roundUpParsers ) {
58
- return roundUpParsers .get (0 );
37
+ RoundUpFormatter (String format , DateTimeFormatter [] roundUpParsers ) {
38
+ super (format , roundUpParsers [0 ], (RoundUpFormatter ) null , roundUpParsers );
59
39
}
60
40
61
41
@ Override
@@ -66,7 +46,18 @@ JavaDateFormatter getRoundupParser() {
66
46
67
47
// named formatters use default roundUpParser
68
48
JavaDateFormatter (String format , DateTimeFormatter printer , DateTimeFormatter ... parsers ) {
69
- this (format , printer , builder -> ROUND_UP_BASE_FIELDS .forEach (builder ::parseDefaulting ), parsers );
49
+ this (
50
+ format ,
51
+ printer ,
52
+ // set up base fields which should be used for default parsing, when we round up for date math
53
+ builder -> builder .parseDefaulting (ChronoField .MONTH_OF_YEAR , 1L )
54
+ .parseDefaulting (ChronoField .DAY_OF_MONTH , 1L )
55
+ .parseDefaulting (ChronoField .HOUR_OF_DAY , 23L )
56
+ .parseDefaulting (ChronoField .MINUTE_OF_HOUR , 59L )
57
+ .parseDefaulting (ChronoField .SECOND_OF_MINUTE , 59L )
58
+ .parseDefaulting (ChronoField .NANO_OF_SECOND , 999_999_999L ),
59
+ parsers
60
+ );
70
61
}
71
62
72
63
// subclasses override roundUpParser
@@ -79,24 +70,28 @@ JavaDateFormatter getRoundupParser() {
79
70
if (printer == null ) {
80
71
throw new IllegalArgumentException ("printer may not be null" );
81
72
}
82
- long distinctZones = Arrays .stream (parsers ).map (DateTimeFormatter ::getZone ).distinct ().count ();
83
- if (distinctZones > 1 ) {
84
- throw new IllegalArgumentException ("formatters must have the same time zone" );
85
- }
86
- long distinctLocales = Arrays .stream (parsers ).map (DateTimeFormatter ::getLocale ).distinct ().count ();
87
- if (distinctLocales > 1 ) {
88
- throw new IllegalArgumentException ("formatters must have the same locale" );
89
- }
90
73
this .printer = printer ;
91
74
this .format = format ;
75
+ this .parsers = parsersArray (printer , parsers );
76
+ this .roundupParser = createRoundUpParser (format , roundupParserConsumer , locale (), this .parsers );
77
+ }
92
78
79
+ private static DateTimeFormatter [] parsersArray (DateTimeFormatter printer , DateTimeFormatter ... parsers ) {
93
80
if (parsers .length == 0 ) {
94
- this .parsers = Collections .singletonList (printer );
95
- } else {
96
- this .parsers = Arrays .asList (parsers );
81
+ return new DateTimeFormatter [] { printer };
82
+ }
83
+ final ZoneId zoneId = parsers [0 ].getZone ();
84
+ final Locale locale = parsers [0 ].getLocale ();
85
+ for (int i = 1 ; i < parsers .length ; i ++) {
86
+ final DateTimeFormatter parser = parsers [i ];
87
+ if (Objects .equals (parser .getZone (), zoneId ) == false ) {
88
+ throw new IllegalArgumentException ("formatters must have the same time zone" );
89
+ }
90
+ if (Objects .equals (parser .getLocale (), locale ) == false ) {
91
+ throw new IllegalArgumentException ("formatters must have the same locale" );
92
+ }
97
93
}
98
- List <DateTimeFormatter > roundUp = createRoundUpParser (format , roundupParserConsumer );
99
- this .roundupParser = new RoundUpFormatter (format , roundUp );
94
+ return parsers ;
100
95
}
101
96
102
97
/**
@@ -108,16 +103,19 @@ JavaDateFormatter getRoundupParser() {
108
103
* <code>DateFormatters</code>.
109
104
* This means that we need to also have multiple RoundUp parsers.
110
105
*/
111
- private List <DateTimeFormatter > createRoundUpParser (String format , Consumer <DateTimeFormatterBuilder > roundupParserConsumer ) {
106
+ private static RoundUpFormatter createRoundUpParser (
107
+ String format ,
108
+ Consumer <DateTimeFormatterBuilder > roundupParserConsumer ,
109
+ Locale locale ,
110
+ DateTimeFormatter [] parsers
111
+ ) {
112
112
if (format .contains ("||" ) == false ) {
113
- List <DateTimeFormatter > roundUpParsers = new ArrayList <>();
114
- for (DateTimeFormatter parser : this .parsers ) {
113
+ return new RoundUpFormatter (format , mapParsers (parser -> {
115
114
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder ();
116
115
builder .append (parser );
117
116
roundupParserConsumer .accept (builder );
118
- roundUpParsers .add (builder .toFormatter (locale ()));
119
- }
120
- return roundUpParsers ;
117
+ return builder .toFormatter (locale );
118
+ }, parsers ));
121
119
}
122
120
return null ;
123
121
}
@@ -135,22 +133,26 @@ public static DateFormatter combined(String input, List<DateFormatter> formatter
135
133
if (printer == null ) {
136
134
printer = javaDateFormatter .getPrinter ();
137
135
}
138
- parsers .addAll (javaDateFormatter .getParsers () );
139
- roundUpParsers .addAll (javaDateFormatter .getRoundupParser ().getParsers () );
136
+ Collections .addAll (parsers , javaDateFormatter .parsers );
137
+ Collections .addAll (roundUpParsers , javaDateFormatter .getRoundupParser ().parsers );
140
138
}
141
139
142
- return new JavaDateFormatter (input , printer , roundUpParsers , parsers );
140
+ return new JavaDateFormatter (
141
+ input ,
142
+ printer ,
143
+ roundUpParsers .toArray (DateTimeFormatter []::new ),
144
+ parsers .toArray (DateTimeFormatter []::new )
145
+ );
143
146
}
144
147
145
- private JavaDateFormatter (
146
- String format ,
147
- DateTimeFormatter printer ,
148
- List <DateTimeFormatter > roundUpParsers ,
149
- List <DateTimeFormatter > parsers
150
- ) {
148
+ private JavaDateFormatter (String format , DateTimeFormatter printer , DateTimeFormatter [] roundUpParsers , DateTimeFormatter [] parsers ) {
149
+ this (format , printer , new RoundUpFormatter (format , roundUpParsers ), parsers );
150
+ }
151
+
152
+ private JavaDateFormatter (String format , DateTimeFormatter printer , RoundUpFormatter roundupParser , DateTimeFormatter [] parsers ) {
151
153
this .format = format ;
152
154
this .printer = printer ;
153
- this .roundupParser = roundUpParsers != null ? new RoundUpFormatter ( format , roundUpParsers ) : null ;
155
+ this .roundupParser = roundupParser ;
154
156
this .parsers = parsers ;
155
157
}
156
158
@@ -190,7 +192,7 @@ public TemporalAccessor parse(String input) {
190
192
* @throws DateTimeParseException when unable to parse with any parsers
191
193
*/
192
194
private TemporalAccessor doParse (String input ) {
193
- if (parsers .size () > 1 ) {
195
+ if (parsers .length > 1 ) {
194
196
for (DateTimeFormatter formatter : parsers ) {
195
197
ParsePosition pos = new ParsePosition (0 );
196
198
Object object = formatter .toFormat ().parseObject (input , pos );
@@ -200,7 +202,7 @@ private TemporalAccessor doParse(String input) {
200
202
}
201
203
throw new DateTimeParseException ("Failed to parse with all enclosed parsers" , input , 0 );
202
204
}
203
- return this .parsers . get ( 0 ) .parse (input );
205
+ return this .parsers [ 0 ] .parse (input );
204
206
}
205
207
206
208
private boolean parsingSucceeded (Object object , String input , ParsePosition pos ) {
@@ -213,9 +215,7 @@ public DateFormatter withZone(ZoneId zoneId) {
213
215
if (zoneId .equals (zone ())) {
214
216
return this ;
215
217
}
216
- List <DateTimeFormatter > parsers = this .parsers .stream ().map (p -> p .withZone (zoneId )).toList ();
217
- List <DateTimeFormatter > roundUpParsers = this .roundupParser .getParsers ().stream ().map (p -> p .withZone (zoneId )).toList ();
218
- return new JavaDateFormatter (format , printer .withZone (zoneId ), roundUpParsers , parsers );
218
+ return mapParsers (p -> p .withZone (zoneId ));
219
219
}
220
220
221
221
@ Override
@@ -224,9 +224,24 @@ public DateFormatter withLocale(Locale locale) {
224
224
if (locale .equals (locale ())) {
225
225
return this ;
226
226
}
227
- List <DateTimeFormatter > parsers = this .parsers .stream ().map (p -> p .withLocale (locale )).toList ();
228
- List <DateTimeFormatter > roundUpParsers = this .roundupParser .getParsers ().stream ().map (p -> p .withLocale (locale )).toList ();
229
- return new JavaDateFormatter (format , printer .withLocale (locale ), roundUpParsers , parsers );
227
+ return mapParsers (p -> p .withLocale (locale ));
228
+ }
229
+
230
+ private JavaDateFormatter mapParsers (UnaryOperator <DateTimeFormatter > mapping ) {
231
+ return new JavaDateFormatter (
232
+ format ,
233
+ mapping .apply (printer ),
234
+ mapParsers (mapping , ((JavaDateFormatter ) this .roundupParser ).parsers ),
235
+ mapParsers (mapping , this .parsers )
236
+ );
237
+ }
238
+
239
+ private static DateTimeFormatter [] mapParsers (UnaryOperator <DateTimeFormatter > mapping , DateTimeFormatter [] parsers ) {
240
+ DateTimeFormatter [] res = new DateTimeFormatter [parsers .length ];
241
+ for (int i = 0 ; i < parsers .length ; i ++) {
242
+ res [i ] = mapping .apply (parsers [i ]);
243
+ }
244
+ return res ;
230
245
}
231
246
232
247
@ Override
@@ -276,7 +291,4 @@ public String toString() {
276
291
return String .format (Locale .ROOT , "format[%s] locale[%s]" , format , locale ());
277
292
}
278
293
279
- Collection <DateTimeFormatter > getParsers () {
280
- return parsers ;
281
- }
282
294
}
0 commit comments