Skip to content

Commit 430741f

Browse files
authored
Fix false positive date detection with trailing dot (#116953) (#117960)
1 parent c47162c commit 430741f

File tree

4 files changed

+38
-1
lines changed

4 files changed

+38
-1
lines changed

docs/changelog/116953.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 116953
2+
summary: Fix false positive date detection with trailing dot
3+
area: Mapping
4+
type: bug
5+
issues:
6+
- 116946

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,10 @@ public long getFrom(TemporalAccessor temporal) {
246246
.toFormatter(Locale.ROOT);
247247

248248
// this supports milliseconds ending in dot
249-
private static final DateTimeFormatter MILLISECONDS_FORMATTER2 = new DateTimeFormatterBuilder().append(MILLISECONDS_FORMATTER1)
249+
private static final DateTimeFormatter MILLISECONDS_FORMATTER2 = new DateTimeFormatterBuilder().optionalStart()
250+
.appendText(NEGATIVE_SIGN_FIELD, Map.of(-1L, "-")) // field is only created in the presence of a '-' char.
251+
.optionalEnd()
252+
.appendValue(UNSIGNED_MILLIS, 1, 19, SignStyle.NOT_NEGATIVE)
250253
.appendLiteral('.')
251254
.toFormatter(Locale.ROOT);
252255

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,17 @@ public void testEpochMillisParser() {
242242
assertThat(formatter.format(instant), is("-0.12345"));
243243
assertThat(Instant.from(formatter.parse(formatter.format(instant))), is(instant));
244244
}
245+
{
246+
Instant instant = Instant.from(formatter.parse("12345."));
247+
assertThat(instant.getEpochSecond(), is(12L));
248+
assertThat(instant.getNano(), is(345_000_000));
249+
assertThat(formatter.format(instant), is("12345"));
250+
assertThat(Instant.from(formatter.parse(formatter.format(instant))), is(instant));
251+
}
252+
{
253+
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> formatter.parse("12345.0."));
254+
assertThat(e.getMessage(), is("failed to parse date field [12345.0.] with format [epoch_millis]"));
255+
}
245256
}
246257

247258
/**

server/src/test/java/org/elasticsearch/index/mapper/DynamicMappingTests.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,23 @@ private void doTestDefaultFloatingPointMappings(DocumentMapper mapper, XContentB
597597
assertThat(((FieldMapper) update.getRoot().getMapper("quux")).fieldType().typeName(), equalTo("float"));
598598
}
599599

600+
public void testDateDetectionEnabled() throws Exception {
601+
MapperService mapperService = createMapperService(topMapping(b -> b.field("date_detection", true)));
602+
603+
ParsedDocument doc = mapperService.documentMapper().parse(source(b -> {
604+
b.field("date", "2024-11-18");
605+
b.field("no_date", "128.0.");
606+
}));
607+
assertNotNull(doc.dynamicMappingsUpdate());
608+
merge(mapperService, dynamicMapping(doc.dynamicMappingsUpdate()));
609+
610+
Mapper mapper = mapperService.documentMapper().mappers().getMapper("date");
611+
assertThat(mapper.typeName(), equalTo("date"));
612+
613+
mapper = mapperService.documentMapper().mappers().getMapper("no_date");
614+
assertThat(mapper.typeName(), equalTo("text"));
615+
}
616+
600617
public void testNumericDetectionEnabled() throws Exception {
601618
MapperService mapperService = createMapperService(topMapping(b -> b.field("numeric_detection", true)));
602619

0 commit comments

Comments
 (0)