Skip to content

Commit c5b30a2

Browse files
author
Christoph Büscher
authored
All DateFormatters should be able to print Long.MAX_VALUE (elastic#65945) (elastic#66101)
All date formats should allow all possible long date values to be formatted. Currently some of the printers used by some formats are too restrictive here (e.g. for 'basic_date_time_no_millis'), only allowing up to four digits for the year. This PR changes this for the formatters that are otherwise failing the added tests that tries to format Long.MAX_VALUE and Long.MIN_VALUE respectively, as these are values we for example implicitely use when sorting missing fields. Closes elastic#65639
1 parent 41285a6 commit c5b30a2

File tree

2 files changed

+29
-4
lines changed

2 files changed

+29
-4
lines changed

server/src/main/java/org/elasticsearch/common/time/DateFormatters.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,13 @@ public class DateFormatters {
345345
.withResolverStyle(ResolverStyle.STRICT)
346346
);
347347

348+
private static final DateTimeFormatter BASIC_YEAR_MONTH_DAY_PRINTER = new DateTimeFormatterBuilder()
349+
.appendValue(ChronoField.YEAR, 4, 10, SignStyle.NORMAL)
350+
.appendValue(MONTH_OF_YEAR, 2, 2, SignStyle.NOT_NEGATIVE)
351+
.appendValue(DAY_OF_MONTH, 2, 2, SignStyle.NOT_NEGATIVE)
352+
.toFormatter(Locale.ROOT)
353+
.withResolverStyle(ResolverStyle.STRICT);
354+
348355
private static final DateTimeFormatter BASIC_YEAR_MONTH_DAY_FORMATTER = new DateTimeFormatterBuilder()
349356
.appendValue(ChronoField.YEAR, 4, 4, SignStyle.NORMAL)
350357
.appendValue(MONTH_OF_YEAR, 2, 2, SignStyle.NOT_NEGATIVE)
@@ -359,7 +366,7 @@ public class DateFormatters {
359366
.withResolverStyle(ResolverStyle.STRICT);
360367

361368
private static final DateTimeFormatter BASIC_DATE_TIME_PRINTER = new DateTimeFormatterBuilder()
362-
.append(BASIC_YEAR_MONTH_DAY_FORMATTER)
369+
.append(BASIC_YEAR_MONTH_DAY_PRINTER)
363370
.append(BASIC_T_TIME_PRINTER)
364371
.toFormatter(Locale.ROOT)
365372
.withResolverStyle(ResolverStyle.STRICT);
@@ -381,12 +388,16 @@ public class DateFormatters {
381388
new DateTimeFormatterBuilder().append(BASIC_YEAR_MONTH_DAY_FORMATTER).appendLiteral("T").toFormatter(Locale.ROOT)
382389
.withResolverStyle(ResolverStyle.STRICT);
383390

391+
private static final DateTimeFormatter BASIC_DATE_T_PRINTER =
392+
new DateTimeFormatterBuilder().append(BASIC_YEAR_MONTH_DAY_PRINTER).appendLiteral("T").toFormatter(Locale.ROOT)
393+
.withResolverStyle(ResolverStyle.STRICT);
394+
384395
/*
385396
* Returns a basic formatter that combines a basic date and time without millis,
386397
* separated by a 'T' (uuuuMMdd'T'HHmmssZ).
387398
*/
388399
private static final DateFormatter BASIC_DATE_TIME_NO_MILLIS = new JavaDateFormatter("basic_date_time_no_millis",
389-
new DateTimeFormatterBuilder().append(BASIC_DATE_T).append(BASIC_TIME_NO_MILLIS_BASE)
400+
new DateTimeFormatterBuilder().append(BASIC_DATE_T_PRINTER).append(BASIC_TIME_NO_MILLIS_BASE)
390401
.appendOffset("+HH:MM", "Z").toFormatter(Locale.ROOT)
391402
.withResolverStyle(ResolverStyle.STRICT),
392403
new DateTimeFormatterBuilder().append(BASIC_DATE_T).append(BASIC_TIME_NO_MILLIS_BASE)
@@ -467,7 +478,7 @@ public class DateFormatters {
467478

468479
private static final DateTimeFormatter STRICT_BASIC_WEEK_DATE_PRINTER = new DateTimeFormatterBuilder()
469480
.parseStrict()
470-
.appendValue(IsoFields.WEEK_BASED_YEAR, 4)
481+
.appendValue(IsoFields.WEEK_BASED_YEAR, 4, 10, SignStyle.NORMAL)
471482
.appendLiteral("W")
472483
.appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2, 2, SignStyle.NEVER)
473484
.appendValue(ChronoField.DAY_OF_WEEK)
@@ -1000,7 +1011,7 @@ public class DateFormatters {
10001011
*/
10011012
private static final DateFormatter BASIC_DATE = new JavaDateFormatter("basic_date",
10021013
new DateTimeFormatterBuilder()
1003-
.appendValue(ChronoField.YEAR, 4, 4, SignStyle.NORMAL)
1014+
.appendValue(ChronoField.YEAR, 4, 10, SignStyle.NORMAL)
10041015
.appendValue(MONTH_OF_YEAR, 2, 2, SignStyle.NOT_NEGATIVE)
10051016
.appendValue(DAY_OF_MONTH, 2, 2, SignStyle.NOT_NEGATIVE)
10061017
.toFormatter(Locale.ROOT)

server/src/test/java/org/elasticsearch/common/time/DateFormattersTests.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.elasticsearch.bootstrap.JavaVersion;
2323
import org.elasticsearch.common.joda.Joda;
24+
import org.elasticsearch.index.mapper.DateFieldMapper;
2425
import org.elasticsearch.test.ESTestCase;
2526

2627
import java.time.Clock;
@@ -93,6 +94,19 @@ public void testEpochMillisParser() {
9394
}
9495
}
9596

97+
/**
98+
* test that formatting a date with Long.MAX_VALUE or Long.MIN_VALUE doesn throw errors since we use these
99+
* e.g. for sorting documents with `null` values first or last
100+
*/
101+
public void testPrintersLongMinMaxValue() {
102+
for (FormatNames format : FormatNames.values()) {
103+
DateFormatter formatter = DateFormatters.forPattern(format.getSnakeCaseName());
104+
formatter.format(DateFieldMapper.Resolution.MILLISECONDS.toInstant(Long.MIN_VALUE));
105+
formatter.format(DateFieldMapper.Resolution.MILLISECONDS.toInstant(Long.MAX_VALUE));
106+
}
107+
assertWarnings("Format name \"week_year\" is deprecated and will be removed in a future version. Use \"weekyear\" format instead");
108+
}
109+
96110
public void testInvalidEpochMilliParser() {
97111
DateFormatter formatter = DateFormatters.forPattern("epoch_millis");
98112
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> formatter.parse("invalid"));

0 commit comments

Comments
 (0)