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