LUCENE-8787: DateRangePrefixTree now parses milliseconds when num digits != 3

This commit is contained in:
Thomas Lemmé 2019-05-01 00:32:19 -04:00 committed by David Smiley
parent a32decde6a
commit 424558ff88
3 changed files with 37 additions and 5 deletions

View File

@ -139,6 +139,10 @@ Improvements
of codec internals. This enables a per reader configuration if FSTs are on- or off-heap on a of codec internals. This enables a per reader configuration if FSTs are on- or off-heap on a
per field basis (Simon Willnauer) per field basis (Simon Willnauer)
* LUCENE-8787: spatial-extras DateRangePrefixTree used to only parse ISO-8601 timestamps with 0 or 3
digits of milliseconds precision but now parses other lengths (although > 3 not used).
(Thomas Lemmé via David Smiley)
Changes in Runtime Behavior Changes in Runtime Behavior
* LUCENE-8671: Load FST off-heap also for ID-like fields if reader is not opened * LUCENE-8671: Load FST off-heap also for ID-like fields if reader is not opened

View File

@ -504,16 +504,16 @@ public class DateRangePrefixTree extends NumberRangePrefixTree {
checkDelimeter(str, offset-1, '.'); checkDelimeter(str, offset-1, '.');
//ms: //ms:
cal.set(Calendar.MILLISECOND, Integer.parseInt(str.substring(offset, offset+3))); int maxOffset = lastOffset - offset; // assume remaining is all digits to compute milliseconds
offset += 3;//last one, move to next char // we truncate off > millisecond precision (3 digits only)
if (lastOffset == offset) int millis = (int) (Integer.parseInt(str.substring(offset, offset + maxOffset)) / Math.pow(10, maxOffset - 3));
return cal; cal.set(Calendar.MILLISECOND, millis);
return cal;
} catch (Exception e) { } catch (Exception e) {
ParseException pe = new ParseException("Improperly formatted datetime: "+str, offset); ParseException pe = new ParseException("Improperly formatted datetime: "+str, offset);
pe.initCause(e); pe.initCause(e);
throw pe; throw pe;
} }
throw new ParseException("Improperly formatted datetime: "+str, offset);
} }
private void checkDelimeter(String str, int offset, char delim) { private void checkDelimeter(String str, int offset, char delim) {

View File

@ -17,8 +17,11 @@
package org.apache.lucene.spatial.prefix.tree; package org.apache.lucene.spatial.prefix.tree;
import java.text.ParseException; import java.text.ParseException;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset; import java.time.ZoneOffset;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
@ -30,6 +33,8 @@ import org.apache.lucene.util.LuceneTestCase;
import org.locationtech.spatial4j.shape.Shape; import org.locationtech.spatial4j.shape.Shape;
import org.locationtech.spatial4j.shape.SpatialRelation; import org.locationtech.spatial4j.shape.SpatialRelation;
import static java.time.format.DateTimeFormatter.ISO_DATE_TIME;
public class DateRangePrefixTreeTest extends LuceneTestCase { public class DateRangePrefixTreeTest extends LuceneTestCase {
@ParametersFactory(argumentFormatting = "calendar=%s") @ParametersFactory(argumentFormatting = "calendar=%s")
@ -113,6 +118,29 @@ public class DateRangePrefixTreeTest extends LuceneTestCase {
assertEquals(cal, tree.parseCalendar(expectedISO8601)); assertEquals(cal, tree.parseCalendar(expectedISO8601));
} }
public void testParseCalendar() throws ParseException {
Instant expected = OffsetDateTime.of(1984, 12, 18, 12, 34, 56, 100000000, ZoneOffset.UTC).toInstant();
assertEquals(expected, tree.parseCalendar("1984-12-18T12:34:56.1Z").toInstant());
assertEquals(expected.with(ChronoField.MILLI_OF_SECOND, 10), tree.parseCalendar("1984-12-18T12:34:56.01Z").toInstant());
assertEquals(expected.with(ChronoField.MILLI_OF_SECOND, 1), tree.parseCalendar("1984-12-18T12:34:56.001Z").toInstant());
assertEquals(expected, tree.parseCalendar("1984-12-18T12:34:56.1000Z").toInstant());
assertEquals(expected, tree.parseCalendar("1984-12-18T12:34:56.100000000Z").toInstant());
assertEquals(expected.with(ChronoField.NANO_OF_SECOND, 0), tree.parseCalendar("1984-12-18T12:34:56Z").toInstant());
// decimal places are simply cut off as rounding may affect the "seconds" part of the calender which was set before
assertEquals(expected.with(ChronoField.MILLI_OF_SECOND, 999), tree.parseCalendar("1984-12-18T12:34:56.9999Z").toInstant());
assertEquals(expected, tree.parseCalendar("1984-12-18T12:34:56.1").toInstant());
assertEquals(expected.with(ChronoField.MILLI_OF_SECOND, 10), tree.parseCalendar("1984-12-18T12:34:56.01").toInstant());
assertEquals(expected.with(ChronoField.MILLI_OF_SECOND, 1), tree.parseCalendar("1984-12-18T12:34:56.001").toInstant());
assertEquals(expected, tree.parseCalendar("1984-12-18T12:34:56.1000").toInstant());
assertEquals(expected, tree.parseCalendar("1984-12-18T12:34:56.100000000").toInstant());
assertEquals(expected.with(ChronoField.NANO_OF_SECOND, 0), tree.parseCalendar("1984-12-18T12:34:56").toInstant());
assertEquals(expected.with(ChronoField.MILLI_OF_SECOND, 999), tree.parseCalendar("1984-12-18T12:34:56.9999").toInstant());
assertEquals(OffsetDateTime.parse("1984-12-18T12:34:56.01Z", ISO_DATE_TIME).get(ChronoField.MILLI_OF_SECOND), 10);
}
//copies from DateRangePrefixTree //copies from DateRangePrefixTree
private static final int[] CAL_FIELDS = { private static final int[] CAL_FIELDS = {
Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH,