blob: 8b04101feb56a586bf931c2bd29ce453ec4e4893 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.update.processor;
import java.io.IOException;
import java.text.DecimalFormatSymbols;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.hamcrest.core.IsInstanceOf;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.schema.IndexSchema;
import org.junit.BeforeClass;
/**
* Tests for the field mutating update processors
* that parse Dates, Longs, Doubles, and Booleans.
*/
public class ParsingFieldUpdateProcessorsTest extends UpdateProcessorTestBase {
private static final double EPSILON = 1E-15;
private static final DateTimeFormatter isoDateOptionalTimeFormatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd['T'HH:mm[:ss[.SSS]]][z", Locale.ROOT).withZone(ZoneOffset.UTC);
private static final IsInstanceOf IS_BOOLEAN = new IsInstanceOf(Boolean.class);
private static final IsInstanceOf IS_STRING = new IsInstanceOf(String.class);
private static final IsInstanceOf IS_DATE = new IsInstanceOf(Date.class);
private static final IsInstanceOf IS_FLOAT = new IsInstanceOf(Float.class);
private static final IsInstanceOf IS_DOUBLE = new IsInstanceOf(Double.class);
private static final IsInstanceOf IS_INTEGER = new IsInstanceOf(Integer.class);
private static final IsInstanceOf IS_LONG = new IsInstanceOf(Long.class);
@BeforeClass
public static void beforeClass() throws Exception {
initCore("solrconfig-parsing-update-processor-chains.xml", "schema12.xml");
}
public void testParseDateRoundTrip() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("date_dt")); // should match "*_dt" dynamic field
String dateString = "2010-11-12T13:14:15.168Z";
SolrInputDocument d = processAdd("parse-date", doc(f("id", "9"), f("date_dt", dateString)));
assertNotNull(d);
assertThat(d.getFieldValue("date_dt"), IS_DATE);
assertEquals(Instant.parse(dateString), ((Date) d.getFieldValue("date_dt")).toInstant());
assertU(commit());
assertQ(req("id:9"), "//date[@name='date_dt'][.='" + dateString + "']");
}
public void testParseTrieDateRoundTrip() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("date_tdt")); // should match "*_tdt" dynamic field
String dateString = "2010-11-12T13:14:15.168Z";
SolrInputDocument d = processAdd("parse-date", doc(f("id", "39"), f("date_tdt", dateString)));
assertNotNull(d);
assertThat(d.getFieldValue("date_tdt"), IS_DATE);
assertEquals(Instant.parse(dateString), ((Date) d.getFieldValue("date_tdt")).toInstant());
assertU(commit());
assertQ(req("id:39"), "//date[@name='date_tdt'][.='" + dateString + "']");
}
public void testParseDateFieldNotInSchema() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNull(schema.getFieldOrNull("not_in_schema"));
String dateString = "2010-11-12T13:14:15.168Z";
SolrInputDocument d = processAdd("parse-date-no-run-processor",
doc(f("id", "18"), f("not_in_schema", dateString)));
assertNotNull(d);
assertThat(d.getFieldValue("not_in_schema"), IS_DATE);
assertEquals(Instant.parse(dateString), ((Date)d.getFieldValue("not_in_schema")).toInstant());
d = processAdd("parse-date-no-run-processor",
doc(f("id", "36"), f("not_in_schema", "not a date", dateString)));
assertNotNull(d);
for (Object val : d.getFieldValues("not_in_schema")) {
// check that nothing was mutated, since not all field values are parseable as dates
assertThat(val, IS_STRING);
}
d = processAdd("parse-date-no-run-processor",
doc(f("id", "72"), f("not_in_schema", dateString, "not a date")));
assertNotNull(d);
for (Object val : d.getFieldValues("not_in_schema")) {
// check again that nothing was mutated, but with a valid date first this time
assertThat(val, IS_STRING);
}
}
public void testParseDateNonUTCdefaultTimeZoneRoundTrip() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("date_dt")); // should match "*_dt" dynamic field
String dateStringNoTimeZone = "2010-11-12T13:14:15.168";
String dateStringUTC = dateStringNoTimeZone + "Z";
// dateStringNoTimeZone interpreted as being in timeZone America/New_York, then printed as UTC
String dateStringUSEasternTimeAsUTC = "2010-11-12T18:14:15.168Z";
SolrInputDocument d = processAdd
("parse-date-non-UTC-defaultTimeZone", doc(f("id", "99"), f("dateUTC_dt", dateStringUTC),
f("dateNoTimeZone_dt", dateStringNoTimeZone)));
assertNotNull(d);
assertThat(d.getFieldValue("dateUTC_dt"), IS_DATE);
assertThat(d.getFieldValue("dateNoTimeZone_dt"), IS_DATE);
assertU(commit());
assertQ(req("id:99")
,"//date[@name='dateUTC_dt'][.='" + dateStringUTC + "']"
,"//date[@name='dateNoTimeZone_dt'][.='" + dateStringUSEasternTimeAsUTC + "']");
}
public void testParseDateExplicitNotInSchemaSelector() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNull(schema.getFieldOrNull("not_in_schema"));
String dateString = "2010-11-12T13:14:15.168Z";
SolrInputDocument d = processAdd("parse-date-explicit-not-in-schema-selector-no-run-processor",
doc(f("id", "88"), f("not_in_schema", dateString)));
assertNotNull(d);
assertThat(d.getFieldValue("not_in_schema"), IS_DATE);
assertEquals(Instant.parse(dateString), ((Date)d.getFieldValue("not_in_schema")).toInstant());
}
public void testParseDateExplicitTypeClassSelector() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("date_dt"));
String dateString = "2010-11-12T13:14:15.168Z";
SolrInputDocument d;
if (schema.getField("date_dt").getType().isPointField()) {
d = processAdd("parse-date-explicit-typeclass-point-selector-no-run-processor",
doc(f("id", "77"), f("date_dt", dateString)));
} else {
d = processAdd("parse-date-explicit-typeclass-selector-no-run-processor",
doc(f("id", "77"), f("date_dt", dateString)));
}
assertNotNull(d);
assertThat(d.getFieldValue("date_dt"), IS_DATE);
assertEquals(Instant.parse(dateString), ((Date)d.getFieldValue("date_dt")).toInstant());
}
public void testParseUSPacificDate() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNull(schema.getFieldOrNull("not_in_schema"));
String dateString = "8/9/2010"; // Interpreted as 00:00 US Pacific Daylight Time = UTC+07:00
SolrInputDocument d = processAdd("US-Pacific-parse-date-no-run-processor",
doc(f("id", "288"), f("not_in_schema", dateString)));
assertNotNull(d);
assertThat(d.getFieldValue("not_in_schema"), IS_DATE);
assertEquals(Instant.parse("2010-08-09T07:00:00.000Z"), ((Date)d.getFieldValue("not_in_schema")).toInstant());
}
public void testParseDateManyFormats() throws Exception {
String[] formatExamples = {
"2010-01-15T00:00:00.000Z",
"2010-01-15T00:00:00,000Z",
"2010-01-15T00:00:00.000",
"2010-01-15T00:00:00,000",
"2010-01-15T00:00:00Z",
"2010-01-15T00:00:00",
"2010-01-15T00:00Z",
"2010-01-15T00:00",
"2010-01-15 00:00:00.000Z",
"2010-01-15 00:00:00,000Z",
"2010-01-15 00:00:00.000",
"2010-01-15 00:00:00,000",
"2010-01-15 00:00:00Z",
"2010-01-15 00:00:00",
"2010-01-15 00:00Z",
"2010-01-15 00:00",
"2010-01-15 12:00 AM",
"2010-01-15 12:00AM",
"2010-01-15",
"Fri Jan 15 00:00:00 +0000 2010",
"Fri Jan 15 00:00:00 2010 +00:00",
"Fri Jan 15 00:00:00 2010",
"Fri, 15 Jan 2010 00:00:00 +00:00",
"Friday, 15-Jan-10 00:00:00 +00:00",
"Friday, January 15, 2010",
"January 15, 2010",
"Jan. 15, 2010"
};
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("dateUTC_dt")); // should match "*_dt" dynamic field
Instant expectedInstant = Instant.parse(formatExamples[0]);
for (int i = 0 ; i < formatExamples.length ; ++i) {
String dateString = formatExamples[i];
String id = "95" + i;
SolrInputDocument d = processAdd("parse-date-many-formats-no-run-processor",
doc(f("id", id), f("dateUTC_dt", dateString)));
assertNotNull(d);
assertThat("index: " + i + " date '" + dateString + "' is not mutated to a Date",
d.getFieldValue("dateUTC_dt"), IS_DATE);
assertEquals("date '" + dateString + "' mismatched milliseconds",
expectedInstant, ((Date)d.getFieldValue("dateUTC_dt")).toInstant());
}
}
public void testParseFrenchDate() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNull(schema.getFieldOrNull("not_in_schema"));
String frenchDateString = "le vendredi 15 janvier 2010";
String dateString = "2010-01-15T00:00:00.000Z";
SolrInputDocument d = processAdd("parse-french-date-UTC-defaultTimeZone-no-run-processor",
doc(f("id", "88"), f("not_in_schema", frenchDateString)));
assertNotNull(d);
assertThat(d.getFieldValue("not_in_schema"), IS_DATE);
assertEquals(Instant.parse(dateString), ((Date)d.getFieldValue("not_in_schema")).toInstant());
}
public void testFailedParseMixedDate() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNull(schema.getFieldOrNull("not_in_schema"));
Map<Object,Object> mixed = new HashMap<>();
String[] dateStrings = { "2020-05-13T18:47", "1989-12-14", "1682-07-22T18:33:00.000Z" };
for (String dateString : dateStrings) {
mixed.put(parse(isoDateOptionalTimeFormatter, dateString), dateString);
}
Double extraDouble = 29.554d;
mixed.put(extraDouble, extraDouble); // Double-typed field value
SolrInputDocument d = processAdd("parse-date-no-run-processor",
doc(f("id", "7201"), f("not_in_schema", mixed.values())));
assertNotNull(d);
boolean foundDouble = false;
for (Object o : d.getFieldValues("not_in_schema")) {
if (extraDouble == o) {
foundDouble = true;
} else {
assertThat(o, IS_STRING);
}
mixed.values().remove(o);
}
assertTrue(foundDouble);
assertTrue(mixed.isEmpty());
}
public void testParseIntRoundTrip() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("int1_i")); // should match dynamic field "*_i"
assertNotNull(schema.getFieldOrNull("int2_i")); // should match dynamic field "*_i"
int value = 1089883491;
String intString1 = "1089883491";
String intString2 = "1,089,883,491";
SolrInputDocument d = processAdd("parse-int",
doc(f("id", "113"), f("int1_i", intString1), f("int2_i", intString2)));
assertNotNull(d);
assertThat(d.getFieldValue("int1_i"), IS_INTEGER);
assertEquals(value, ((Integer)d.getFieldValue("int1_i")).intValue());
assertThat(d.getFieldValue("int2_i"), IS_INTEGER);
assertEquals(value, ((Integer)d.getFieldValue("int2_i")).intValue());
assertU(commit());
assertQ(req("id:113")
,"//int[@name='int1_i'][.='" + value + "']"
,"//int[@name='int2_i'][.='" + value + "']");
}
public void testParseIntNonRootLocale() throws Exception {
final DecimalFormatSymbols ru_RU = DecimalFormatSymbols.getInstance(new Locale("ru","RU"));
final char groupChar = ru_RU.getGroupingSeparator();
int value = 1089883491;
String intString1 = "1089883491";
String intString2 = "1"+groupChar+"089"+groupChar+"883"+groupChar+"491";
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("int_i")); // should match dynamic field "*_i"
assertNull(schema.getFieldOrNull("not_in_schema"));
SolrInputDocument d = processAdd("parse-int-russian-no-run-processor",
doc(f("id", "113"), f("int_i", intString1), f("not_in_schema", intString2)));
assertNotNull(d);
assertThat(d.getFieldValue("int_i"), IS_INTEGER);
assertEquals(value, ((Integer)d.getFieldValue("int_i")).intValue());
assertThat(d.getFieldValue("not_in_schema"), IS_INTEGER);
assertEquals(value, ((Integer)d.getFieldValue("not_in_schema")).intValue());
}
public void testParseTrieIntRoundTrip() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("int1_ti")); // should match dynamic field "*_ti"
assertNotNull(schema.getFieldOrNull("int2_ti")); // should match dynamic field "*_ti"
int value = 1089883491;
String intString1 = "1089883491";
String intString2 = "1,089,883,491";
SolrInputDocument d = processAdd("parse-int",
doc(f("id", "113"), f("int1_ti", intString1), f("int2_ti", intString2)));
assertNotNull(d);
assertThat(d.getFieldValue("int1_ti"), IS_INTEGER);
assertEquals(value, ((Integer)d.getFieldValue("int1_ti")).intValue());
assertThat(d.getFieldValue("int2_ti"), IS_INTEGER);
assertEquals(value, ((Integer)d.getFieldValue("int2_ti")).intValue());
assertU(commit());
assertQ(req("id:113")
,"//int[@name='int1_ti'][.='" + value + "']"
,"//int[@name='int2_ti'][.='" + value + "']");
}
public void testIntOverflow() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNull(schema.getFieldOrNull("not_in_schema1"));
assertNull(schema.getFieldOrNull("not_in_schema2"));
long longValue1 = (long)Integer.MAX_VALUE + 100L;
long longValue2 = (long)Integer.MIN_VALUE - 100L;
String longString1 = Long.toString(longValue1);
String longString2 = Long.toString(longValue2);
SolrInputDocument d = processAdd("parse-int-no-run-processor",
doc(f("id", "282"), f("not_in_schema1", longString1), f("not_in_schema2", longString2)));
assertNotNull(d);
assertThat(d.getFieldValue("not_in_schema1"), IS_STRING);
assertThat(d.getFieldValue("not_in_schema2"), IS_STRING);
}
public void testFailedParseMixedInt() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNull(schema.getFieldOrNull("not_in_schema"));
Map<Object,Object> mixed = new HashMap<>();
Float floatVal = 294423.0f;
mixed.put(85, "85");
mixed.put(floatVal, floatVal); // Float-typed field value
mixed.put(-2894518, "-2,894,518");
mixed.put(1879472193, "1,879,472,193");
SolrInputDocument d = processAdd("parse-int-no-run-processor",
doc(f("id", "7202"), f("not_in_schema", mixed.values())));
assertNotNull(d);
boolean foundFloat = false;
for (Object o : d.getFieldValues("not_in_schema")) {
if (floatVal == o) {
foundFloat = true;
} else {
assertThat(o, IS_STRING);
}
mixed.values().remove(o);
}
assertTrue(foundFloat);
assertTrue(mixed.isEmpty());
}
public void testParseLongRoundTrip() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("long1_l")); // should match dynamic field "*_l"
assertNotNull(schema.getFieldOrNull("long2_l")); // should match dynamic field "*_l"
long value = 1089883491L;
String longString1 = "1089883491";
String longString2 = "1,089,883,491";
SolrInputDocument d = processAdd("parse-long",
doc(f("id", "113"), f("long1_l", longString1), f("long2_l", longString2)));
assertNotNull(d);
assertThat(d.getFieldValue("long1_l"), IS_LONG);
assertEquals(value, ((Long) d.getFieldValue("long1_l")).longValue());
assertThat(d.getFieldValue("long2_l"), IS_LONG);
assertEquals(value, ((Long)d.getFieldValue("long2_l")).longValue());
assertU(commit());
assertQ(req("id:113")
,"//long[@name='long1_l'][.='" + value + "']"
,"//long[@name='long2_l'][.='" + value + "']");
}
public void testParseLongNonRootLocale() throws Exception {
final DecimalFormatSymbols ru_RU = DecimalFormatSymbols.getInstance(new Locale("ru","RU"));
final char groupChar = ru_RU.getGroupingSeparator();
long value = 1089883491L;
String longString1 = "1089883491";
String longString2 = "1"+groupChar+"089"+groupChar+"883"+groupChar+"491";
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("long_l")); // should match dynamic field "*_l"
assertNull(schema.getFieldOrNull("not_in_schema"));
SolrInputDocument d = processAdd("parse-long-russian-no-run-processor",
doc(f("id", "113"), f("long_l", longString1), f("not_in_schema", longString2)));
assertNotNull(d);
assertThat(d.getFieldValue("long_l"), IS_LONG);
assertEquals(value, ((Long)d.getFieldValue("long_l")).longValue());
assertThat(d.getFieldValue("not_in_schema"), IS_LONG);
assertEquals(value, ((Long)d.getFieldValue("not_in_schema")).longValue());
}
public void testParseTrieLongRoundTrip() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("long1_tl")); // should match dynamic field "*_tl"
assertNotNull(schema.getFieldOrNull("long2_tl")); // should match dynamic field "*_tl"
long value = 1089883491L;
String longString1 = "1089883491";
String longString2 = "1,089,883,491";
SolrInputDocument d = processAdd("parse-long",
doc(f("id", "113"), f("long1_tl", longString1), f("long2_tl", longString2)));
assertNotNull(d);
assertThat(d.getFieldValue("long1_tl"), IS_LONG);
assertEquals(value, ((Long)d.getFieldValue("long1_tl")).longValue());
assertThat(d.getFieldValue("long2_tl"), IS_LONG);
assertEquals(value, ((Long)d.getFieldValue("long2_tl")).longValue());
assertU(commit());
assertQ(req("id:113")
,"//long[@name='long1_tl'][.='" + value + "']"
,"//long[@name='long2_tl'][.='" + value + "']");
}
public void testFailedParseMixedLong() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNull(schema.getFieldOrNull("not_in_schema"));
Map<Object,Object> mixed = new HashMap<>();
Float floatVal = 294423.0f;
mixed.put(85L, "85");
mixed.put(floatVal, floatVal); // Float-typed field value
mixed.put(-2894518L, "-2,894,518");
mixed.put(1879472193L, "1,879,472,193");
SolrInputDocument d = processAdd("parse-long-no-run-processor",
doc(f("id", "7204"), f("not_in_schema", mixed.values())));
assertNotNull(d);
boolean foundFloat = false;
for (Object o : d.getFieldValues("not_in_schema")) {
if (floatVal == o) {
foundFloat = true;
} else {
assertThat(o, IS_STRING);
}
mixed.values().remove(o);
}
assertTrue(foundFloat);
assertTrue(mixed.isEmpty());
}
public void testParseFloatRoundTrip() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("float1_f")); // should match dynamic field "*_f"
assertNotNull(schema.getFieldOrNull("float2_f")); // should match dynamic field "*_f"
float value = 10898.83491f;
String floatString1 = "10898.83491";
String floatString2 = "10,898.83491";
SolrInputDocument d = processAdd("parse-float",
doc(f("id", "128"), f("float1_f", floatString1), f("float2_f", floatString2)));
assertNotNull(d);
assertThat(d.getFieldValue("float1_f"), IS_FLOAT);
assertEquals(value, (Float)d.getFieldValue("float1_f"), EPSILON);
assertThat(d.getFieldValue("float2_f"), IS_FLOAT);
assertEquals(value, (Float)d.getFieldValue("float2_f"), EPSILON);
assertU(commit());
assertQ(req("id:128")
,"//float[@name='float1_f'][.='" + value + "']"
,"//float[@name='float2_f'][.='" + value + "']");
}
public void testParseFloatNonRootLocale() throws Exception {
final DecimalFormatSymbols fr_FR = DecimalFormatSymbols.getInstance(new Locale("fr","FR"));
final char groupChar = fr_FR.getGroupingSeparator();
final char decimalChar = fr_FR.getDecimalSeparator();
float value = 10898.83491F;
String floatString1 = "10898"+decimalChar+"83491";
String floatString2 = "10"+groupChar+"898"+decimalChar+"83491";
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("float_f")); // should match dynamic field "*_f"
assertNull(schema.getFieldOrNull("not_in_schema"));
SolrInputDocument d = processAdd("parse-float-french-no-run-processor",
doc(f("id", "140"), f("float_f", floatString1),
f("not_in_schema", floatString2)));
assertNotNull(d);
assertThat(d.getFieldValue("float_f"), IS_FLOAT);
assertEquals(value, (Float)d.getFieldValue("float_f"), EPSILON);
assertThat(d.getFieldValue("not_in_schema"), IS_FLOAT);
assertEquals(value, (Float)d.getFieldValue("not_in_schema"), EPSILON);
}
public void testParseTrieFloatRoundTrip() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("float1_tf")); // should match dynamic field "*_tf"
assertNotNull(schema.getFieldOrNull("float2_tf")); // should match dynamic field "*_tf"
float value = 10898.83491f;
String floatString1 = "10898.83491";
String floatString2 = "10,898.83491";
SolrInputDocument d = processAdd("parse-float",
doc(f("id", "728"), f("float1_tf", floatString1), f("float2_tf", floatString2)));
assertNotNull(d);
assertThat(d.getFieldValue("float1_tf"), IS_FLOAT);
assertEquals(value, (Float)d.getFieldValue("float1_tf"), EPSILON);
assertThat(d.getFieldValue("float2_tf"), IS_FLOAT);
assertEquals(value, (Float)d.getFieldValue("float2_tf"), EPSILON);
assertU(commit());
assertQ(req("id:728")
,"//float[@name='float1_tf'][.='" + value + "']"
,"//float[@name='float2_tf'][.='" + value + "']");
}
public void testMixedFloats() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("float_tf")); // should match dynamic field "*_tf"
Map<Float,Object> mixedFloats = new HashMap<>();
mixedFloats.put(85.0f, "85");
mixedFloats.put(2894518.0f, "2,894,518");
mixedFloats.put(2.94423E-9f, 2.94423E-9f); // Float-typed field value
mixedFloats.put(48794721.937f, "48,794,721.937");
SolrInputDocument d = processAdd("parse-float-no-run-processor",
doc(f("id", "342"), f("float_tf", mixedFloats.values())));
assertNotNull(d);
for (Object o : d.getFieldValues("float_tf")) {
assertThat(o, IS_FLOAT);
mixedFloats.remove(o);
}
assertTrue(mixedFloats.isEmpty());
}
public void testFailedParseMixedFloat() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNull(schema.getFieldOrNull("not_in_schema"));
Map<Object,Object> mixed = new HashMap<>();
Long longVal = 294423L;
mixed.put(85L, "85");
mixed.put(longVal, longVal); // Float-typed field value
mixed.put(-2894518L, "-2,894,518");
mixed.put(1879472193L, "1,879,472,193");
SolrInputDocument d = processAdd("parse-float-no-run-processor",
doc(f("id", "7205"), f("not_in_schema", mixed.values())));
assertNotNull(d);
boolean foundLong = false;
for (Object o : d.getFieldValues("not_in_schema")) {
if (longVal == o) {
foundLong = true;
} else {
assertThat(o, IS_STRING);
}
mixed.values().remove(o);
}
assertTrue(foundLong);
assertTrue(mixed.isEmpty());
}
public void testParseDoubleRoundTrip() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("double1_d")); // should match dynamic field "*_d"
assertNotNull(schema.getFieldOrNull("double2_d")); // should match dynamic field "*_d"
double value = 10898.83491;
String doubleString1 = "10898.83491";
String doubleString2 = "10,898.83491";
SolrInputDocument d = processAdd("parse-double",
doc(f("id", "128"), f("double1_d", doubleString1), f("double2_d", doubleString2)));
assertNotNull(d);
assertThat(d.getFieldValue("double1_d"), IS_DOUBLE);
assertEquals(value, (Double)d.getFieldValue("double1_d"), EPSILON);
assertThat(d.getFieldValue("double2_d"), IS_DOUBLE);
assertEquals(value, (Double)d.getFieldValue("double2_d"), EPSILON);
assertU(commit());
assertQ(req("id:128")
,"//double[@name='double1_d'][.='" + value + "']"
,"//double[@name='double2_d'][.='" + value + "']");
}
public void testParseDoubleNonRootLocale() throws Exception {
final DecimalFormatSymbols fr_FR = DecimalFormatSymbols.getInstance(new Locale("fr","FR"));
final char groupChar = fr_FR.getGroupingSeparator();
final char decimalChar = fr_FR.getDecimalSeparator();
double value = 10898.83491D;
String doubleString1 = "10898"+decimalChar+"83491";
String doubleString2 = "10"+groupChar+"898"+decimalChar+"83491";
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("double_d")); // should match dynamic field "*_d"
assertNull(schema.getFieldOrNull("not_in_schema"));
SolrInputDocument d = processAdd("parse-double-french-no-run-processor",
doc(f("id", "140"), f("double_d", doubleString1),
f("not_in_schema", doubleString2)));
assertNotNull(d);
assertThat(d.getFieldValue("double_d"), IS_DOUBLE);
assertEquals(value, (Double)d.getFieldValue("double_d"), EPSILON);
assertThat(d.getFieldValue("not_in_schema"), IS_DOUBLE);
assertEquals(value, (Double)d.getFieldValue("not_in_schema"), EPSILON);
}
public void testParseTrieDoubleRoundTrip() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("double1_td")); // should match dynamic field "*_td"
assertNotNull(schema.getFieldOrNull("double2_td")); // should match dynamic field "*_td"
double value = 10898.83491;
String doubleString1 = "10898.83491";
String doubleString2 = "10,898.83491";
SolrInputDocument d = processAdd("parse-double",
doc(f("id", "728"), f("double1_td", doubleString1), f("double2_td", doubleString2)));
assertNotNull(d);
assertThat(d.getFieldValue("double1_td"), IS_DOUBLE);
assertEquals(value, (Double)d.getFieldValue("double1_td"), EPSILON);
assertThat(d.getFieldValue("double2_td"), IS_DOUBLE);
assertEquals(value, (Double)d.getFieldValue("double2_td"), EPSILON);
assertU(commit());
assertQ(req("id:728")
,"//double[@name='double1_td'][.='" + value + "']"
,"//double[@name='double2_td'][.='" + value + "']");
}
public void testFailedParseMixedDouble() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNull(schema.getFieldOrNull("not_in_schema"));
Map<Object,Object> mixed = new HashMap<>();
Long longVal = 294423L;
mixed.put(85, "85.0");
mixed.put(longVal, longVal); // Float-typed field value
mixed.put(-2894.518, "-2,894.518");
mixed.put(187947.2193, "187,947.2193");
SolrInputDocument d = processAdd("parse-double-no-run-processor",
doc(f("id", "7206"), f("not_in_schema", mixed.values())));
assertNotNull(d);
boolean foundLong = false;
for (Object o : d.getFieldValues("not_in_schema")) {
if (longVal == o) {
foundLong = true;
} else {
assertThat(o, IS_STRING);
}
mixed.values().remove(o);
}
assertTrue(foundLong);
assertTrue(mixed.isEmpty());
}
public void testParseBooleanRoundTrip() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("boolean1_b")); // should match dynamic field "*_b"
assertNotNull(schema.getFieldOrNull("boolean2_b")); // should match dynamic field "*_b"
boolean value1 = true;
boolean value2 = false;
SolrInputDocument d = processAdd("parse-boolean",
doc(f("id", "141"), f("boolean1_b", value1), f("boolean2_b", value2)));
assertNotNull(d);
assertThat(d.getFieldValue("boolean1_b"), IS_BOOLEAN);
assertEquals(value1, d.getFieldValue("boolean1_b"));
assertThat(d.getFieldValue("boolean2_b"), IS_BOOLEAN);
assertEquals(value2, d.getFieldValue("boolean2_b"));
assertU(commit());
assertQ(req("id:141")
,"//bool[@name='boolean1_b'][.='" + value1 + "']"
,"//bool[@name='boolean2_b'][.='" + value2 + "']");
}
public void testParseAlternateValueBooleans() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("boolean1_b")); // should match dynamic field "*_b"
assertNotNull(schema.getFieldOrNull("boolean2_b")); // should match dynamic field "*_b"
assertNotNull(schema.getFieldOrNull("boolean3_b")); // should match dynamic field "*_b"
assertNotNull(schema.getFieldOrNull("boolean4_b")); // should match dynamic field "*_b"
assertNotNull(schema.getFieldOrNull("boolean5_b")); // should match dynamic field "*_b"
assertNull(schema.getFieldOrNull("not_in_schema"));
boolean[] values = { true, true, true, false, false, false };
String[] stringValues = { "on", "yes", "True", "Off", "no", "FALSE" };
String[] fieldNames = { "boolean1_b", "boolean2_b", "boolean3_b", "boolean4_b", "boolean5_b", "not_in_schema" };
SolrInputDocument d = doc(f("id", "55"));
for (int i = 0 ; i < values.length ; ++i) {
d.addField(fieldNames[i], stringValues[i]);
}
d = processAdd("parse-boolean-alternate-values-no-run-processor", d);
assertNotNull(d);
for (int i = 0 ; i < values.length ; ++i) {
assertThat(d.getFieldValue(fieldNames[i]), IS_BOOLEAN);
assertEquals(values[i], d.getFieldValue(fieldNames[i]));
}
}
public void testParseAlternateSingleValuesBooleans() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("boolean1_b")); // should match dynamic field "*_b"
assertNotNull(schema.getFieldOrNull("boolean2_b")); // should match dynamic field "*_b"
boolean[] values = { true, false };
String[] stringValues = { "yup", "nope" };
String[] fieldNames = { "boolean1_b", "boolean2_b" };
SolrInputDocument d = doc(f("id", "59"));
for (int i = 0 ; i < values.length ; ++i) {
d.addField(fieldNames[i], stringValues[i]);
}
d = processAdd("parse-boolean-alternate-single-values-no-run-processor", d);
assertNotNull(d);
for (int i = 0 ; i < values.length ; ++i) {
assertThat(d.getFieldValue(fieldNames[i]), IS_BOOLEAN);
assertEquals(values[i], d.getFieldValue(fieldNames[i]));
}
// Standard boolean values should not be mutated, since they're not configured
stringValues = new String[] { "true", "false" };
d = doc(f("id", "593"));
for (int i = 0 ; i < values.length ; ++i) {
d.addField(fieldNames[i], stringValues[i]);
}
d = processAdd("parse-boolean-alternate-single-values-no-run-processor", d);
assertNotNull(d);
for (int i = 0 ; i < values.length ; ++i) {
assertThat(d.getFieldValue(fieldNames[i]), IS_STRING);
}
}
public void testFailedParseMixedBoolean() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
assertNull(schema.getFieldOrNull("not_in_schema"));
Map<Object,Object> mixed = new HashMap<>();
Long longVal = 294423L;
mixed.put(true, "true");
mixed.put(longVal, longVal); // Float-typed field value
mixed.put(false, "false");
mixed.put(true, "true");
SolrInputDocument d = processAdd("parse-boolean-no-run-processor",
doc(f("id", "7207"), f("not_in_schema", mixed.values())));
assertNotNull(d);
boolean foundLong = false;
for (Object o : d.getFieldValues("not_in_schema")) {
if (longVal == o) {
foundLong = true;
} else {
assertThat(o, IS_STRING);
}
mixed.values().remove(o);
}
assertTrue(foundLong);
assertTrue(mixed.isEmpty());
}
public void testCascadingParsers() throws Exception {
IndexSchema schema = h.getCore().getLatestSchema();
final String fieldName = "not_in_schema";
assertNull(schema.getFieldOrNull(fieldName));
SolrInputDocument d = null;
String chain = "cascading-parsers-no-run-processor";
Map<Boolean,String> booleans = new HashMap<>();
booleans.put(true, "truE");
booleans.put(false, "False");
d = processAdd(chain, doc(f("id", "341"), f(fieldName, booleans.values())));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertThat(o, IS_BOOLEAN);
booleans.remove(o);
}
assertTrue(booleans.isEmpty());
Map<Integer,String> ints = new HashMap<>();
ints.put(2, "2");
ints.put(50928, "50928");
ints.put(86942008, "86,942,008");
d = processAdd(chain, doc(f("id", "333"), f(fieldName, ints.values())));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertThat(o, IS_INTEGER);
ints.remove(o);
}
assertTrue(ints.isEmpty());
Map<Long,String> longs = new HashMap<>();
longs.put(2L, "2");
longs.put(50928L, "50928");
longs.put(86942008987654L, "86,942,008,987,654");
d = processAdd(chain, doc(f("id", "342"), f(fieldName, longs.values())));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertThat(o, IS_LONG);
longs.remove(o);
}
assertTrue(longs.isEmpty());
/*
// Disabling this test because unlike Integer/Long, Float parsing can perform
// rounding to make values fit. See
Map<Float,String> floats = new HashMap<Float,String>();
floats.put(2.0, "2.");
floats.put(509.28, "509.28");
floats.put(86942.008, "86,942.008");
d = processAdd(chain, doc(f("id", "342"), f(fieldName, floats.values())));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertTrue(o instanceof float);
longs.remove(o);
}
*/
Map<Double,String> doubles = new HashMap<>();
doubles.put(2.0, "2.");
doubles.put(509.28, "509.28");
doubles.put(86942.008, "86,942.008");
d = processAdd(chain, doc(f("id", "342"), f(fieldName, doubles.values())));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertThat(o, IS_DOUBLE);
longs.remove(o);
}
Map<Date,String> dates = new HashMap<>();
String[] dateStrings = { "2020-05-13T18:47", "1989-12-14", "1682-07-22T18:33:00.000Z" };
for (String dateString : dateStrings) {
dates.put(parse(isoDateOptionalTimeFormatter, dateString), dateString);
}
d = processAdd(chain, doc(f("id", "343"), f(fieldName, dates.values())));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertThat(o, IS_DATE);
dates.remove(o);
}
assertTrue(dates.isEmpty());
Map<Double,String> mixedLongsAndDoubles = new LinkedHashMap<>(); // preserve order
mixedLongsAndDoubles.put(85.0, "85");
mixedLongsAndDoubles.put(2.94423E-9, "2.94423E-9");
mixedLongsAndDoubles.put(2894518.0, "2,894,518");
mixedLongsAndDoubles.put(48794721.937, "48,794,721.937");
d = processAdd(chain, doc(f("id", "344"), f(fieldName, mixedLongsAndDoubles.values())));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertThat(o, IS_DOUBLE);
mixedLongsAndDoubles.remove(o);
}
assertTrue(mixedLongsAndDoubles.isEmpty());
Set<String> mixed = new HashSet<>();
mixed.add("true");
mixed.add("1682-07-22T18:33:00.000Z");
mixed.add("2,894,518");
mixed.add("308,393,131,379,900");
mixed.add("48,794,721.937");
d = processAdd(chain, doc(f("id", "345"), f(fieldName, mixed)));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertThat(o, IS_STRING);
}
Map<Double,Object> mixedDoubles = new LinkedHashMap<>(); // preserve order
mixedDoubles.put(85.0, "85");
mixedDoubles.put(2.94423E-9, 2.94423E-9); // Double-typed field value
mixedDoubles.put(2894518.0, "2,894,518");
mixedDoubles.put(48794721.937, "48,794,721.937");
d = processAdd(chain, doc(f("id", "3391"), f(fieldName, mixedDoubles.values())));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertThat(o, IS_DOUBLE);
mixedDoubles.remove(o);
}
assertTrue(mixedDoubles.isEmpty());
Map<Integer,Object> mixedInts = new LinkedHashMap<>(); // preserve order
mixedInts.put(85, "85");
mixedInts.put(294423, 294423); // Integer-typed field value
mixedInts.put(-2894518, "-2,894,518");
mixedInts.put(1879472193, "1,879,472,193");
d = processAdd(chain, doc(f("id", "3392"), f(fieldName, mixedInts.values())));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertThat(o, IS_INTEGER);
mixedInts.remove(o);
}
assertTrue(mixedInts.isEmpty());
Map<Long,Object> mixedLongs = new LinkedHashMap<>(); // preserve order
mixedLongs.put(85L, "85");
mixedLongs.put(42944233L, 42944233L); // Long-typed field value
mixedLongs.put(2894518L, "2,894,518");
mixedLongs.put(48794721937L, "48,794,721,937");
d = processAdd(chain, doc(f("id", "3393"), f(fieldName, mixedLongs.values())));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertThat(o, IS_LONG);
mixedLongs.remove(o);
}
assertTrue(mixedLongs.isEmpty());
Map<Boolean,Object> mixedBooleans = new LinkedHashMap<>(); // preserve order
mixedBooleans.put(true, "true");
mixedBooleans.put(false, false); // Boolean-typed field value
mixedBooleans.put(false, "false");
mixedBooleans.put(true, "true");
d = processAdd(chain, doc(f("id", "3394"), f(fieldName, mixedBooleans.values())));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertThat(o, IS_BOOLEAN);
mixedBooleans.remove(o);
}
assertTrue(mixedBooleans.isEmpty());
Map<Date,Object> mixedDates = new HashMap<>();
dateStrings = new String[] { "2020-05-13T18:47", "1989-12-14", "1682-07-22T18:33:00.000Z" };
for (String dateString : dateStrings) {
mixedDates.put(parse(isoDateOptionalTimeFormatter, dateString), dateString);
}
Date extraDate = parse(isoDateOptionalTimeFormatter, "2003-04-24");
mixedDates.put(extraDate, extraDate); // Date-typed field value
d = processAdd(chain, doc(f("id", "3395"), f(fieldName, mixedDates.values())));
assertNotNull(d);
for (Object o : d.getFieldValues(fieldName)) {
assertThat(o, IS_DATE);
mixedDates.remove(o);
}
assertTrue(mixedDates.isEmpty());
}
// tests that mimic the tests that were in TestExtractionDateUtil
public void testISO8601() throws IOException {
// dates with atypical years
// This test tries to mimic TestExtractionDateUtil#testISO8601
String[] dateStrings = {
"0001-01-01T01:01:01Z", "+12021-12-01T03:03:03Z",
"0000-04-04T04:04:04Z", "-0005-05-05T05:05:05Z",
"-2021-12-01T04:04:04Z", "-12021-12-01T02:02:02Z"
};
int id = 1;
// ensure strings are parsed
for(String notInFormatDateString: dateStrings) {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("date_dt")); // should match "*_dt" dynamic field
SolrInputDocument d = processAdd("parse-date-patterns-default-config", doc(f("id", id), f("date_dt", notInFormatDateString)));
assertNotNull(d);
assertThat("Date string: " + notInFormatDateString + " was not parsed as a date", d.getFieldValue("date_dt"), IS_DATE);
assertEquals(notInFormatDateString, ((Date) d.getField("date_dt").getFirstValue()).toInstant().toString());
assertU(commit());
assertQ(req("id:" + id), "//date[@name='date_dt'][.='" + notInFormatDateString + "']");
++id;
}
// odd values are date strings, even values are expected strings
String[] lenientDateStrings = {
"10995-12-31T23:59:59.990Z", "+10995-12-31T23:59:59.990Z",
"995-1-2T3:4:5Z", "0995-01-02T03:04:05Z",
"2021-01-01t03:04:05", "2021-01-01T03:04:05Z",
"2021-12-01 04:04:04", "2021-12-01T04:04:04Z"
};
// ensure sure strings that should be parsed using lenient resolver are properly parsed
for(int i = 0; i < lenientDateStrings.length; ++i) {
String lenientDateString = lenientDateStrings[i];
String expectedString = lenientDateStrings[++i];
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("date_dt")); // should match "*_dt" dynamic field
SolrInputDocument d = processAdd("parse-date-patterns-default-config", doc(f("id", id), f("date_dt", lenientDateString)));
assertNotNull(d);
assertThat("Date string: " + lenientDateString + " was not parsed as a date",
d.getFieldValue("date_dt"), IS_DATE);
assertEquals(expectedString, ((Date) d.getField("date_dt").getFirstValue()).toInstant().toString());
++id;
}
}
// this test has had problems when the JDK timezone is Americas/Metlakatla
public void testAKSTZone() throws IOException {
final String dateFormat = "EEE MMM d HH:mm:ss z yyyy";
final String inputString = "Thu Nov 13 04:35:51 AKST 2008"; // asctime + timezone1
final long expectTs = 1226583351000L;
assertEquals(expectTs,
DateTimeFormatter.ofPattern(dateFormat, Locale.ENGLISH)
.withZone(ZoneId.of("UTC")).parse(inputString, Instant::from).toEpochMilli());
// ensure english locale and root locale return the same date
assertEquals(expectTs + "", DateTimeFormatter.ofPattern(dateFormat, Locale.ENGLISH)
.withZone(ZoneId.of("UTC")).parse(inputString, Instant::from).toEpochMilli(),
DateTimeFormatter.ofPattern(dateFormat, Locale.ROOT)
.withZone(ZoneId.of("UTC")).parse(inputString, Instant::from).toEpochMilli());
assertParsedDate(inputString, Date.from(Instant.ofEpochMilli(expectTs)), "parse-date-patterns-default-config");
// A bug in Java 9 (not in 8) causes this to fail! (not fixed yet?!)
// see https://bugs.openjdk.java.net/browse/JDK-8189784
if (System.getProperty("java.version").startsWith("1.8.")) {
// with daylight savings time timezone
assertParsedDate("Fri Oct 7 05:14:15 AKDT 2005", Date.from(inst20051007131415()), "parse-date-patterns-default-config");
} else {
System.err.println("Didn't test AKDT because only Java 1.8 does this right! This Java version is: " + System.getProperty("java.version"));
}
}
public void testEDTZone() throws IOException {
//EDT is GMT-4
assertParsedDate("Fri Oct 7 09:14:15 EDT 2005", // asctime + timezone
Date.from(inst20051007131415()), "parse-date-patterns-default-config");
}
public void testNoTime() throws IOException {
Instant instant = instant(2005, 10, 7, 0, 0, 0);
String inputString = "2005-10-07";
assertParsedDate(inputString, Date.from(instant), "parse-date-patterns-default-config");
}
public void testRfc1123() throws IOException {
assertParsedDate("Fri, 07 Oct 2005 13:14:15 GMT", Date.from(inst20051007131415()), "parse-date-patterns-default-config");
}
public void testRfc1036() throws IOException {
assertParsedDate("Friday, 07-Oct-05 13:14:15 GMT", Date.from(inst20051007131415()), "parse-date-patterns-default-config");
}
public void testAsctime() throws Exception {
assertParsedDate("Fri Oct 7 13:14:15 2005" , Date.from(inst20051007131415()), "parse-date-patterns-default-config");
// also see testEDTZone
}
public void testAsctimeLeniency() throws Exception {
// test double digit day
assertParsedDate("Fri Oct 07 13:14:15 2005" , Date.from(inst20051007131415()), "parse-date-patterns-default-config");
// test 2 spaces left of a single digit day
assertParsedDate("Fri Oct 7 13:14:15 2005" , Date.from(inst20051007131415()), "parse-date-patterns-default-config");
// longer day of week
assertParsedDate("Friday Oct 7 13:14:15 2005", Date.from(inst20051007131415()), "parse-date-patterns-default-config");
}
public void testParseQuotedDate() throws IOException {
// also using 2 digit day
assertParsedDate("'Fri, 14 Oct 2005 13:14:15 GMT'",
Date.from(instant(2005, 10, 14, 13, 14, 15)), "parse-date-patterns-default-config");
}
private static Instant instant(final int year, final int month, final int day, int hour, int minute, int second) {
return LocalDate.of(year, month, day).atTime(hour, minute, second).toInstant(ZoneOffset.UTC);
}
private Instant inst20051007131415() {
return instant(2005, 10, 7, 13, 14, 15);
}
private void assertParsedDate(String inputDateString, Date expectedDate, String chain) throws IOException {
IndexSchema schema = h.getCore().getLatestSchema();
assertNotNull(schema.getFieldOrNull("date_dt")); // should match "*_dt" dynamic field
SolrInputDocument d = processAdd(chain, doc(f("id", "1"), f("date_dt", inputDateString)));
assertNotNull(d);
assertThat("Date string: " + inputDateString + " was not parsed as a date",
d.getFieldValue("date_dt"), IS_DATE);
assertEquals(expectedDate, d.getField("date_dt").getFirstValue());
}
private static Date parse(DateTimeFormatter dateTimeFormatter, String dateString) {
final TemporalAccessor temporalAccessor = dateTimeFormatter.parseBest(dateString, OffsetDateTime::from,
ZonedDateTime::from, LocalDateTime::from, LocalDate::from, Instant::from);
return temporalToDate(temporalAccessor, dateTimeFormatter.getZone());
}
private static Date temporalToDate(TemporalAccessor in, ZoneId timeZoneId) {
if (in instanceof OffsetDateTime) {
return Date.from(((OffsetDateTime) in).toInstant());
} else if (in instanceof ZonedDateTime) {
return Date.from(((ZonedDateTime) in).toInstant());
} else if (in instanceof LocalDateTime) {
return Date.from(((LocalDateTime) in).atZone(timeZoneId).toInstant());
} else if (in instanceof Instant) {
return Date.from((Instant) in);
} else {
return Date.from(((LocalDate) in).atStartOfDay(timeZoneId).toInstant());
}
}
}