22
22
import java .util .List ;
23
23
import java .util .Locale ;
24
24
import java .util .Objects ;
25
- import java .util .function .Consumer ;
25
+ import java .util .function .BiConsumer ;
26
26
import java .util .function .UnaryOperator ;
27
27
28
28
class JavaDateFormatter implements DateFormatter {
29
+ /**
30
+ * A default consumer that allows to round up fields (used for range searches, optional fields missing)
31
+ * it relies on toString implementation of DateTimeFormatter and ChronoField.
32
+ * For instance for pattern
33
+ * the parser would have a toString()
34
+ * <code>
35
+ * Value(MonthOfYear,2)'/'Value(DayOfMonth,2)'/'Value(YearOfEra,4,19,EXCEEDS_PAD)'
36
+ * 'Value(ClockHourOfAmPm,2)':'Value(MinuteOfHour,2)' 'Text(AmPmOfDay,SHORT)
37
+ * </code>
38
+ * and ChronoField.CLOCK_HOUR_OF_AMPM would have toString() ClockHourOfAmPm
39
+ * this allows the rounding logic to default CLOCK_HOUR_OF_AMPM field instead of HOUR_OF_DAY
40
+ * without this logic, the rounding would result in a conflict as HOUR_OF_DAY would be missing, but CLOCK_HOUR_OF_AMPM would be provided
41
+ */
42
+ private static final BiConsumer <DateTimeFormatterBuilder , DateTimeFormatter > DEFAULT_ROUND_UP = (builder , parser ) -> {
43
+ String parserAsString = parser .toString ();
44
+ if (parserAsString .contains (ChronoField .MONTH_OF_YEAR .toString ())) {
45
+ builder .parseDefaulting (ChronoField .MONTH_OF_YEAR , 1L );
46
+ }
47
+ if (parserAsString .contains (ChronoField .DAY_OF_MONTH .toString ())) {
48
+ builder .parseDefaulting (ChronoField .DAY_OF_MONTH , 1L );
49
+ }
50
+ if (parserAsString .contains (ChronoField .CLOCK_HOUR_OF_AMPM .toString ())) {
51
+ builder .parseDefaulting (ChronoField .CLOCK_HOUR_OF_AMPM , 11L );
52
+ builder .parseDefaulting (ChronoField .AMPM_OF_DAY , 1L );
53
+ } else if (parserAsString .contains (ChronoField .HOUR_OF_AMPM .toString ())) {
54
+ builder .parseDefaulting (ChronoField .HOUR_OF_AMPM , 11L );
55
+ builder .parseDefaulting (ChronoField .AMPM_OF_DAY , 1L );
56
+ } else {
57
+ builder .parseDefaulting (ChronoField .HOUR_OF_DAY , 23L );
58
+ }
59
+ builder .parseDefaulting (ChronoField .MINUTE_OF_HOUR , 59L );
60
+ builder .parseDefaulting (ChronoField .SECOND_OF_MINUTE , 59L );
61
+ builder .parseDefaulting (ChronoField .NANO_OF_SECOND , 999_999_999L );
62
+ };
29
63
30
64
private final String format ;
31
65
private final DateTimeFormatter printer ;
@@ -50,12 +84,7 @@ JavaDateFormatter getRoundupParser() {
50
84
format ,
51
85
printer ,
52
86
// 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 ),
87
+ DEFAULT_ROUND_UP ,
59
88
parsers
60
89
);
61
90
}
@@ -64,7 +93,7 @@ JavaDateFormatter getRoundupParser() {
64
93
JavaDateFormatter (
65
94
String format ,
66
95
DateTimeFormatter printer ,
67
- Consumer <DateTimeFormatterBuilder > roundupParserConsumer ,
96
+ BiConsumer <DateTimeFormatterBuilder , DateTimeFormatter > roundupParserConsumer ,
68
97
DateTimeFormatter ... parsers
69
98
) {
70
99
if (printer == null ) {
@@ -105,15 +134,15 @@ private static DateTimeFormatter[] parsersArray(DateTimeFormatter printer, DateT
105
134
*/
106
135
private static RoundUpFormatter createRoundUpParser (
107
136
String format ,
108
- Consumer <DateTimeFormatterBuilder > roundupParserConsumer ,
137
+ BiConsumer <DateTimeFormatterBuilder , DateTimeFormatter > roundupParserConsumer ,
109
138
Locale locale ,
110
139
DateTimeFormatter [] parsers
111
140
) {
112
141
if (format .contains ("||" ) == false ) {
113
142
return new RoundUpFormatter (format , mapParsers (parser -> {
114
143
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder ();
115
144
builder .append (parser );
116
- roundupParserConsumer .accept (builder );
145
+ roundupParserConsumer .accept (builder , parser );
117
146
return builder .toFormatter (locale );
118
147
}, parsers ));
119
148
}
@@ -205,7 +234,7 @@ private TemporalAccessor doParse(String input) {
205
234
return this .parsers [0 ].parse (input );
206
235
}
207
236
208
- private boolean parsingSucceeded (Object object , String input , ParsePosition pos ) {
237
+ private static boolean parsingSucceeded (Object object , String input , ParsePosition pos ) {
209
238
return object != null && pos .getIndex () == input .length ();
210
239
}
211
240
0 commit comments