mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-25 09:28:27 +00:00
Speed up converting of temporal accessor to zoned date time (#37915)
The existing implementation was slow due to exceptions being thrown if an accessor did not have a time zone. This implementation queries for having a timezone, local time and local date and also checks for an instant preventing to throw an exception and thus speeding up the conversion. This removes the existing method and create a new one named DateFormatters.from(TemporalAccessor accessor) to resemble the naming of the java time ones. Before this change an epoch millis parser using the toZonedDateTime method took approximately 50x longer. Relates #37826
This commit is contained in:
parent
160d1bd4dd
commit
b94acb608b
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.elasticsearch.benchmark.time;
|
||||
|
||||
import org.elasticsearch.common.time.DateFormatter;
|
||||
import org.elasticsearch.common.time.DateFormatters;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Fork(3)
|
||||
@Warmup(iterations = 10)
|
||||
@Measurement(iterations = 10)
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@State(Scope.Benchmark)
|
||||
@SuppressWarnings("unused") //invoked by benchmarking framework
|
||||
public class DateFormatterFromBenchmark {
|
||||
|
||||
private final TemporalAccessor accessor = DateFormatter.forPattern("epoch_millis").parse("1234567890");
|
||||
|
||||
@Benchmark
|
||||
public TemporalAccessor benchmarkFrom() {
|
||||
// benchmark an accessor that does not contain a timezone
|
||||
// this used to throw an exception earlier and thus was very very slow
|
||||
return DateFormatters.from(accessor);
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ public final class TimeUtil {
|
||||
if (parser.currentToken() == XContentParser.Token.VALUE_NUMBER) {
|
||||
return new Date(parser.longValue());
|
||||
} else if (parser.currentToken() == XContentParser.Token.VALUE_STRING) {
|
||||
return new Date(DateFormatters.toZonedDateTime(DateTimeFormatter.ISO_INSTANT.parse(parser.text())).toInstant().toEpochMilli());
|
||||
return new Date(DateFormatters.from(DateTimeFormatter.ISO_INSTANT.parse(parser.text())).toInstant().toEpochMilli());
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"unexpected token [" + parser.currentToken() + "] for [" + fieldName + "]");
|
||||
|
@ -28,12 +28,23 @@ import org.joda.time.format.ISODateTimeFormat;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.time.temporal.TemporalAccessor;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
|
||||
import static java.time.temporal.ChronoField.HOUR_OF_DAY;
|
||||
import static java.time.temporal.ChronoField.MINUTE_OF_DAY;
|
||||
import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
|
||||
import static java.time.temporal.ChronoField.NANO_OF_SECOND;
|
||||
import static java.time.temporal.ChronoField.SECOND_OF_DAY;
|
||||
|
||||
enum DateFormat {
|
||||
Iso8601 {
|
||||
@Override
|
||||
@ -70,22 +81,37 @@ enum DateFormat {
|
||||
}
|
||||
},
|
||||
Java {
|
||||
private final List<ChronoField> FIELDS =
|
||||
Arrays.asList(NANO_OF_SECOND, SECOND_OF_DAY, MINUTE_OF_DAY, HOUR_OF_DAY, DAY_OF_MONTH, MONTH_OF_YEAR);
|
||||
|
||||
@Override
|
||||
Function<String, DateTime> getFunction(String format, DateTimeZone timezone, Locale locale) {
|
||||
|
||||
// support the 6.x BWC compatible way of parsing java 8 dates
|
||||
if (format.startsWith("8")) {
|
||||
format = format.substring(1);
|
||||
}
|
||||
|
||||
ZoneId zoneId = DateUtils.dateTimeZoneToZoneId(timezone);
|
||||
int year = LocalDate.now(ZoneOffset.UTC).getYear();
|
||||
DateFormatter formatter = DateFormatter.forPattern(format)
|
||||
.withLocale(locale)
|
||||
.withZone(DateUtils.dateTimeZoneToZoneId(timezone));
|
||||
.withZone(zoneId);
|
||||
return text -> {
|
||||
ZonedDateTime defaultZonedDateTime = Instant.EPOCH.atZone(ZoneOffset.UTC).withYear(year);
|
||||
TemporalAccessor accessor = formatter.parse(text);
|
||||
long millis = DateFormatters.toZonedDateTime(accessor, defaultZonedDateTime).toInstant().toEpochMilli();
|
||||
// if there is no year, we fall back to the current one and
|
||||
// fill the rest of the date up with the parsed date
|
||||
if (accessor.isSupported(ChronoField.YEAR) == false) {
|
||||
ZonedDateTime newTime = Instant.EPOCH.atZone(ZoneOffset.UTC).withYear(year);
|
||||
for (ChronoField field : FIELDS) {
|
||||
if (accessor.isSupported(field)) {
|
||||
newTime = newTime.with(field, accessor.get(field));
|
||||
}
|
||||
}
|
||||
|
||||
accessor = newTime.withZoneSameLocal(zoneId);
|
||||
}
|
||||
|
||||
long millis = DateFormatters.from(accessor).toInstant().toEpochMilli();
|
||||
return new DateTime(millis, timezone);
|
||||
};
|
||||
}
|
||||
|
@ -19,29 +19,43 @@
|
||||
|
||||
package org.elasticsearch.ingest.common;
|
||||
|
||||
import org.elasticsearch.common.time.DateUtils;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
|
||||
public class DateFormatTests extends ESTestCase {
|
||||
|
||||
public void testParseJoda() {
|
||||
Function<String, DateTime> jodaFunction = DateFormat.Java.getFunction("MMM dd HH:mm:ss Z",
|
||||
public void testParseJava() {
|
||||
Function<String, DateTime> javaFunction = DateFormat.Java.getFunction("MMM dd HH:mm:ss Z",
|
||||
DateTimeZone.forOffsetHours(-8), Locale.ENGLISH);
|
||||
assertThat(Instant.ofEpochMilli(jodaFunction.apply("Nov 24 01:29:01 -0800").getMillis())
|
||||
assertThat(Instant.ofEpochMilli(javaFunction.apply("Nov 24 01:29:01 -0800").getMillis())
|
||||
.atZone(ZoneId.of("GMT-8"))
|
||||
.format(DateTimeFormatter.ofPattern("MM dd HH:mm:ss", Locale.ENGLISH)),
|
||||
equalTo("11 24 01:29:01"));
|
||||
}
|
||||
|
||||
public void testParseJavaDefaultYear() {
|
||||
String format = randomFrom("8dd/MM", "dd/MM");
|
||||
DateTimeZone timezone = DateUtils.zoneIdToDateTimeZone(ZoneId.of("Europe/Amsterdam"));
|
||||
Function<String, DateTime> javaFunction = DateFormat.Java.getFunction(format, timezone, Locale.ENGLISH);
|
||||
int year = ZonedDateTime.now(ZoneOffset.UTC).getYear();
|
||||
DateTime dateTime = javaFunction.apply("12/06");
|
||||
assertThat(dateTime.getYear(), is(year));
|
||||
assertThat(dateTime.toString(), is(year + "-06-12T00:00:00.000+02:00"));
|
||||
}
|
||||
|
||||
public void testParseUnixMs() {
|
||||
assertThat(DateFormat.UnixMs.getFunction(null, DateTimeZone.UTC, null).apply("1000500").getMillis(), equalTo(1000500L));
|
||||
}
|
||||
|
@ -20,11 +20,13 @@
|
||||
package org.elasticsearch.common.time;
|
||||
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.Year;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
@ -1550,105 +1552,91 @@ public class DateFormatters {
|
||||
dateTimeFormatters.toArray(new DateTimeFormatter[0]));
|
||||
}
|
||||
|
||||
private static final ZonedDateTime EPOCH_ZONED_DATE_TIME = Instant.EPOCH.atZone(ZoneOffset.UTC);
|
||||
private static final LocalDate LOCALDATE_EPOCH = LocalDate.of(1970, 1, 1);
|
||||
|
||||
public static ZonedDateTime toZonedDateTime(TemporalAccessor accessor) {
|
||||
return toZonedDateTime(accessor, EPOCH_ZONED_DATE_TIME);
|
||||
}
|
||||
|
||||
public static ZonedDateTime toZonedDateTime(TemporalAccessor accessor, ZonedDateTime defaults) {
|
||||
try {
|
||||
return ZonedDateTime.from(accessor);
|
||||
} catch (DateTimeException e ) {
|
||||
/**
|
||||
* Convert a temporal accessor to a zoned date time object - as performant as possible.
|
||||
* The .from() methods from the JDK are throwing exceptions when for example ZonedDateTime.from(accessor)
|
||||
* or Instant.from(accessor). This results in a huge performance penalty and should be prevented
|
||||
* This method prevents exceptions by querying the accessor for certain capabilities
|
||||
* and then act on it accordingly
|
||||
*
|
||||
* This action assumes that we can reliably fall back to some defaults if not all parts of a
|
||||
* zoned date time are set
|
||||
*
|
||||
* - If a zoned date time is passed, it is returned
|
||||
* - If no timezone is found, ZoneOffset.UTC is used
|
||||
* - If we find a time and a date, converting to a ZonedDateTime is straight forward,
|
||||
* no defaults will be applied
|
||||
* - If an accessor only containing of seconds and nanos is found (like epoch_millis/second)
|
||||
* an Instant is created out of that, that becomes a ZonedDateTime with a time zone
|
||||
* - If no time is given, the start of the day is used
|
||||
* - If no month of the year is found, the first day of the year is used
|
||||
* - If an iso based weekyear is found, but not week is specified, the first monday
|
||||
* of the new year is chosen (reataining BWC to joda time)
|
||||
* - If an iso based weekyear is found and an iso based weekyear week, the start
|
||||
* of the day is used
|
||||
*
|
||||
* @param accessor The accessor returned from a parser
|
||||
*
|
||||
* @return The converted zoned date time
|
||||
*/
|
||||
public static ZonedDateTime from(TemporalAccessor accessor) {
|
||||
if (accessor instanceof ZonedDateTime) {
|
||||
return (ZonedDateTime) accessor;
|
||||
}
|
||||
|
||||
ZonedDateTime result = defaults;
|
||||
ZoneId zoneId = accessor.query(TemporalQueries.zone());
|
||||
if (zoneId == null) {
|
||||
zoneId = ZoneOffset.UTC;
|
||||
}
|
||||
|
||||
LocalDate localDate = accessor.query(TemporalQueries.localDate());
|
||||
LocalTime localTime = accessor.query(TemporalQueries.localTime());
|
||||
boolean isLocalDateSet = localDate != null;
|
||||
boolean isLocalTimeSet = localTime != null;
|
||||
|
||||
// special case epoch seconds
|
||||
if (accessor.isSupported(ChronoField.INSTANT_SECONDS)) {
|
||||
result = result.with(ChronoField.INSTANT_SECONDS, accessor.getLong(ChronoField.INSTANT_SECONDS));
|
||||
if (accessor.isSupported(ChronoField.NANO_OF_SECOND)) {
|
||||
result = result.with(ChronoField.NANO_OF_SECOND, accessor.getLong(ChronoField.NANO_OF_SECOND));
|
||||
// the first two cases are the most common, so this allows us to exit early when parsing dates
|
||||
if (isLocalDateSet && isLocalTimeSet) {
|
||||
return of(localDate, localTime, zoneId);
|
||||
} else if (accessor.isSupported(ChronoField.INSTANT_SECONDS) && accessor.isSupported(NANO_OF_SECOND)) {
|
||||
return Instant.from(accessor).atZone(zoneId);
|
||||
} else if (isLocalDateSet) {
|
||||
return localDate.atStartOfDay(zoneId);
|
||||
} else if (isLocalTimeSet) {
|
||||
return of(LOCALDATE_EPOCH, localTime, zoneId);
|
||||
} else if (accessor.isSupported(ChronoField.YEAR)) {
|
||||
if (accessor.isSupported(MONTH_OF_YEAR)) {
|
||||
return getFirstOfMonth(accessor).atStartOfDay(zoneId);
|
||||
} else {
|
||||
return Year.of(accessor.get(ChronoField.YEAR)).atDay(1).atStartOfDay(zoneId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// try to set current year
|
||||
if (accessor.isSupported(ChronoField.YEAR)) {
|
||||
result = result.with(ChronoField.YEAR, accessor.getLong(ChronoField.YEAR));
|
||||
} else if (accessor.isSupported(ChronoField.YEAR_OF_ERA)) {
|
||||
result = result.with(ChronoField.YEAR_OF_ERA, accessor.getLong(ChronoField.YEAR_OF_ERA));
|
||||
} else if (accessor.isSupported(WeekFields.ISO.weekBasedYear())) {
|
||||
if (accessor.isSupported(WeekFields.ISO.weekOfWeekBasedYear())) {
|
||||
return LocalDate.from(result)
|
||||
.with(WeekFields.ISO.weekBasedYear(), accessor.getLong(WeekFields.ISO.weekBasedYear()))
|
||||
.withDayOfMonth(1) // makes this compatible with joda
|
||||
return Year.of(accessor.get(WeekFields.ISO.weekBasedYear()))
|
||||
.atDay(1)
|
||||
.with(WeekFields.ISO.weekOfWeekBasedYear(), accessor.getLong(WeekFields.ISO.weekOfWeekBasedYear()))
|
||||
.atStartOfDay(ZoneOffset.UTC);
|
||||
.atStartOfDay(zoneId);
|
||||
} else {
|
||||
return LocalDate.from(result)
|
||||
.with(WeekFields.ISO.weekBasedYear(), accessor.getLong(WeekFields.ISO.weekBasedYear()))
|
||||
// this exists solely to be BWC compatible with joda
|
||||
// .with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY))
|
||||
return Year.of(accessor.get(WeekFields.ISO.weekBasedYear()))
|
||||
.atDay(1)
|
||||
.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY))
|
||||
.atStartOfDay(defaults.getZone());
|
||||
// return result.withHour(0).withMinute(0).withSecond(0)
|
||||
// .with(WeekFields.ISO.weekBasedYear(), 0)
|
||||
// .with(WeekFields.ISO.weekBasedYear(), accessor.getLong(WeekFields.ISO.weekBasedYear()));
|
||||
// return ((ZonedDateTime) tmp).with(WeekFields.ISO.weekOfWeekBasedYear(), 1);
|
||||
.atStartOfDay(zoneId);
|
||||
}
|
||||
} else if (accessor.isSupported(IsoFields.WEEK_BASED_YEAR)) {
|
||||
// special case weekbased year
|
||||
result = result.with(IsoFields.WEEK_BASED_YEAR, accessor.getLong(IsoFields.WEEK_BASED_YEAR));
|
||||
if (accessor.isSupported(IsoFields.WEEK_OF_WEEK_BASED_YEAR)) {
|
||||
result = result.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, accessor.getLong(IsoFields.WEEK_OF_WEEK_BASED_YEAR));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// month
|
||||
if (accessor.isSupported(ChronoField.MONTH_OF_YEAR)) {
|
||||
result = result.with(ChronoField.MONTH_OF_YEAR, accessor.getLong(ChronoField.MONTH_OF_YEAR));
|
||||
}
|
||||
// we should not reach this piece of code, everything being parsed we should be able to
|
||||
// convert to a zoned date time! If not, we have to extend the above methods
|
||||
throw new IllegalArgumentException("temporal accessor [" + accessor + "] cannot be converted to zoned date time");
|
||||
}
|
||||
|
||||
// day of month
|
||||
if (accessor.isSupported(ChronoField.DAY_OF_MONTH)) {
|
||||
result = result.with(ChronoField.DAY_OF_MONTH, accessor.getLong(ChronoField.DAY_OF_MONTH));
|
||||
}
|
||||
@SuppressForbidden(reason = "ZonedDateTime.of is fine here")
|
||||
private static ZonedDateTime of(LocalDate localDate, LocalTime localTime, ZoneId zoneId) {
|
||||
return ZonedDateTime.of(localDate, localTime, zoneId);
|
||||
}
|
||||
|
||||
// hour
|
||||
if (accessor.isSupported(ChronoField.HOUR_OF_DAY)) {
|
||||
result = result.with(ChronoField.HOUR_OF_DAY, accessor.getLong(ChronoField.HOUR_OF_DAY));
|
||||
}
|
||||
|
||||
// minute
|
||||
if (accessor.isSupported(ChronoField.MINUTE_OF_HOUR)) {
|
||||
result = result.with(ChronoField.MINUTE_OF_HOUR, accessor.getLong(ChronoField.MINUTE_OF_HOUR));
|
||||
}
|
||||
|
||||
// second
|
||||
if (accessor.isSupported(ChronoField.SECOND_OF_MINUTE)) {
|
||||
result = result.with(ChronoField.SECOND_OF_MINUTE, accessor.getLong(ChronoField.SECOND_OF_MINUTE));
|
||||
}
|
||||
|
||||
if (accessor.isSupported(ChronoField.OFFSET_SECONDS)) {
|
||||
result = result.withZoneSameLocal(ZoneOffset.ofTotalSeconds(accessor.get(ChronoField.OFFSET_SECONDS)));
|
||||
}
|
||||
|
||||
// millis
|
||||
if (accessor.isSupported(ChronoField.MILLI_OF_SECOND)) {
|
||||
result = result.with(ChronoField.MILLI_OF_SECOND, accessor.getLong(ChronoField.MILLI_OF_SECOND));
|
||||
}
|
||||
|
||||
if (accessor.isSupported(ChronoField.NANO_OF_SECOND)) {
|
||||
result = result.with(ChronoField.NANO_OF_SECOND, accessor.getLong(ChronoField.NANO_OF_SECOND));
|
||||
}
|
||||
|
||||
ZoneId zoneOffset = accessor.query(TemporalQueries.zone());
|
||||
if (zoneOffset != null) {
|
||||
result = result.withZoneSameLocal(zoneOffset);
|
||||
}
|
||||
|
||||
return result;
|
||||
@SuppressForbidden(reason = "LocalDate.of is fine here")
|
||||
private static LocalDate getFirstOfMonth(TemporalAccessor accessor) {
|
||||
return LocalDate.of(accessor.get(ChronoField.YEAR), accessor.get(MONTH_OF_YEAR), 1);
|
||||
}
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ public class JavaDateMathParser implements DateMathParser {
|
||||
DateTimeFormatter formatter = roundUpIfNoTime ? this.roundUpFormatter : this.formatter;
|
||||
try {
|
||||
if (timeZone == null) {
|
||||
return DateFormatters.toZonedDateTime(formatter.parse(value)).toInstant();
|
||||
return DateFormatters.from(formatter.parse(value)).toInstant();
|
||||
} else {
|
||||
TemporalAccessor accessor = formatter.parse(value);
|
||||
ZoneId zoneId = TemporalQueries.zone().queryFrom(accessor);
|
||||
@ -226,7 +226,7 @@ public class JavaDateMathParser implements DateMathParser {
|
||||
timeZone = zoneId;
|
||||
}
|
||||
|
||||
return DateFormatters.toZonedDateTime(accessor).withZoneSameLocal(timeZone).toInstant();
|
||||
return DateFormatters.from(accessor).withZoneSameLocal(timeZone).toInstant();
|
||||
}
|
||||
} catch (DateTimeParseException e) {
|
||||
throw new ElasticsearchParseException("failed to parse date field [{}] with format [{}]: [{}]",
|
||||
|
@ -247,7 +247,7 @@ public class DateFieldMapper extends FieldMapper {
|
||||
}
|
||||
|
||||
long parse(String value) {
|
||||
return DateFormatters.toZonedDateTime(dateTimeFormatter().parse(value)).toInstant().toEpochMilli();
|
||||
return DateFormatters.from(dateTimeFormatter().parse(value)).toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -730,7 +730,7 @@ public class RoundingTests extends ESTestCase {
|
||||
|
||||
private static long time(String time, ZoneId zone) {
|
||||
TemporalAccessor accessor = DateFormatter.forPattern("date_optional_time").withZone(zone).parse(time);
|
||||
return DateFormatters.toZonedDateTime(accessor).toInstant().toEpochMilli();
|
||||
return DateFormatters.from(accessor).toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
private static Matcher<Long> isDate(final long expected, ZoneId tz) {
|
||||
|
@ -688,7 +688,7 @@ public class JavaJodaTimeDuellingTests extends ESTestCase {
|
||||
DateTime jodaDateTime = jodaFormatter.parseJoda(input);
|
||||
|
||||
TemporalAccessor javaTimeAccessor = javaFormatter.parse(input);
|
||||
ZonedDateTime zonedDateTime = DateFormatters.toZonedDateTime(javaTimeAccessor);
|
||||
ZonedDateTime zonedDateTime = DateFormatters.from(javaTimeAccessor);
|
||||
|
||||
String msg = String.format(Locale.ROOT, "Input [%s] Format [%s] Joda [%s], Java [%s]", input, format, jodaDateTime,
|
||||
DateTimeFormatter.ISO_INSTANT.format(zonedDateTime.toInstant()));
|
||||
|
@ -84,14 +84,14 @@ public class DateFormattersTests extends ESTestCase {
|
||||
public void testEpochMilliParsersWithDifferentFormatters() {
|
||||
DateFormatter formatter = DateFormatter.forPattern("strict_date_optional_time||epoch_millis");
|
||||
TemporalAccessor accessor = formatter.parse("123");
|
||||
assertThat(DateFormatters.toZonedDateTime(accessor).toInstant().toEpochMilli(), is(123L));
|
||||
assertThat(DateFormatters.from(accessor).toInstant().toEpochMilli(), is(123L));
|
||||
assertThat(formatter.pattern(), is("strict_date_optional_time||epoch_millis"));
|
||||
}
|
||||
|
||||
public void testParsersWithMultipleInternalFormats() throws Exception {
|
||||
ZonedDateTime first = DateFormatters.toZonedDateTime(
|
||||
ZonedDateTime first = DateFormatters.from(
|
||||
DateFormatters.forPattern("strict_date_optional_time_nanos").parse("2018-05-15T17:14:56+0100"));
|
||||
ZonedDateTime second = DateFormatters.toZonedDateTime(
|
||||
ZonedDateTime second = DateFormatters.from(
|
||||
DateFormatters.forPattern("strict_date_optional_time_nanos").parse("2018-05-15T17:14:56+01:00"));
|
||||
assertThat(first, is(second));
|
||||
}
|
||||
@ -163,7 +163,7 @@ public class DateFormattersTests extends ESTestCase {
|
||||
assertRoundupFormatter("epoch_millis", "1234567890", 1234567890L);
|
||||
// also check nanos of the epoch_millis formatter if it is rounded up to the nano second
|
||||
DateTimeFormatter roundUpFormatter = ((JavaDateFormatter) DateFormatter.forPattern("8epoch_millis")).getRoundupParser();
|
||||
Instant epochMilliInstant = DateFormatters.toZonedDateTime(roundUpFormatter.parse("1234567890")).toInstant();
|
||||
Instant epochMilliInstant = DateFormatters.from(roundUpFormatter.parse("1234567890")).toInstant();
|
||||
assertThat(epochMilliInstant.getLong(ChronoField.NANO_OF_SECOND), is(890_999_999L));
|
||||
|
||||
assertRoundupFormatter("strict_date_optional_time||epoch_millis", "2018-10-10T12:13:14.123Z", 1539173594123L);
|
||||
@ -175,7 +175,7 @@ public class DateFormattersTests extends ESTestCase {
|
||||
assertRoundupFormatter("epoch_second", "1234567890", 1234567890999L);
|
||||
// also check nanos of the epoch_millis formatter if it is rounded up to the nano second
|
||||
DateTimeFormatter epochSecondRoundupParser = ((JavaDateFormatter) DateFormatter.forPattern("8epoch_second")).getRoundupParser();
|
||||
Instant epochSecondInstant = DateFormatters.toZonedDateTime(epochSecondRoundupParser.parse("1234567890")).toInstant();
|
||||
Instant epochSecondInstant = DateFormatters.from(epochSecondRoundupParser.parse("1234567890")).toInstant();
|
||||
assertThat(epochSecondInstant.getLong(ChronoField.NANO_OF_SECOND), is(999_999_999L));
|
||||
|
||||
assertRoundupFormatter("strict_date_optional_time||epoch_second", "2018-10-10T12:13:14.123Z", 1539173594123L);
|
||||
@ -189,7 +189,7 @@ public class DateFormattersTests extends ESTestCase {
|
||||
JavaDateFormatter dateFormatter = (JavaDateFormatter) DateFormatter.forPattern(format);
|
||||
dateFormatter.parse(input);
|
||||
DateTimeFormatter roundUpFormatter = dateFormatter.getRoundupParser();
|
||||
long millis = DateFormatters.toZonedDateTime(roundUpFormatter.parse(input)).toInstant().toEpochMilli();
|
||||
long millis = DateFormatters.from(roundUpFormatter.parse(input)).toInstant().toEpochMilli();
|
||||
assertThat(millis, is(expectedMilliSeconds));
|
||||
}
|
||||
|
||||
|
@ -138,12 +138,12 @@ public class JavaDateMathParserTests extends ESTestCase {
|
||||
// If a user only specifies times, then the date needs to always be 1970-01-01 regardless of rounding
|
||||
DateFormatter formatter = DateFormatters.forPattern("HH:mm:ss");
|
||||
DateMathParser parser = formatter.toDateMathParser();
|
||||
ZonedDateTime zonedDateTime = DateFormatters.toZonedDateTime(formatter.parse("04:52:20"));
|
||||
ZonedDateTime zonedDateTime = DateFormatters.from(formatter.parse("04:52:20"));
|
||||
assertThat(zonedDateTime.getYear(), is(1970));
|
||||
Instant millisStart = zonedDateTime.toInstant();
|
||||
assertEquals(millisStart, parser.parse("04:52:20", () -> 0, false, (ZoneId) null));
|
||||
// due to rounding up, we have to add the number of milliseconds here manually
|
||||
long millisEnd = DateFormatters.toZonedDateTime(formatter.parse("04:52:20")).toInstant().toEpochMilli() + 999;
|
||||
long millisEnd = DateFormatters.from(formatter.parse("04:52:20")).toInstant().toEpochMilli() + 999;
|
||||
assertEquals(millisEnd, parser.parse("04:52:20", () -> 0, true, (ZoneId) null).toEpochMilli());
|
||||
}
|
||||
|
||||
|
@ -113,9 +113,9 @@ public class DateFieldTypeTests extends FieldTypeTestCase {
|
||||
Directory dir = newDirectory();
|
||||
IndexWriter w = new IndexWriter(dir, new IndexWriterConfig(null));
|
||||
long instant1 =
|
||||
DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse("2015-10-12")).toInstant().toEpochMilli();
|
||||
DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse("2015-10-12")).toInstant().toEpochMilli();
|
||||
long instant2 =
|
||||
DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse("2016-04-03")).toInstant().toEpochMilli();
|
||||
DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse("2016-04-03")).toInstant().toEpochMilli();
|
||||
Document doc = new Document();
|
||||
LongPoint field = new LongPoint("my_date", instant1);
|
||||
doc.add(field);
|
||||
@ -142,7 +142,7 @@ public class DateFieldTypeTests extends FieldTypeTestCase {
|
||||
|
||||
public void testValueFormat() {
|
||||
MappedFieldType ft = createDefaultFieldType();
|
||||
long instant = DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse("2015-10-12T14:10:55"))
|
||||
long instant = DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse("2015-10-12T14:10:55"))
|
||||
.toInstant().toEpochMilli();
|
||||
|
||||
assertEquals("2015-10-12T14:10:55.000Z",
|
||||
@ -155,7 +155,7 @@ public class DateFieldTypeTests extends FieldTypeTestCase {
|
||||
ft.docValueFormat(null, ZoneOffset.UTC).parseLong("2015-10-12T14:10:55", false, null));
|
||||
assertEquals(instant + 999,
|
||||
ft.docValueFormat(null, ZoneOffset.UTC).parseLong("2015-10-12T14:10:55", true, null));
|
||||
long i = DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse("2015-10-13")).toInstant().toEpochMilli();
|
||||
long i = DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse("2015-10-13")).toInstant().toEpochMilli();
|
||||
assertEquals(i - 1, ft.docValueFormat(null, ZoneOffset.UTC).parseLong("2015-10-12||/d", true, null));
|
||||
}
|
||||
|
||||
@ -176,7 +176,7 @@ public class DateFieldTypeTests extends FieldTypeTestCase {
|
||||
MappedFieldType ft = createDefaultFieldType();
|
||||
ft.setName("field");
|
||||
String date = "2015-10-12T14:10:55";
|
||||
long instant = DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(date)).toInstant().toEpochMilli();
|
||||
long instant = DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(date)).toInstant().toEpochMilli();
|
||||
ft.setIndexOptions(IndexOptions.DOCS);
|
||||
Query expected = new IndexOrDocValuesQuery(
|
||||
LongPoint.newRangeQuery("field", instant, instant + 999),
|
||||
@ -199,9 +199,9 @@ public class DateFieldTypeTests extends FieldTypeTestCase {
|
||||
ft.setName("field");
|
||||
String date1 = "2015-10-12T14:10:55";
|
||||
String date2 = "2016-04-28T11:33:52";
|
||||
long instant1 = DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(date1)).toInstant().toEpochMilli();
|
||||
long instant1 = DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(date1)).toInstant().toEpochMilli();
|
||||
long instant2 =
|
||||
DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(date2)).toInstant().toEpochMilli() + 999;
|
||||
DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(date2)).toInstant().toEpochMilli() + 999;
|
||||
ft.setIndexOptions(IndexOptions.DOCS);
|
||||
Query expected = new IndexOrDocValuesQuery(
|
||||
LongPoint.newRangeQuery("field", instant1, instant2),
|
||||
|
@ -91,7 +91,7 @@ public class DateHistogramIT extends ESIntegTestCase {
|
||||
}
|
||||
|
||||
private ZonedDateTime date(String date) {
|
||||
return DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(date));
|
||||
return DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(date));
|
||||
}
|
||||
|
||||
private static String format(ZonedDateTime date, String pattern) {
|
||||
@ -1191,10 +1191,10 @@ public class DateHistogramIT extends ESIntegTestCase {
|
||||
|
||||
List<IndexRequestBuilder> builders = new ArrayList<>();
|
||||
DateFormatter formatter = DateFormatter.forPattern("date_optional_time");
|
||||
builders.add(indexDoc(index, DateFormatters.toZonedDateTime(formatter.parse("2016-01-03T08:00:00.000Z")), 1));
|
||||
builders.add(indexDoc(index, DateFormatters.toZonedDateTime(formatter.parse("2016-01-03T08:00:00.000Z")), 2));
|
||||
builders.add(indexDoc(index, DateFormatters.toZonedDateTime(formatter.parse("2016-01-06T08:00:00.000Z")), 3));
|
||||
builders.add(indexDoc(index, DateFormatters.toZonedDateTime(formatter.parse("2016-01-06T08:00:00.000Z")), 4));
|
||||
builders.add(indexDoc(index, DateFormatters.from(formatter.parse("2016-01-03T08:00:00.000Z")), 1));
|
||||
builders.add(indexDoc(index, DateFormatters.from(formatter.parse("2016-01-03T08:00:00.000Z")), 2));
|
||||
builders.add(indexDoc(index, DateFormatters.from(formatter.parse("2016-01-06T08:00:00.000Z")), 3));
|
||||
builders.add(indexDoc(index, DateFormatters.from(formatter.parse("2016-01-06T08:00:00.000Z")), 4));
|
||||
indexRandom(true, builders);
|
||||
ensureSearchable(index);
|
||||
|
||||
|
@ -54,7 +54,7 @@ public class DateHistogramOffsetIT extends ESIntegTestCase {
|
||||
private static final DateFormatter FORMATTER = DateFormatter.forPattern(DATE_FORMAT);
|
||||
|
||||
private ZonedDateTime date(String date) {
|
||||
return DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(date));
|
||||
return DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(date));
|
||||
}
|
||||
|
||||
@Before
|
||||
|
@ -1835,6 +1835,6 @@ public class CompositeAggregatorTests extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
private static long asLong(String dateTime) {
|
||||
return DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(dateTime)).toInstant().toEpochMilli();
|
||||
return DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(dateTime)).toInstant().toEpochMilli();
|
||||
}
|
||||
}
|
||||
|
@ -475,6 +475,6 @@ public class DateHistogramAggregatorTests extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
private static long asLong(String dateTime) {
|
||||
return DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(dateTime)).toInstant().toEpochMilli();
|
||||
return DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(dateTime)).toInstant().toEpochMilli();
|
||||
}
|
||||
}
|
||||
|
@ -143,14 +143,14 @@ public class DateHistogramTests extends BaseAggregationTestCase<DateHistogramAgg
|
||||
try (Directory dir = newDirectory();
|
||||
IndexWriter w = new IndexWriter(dir, newIndexWriterConfig())) {
|
||||
|
||||
long millis1 = DateFormatters.toZonedDateTime(format.parse("2018-03-11T11:55:00")).toInstant().toEpochMilli();
|
||||
long millis1 = DateFormatters.from(format.parse("2018-03-11T11:55:00")).toInstant().toEpochMilli();
|
||||
w.addDocument(documentForDate(DATE_FIELD_NAME, millis1));
|
||||
long millis2 = DateFormatters.toZonedDateTime(format.parse("2017-10-30T18:13:00")).toInstant().toEpochMilli();
|
||||
long millis2 = DateFormatters.from(format.parse("2017-10-30T18:13:00")).toInstant().toEpochMilli();
|
||||
w.addDocument(documentForDate(DATE_FIELD_NAME, millis2));
|
||||
|
||||
try (IndexReader readerThatDoesntCross = DirectoryReader.open(w)) {
|
||||
|
||||
long millis3 = DateFormatters.toZonedDateTime(format.parse("2018-03-25T02:44:00")).toInstant().toEpochMilli();
|
||||
long millis3 = DateFormatters.from(format.parse("2018-03-25T02:44:00")).toInstant().toEpochMilli();
|
||||
w.addDocument(documentForDate(DATE_FIELD_NAME, millis3));
|
||||
|
||||
try (IndexReader readerThatCrosses = DirectoryReader.open(w)) {
|
||||
|
@ -140,6 +140,6 @@ public class AvgBucketAggregatorTests extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
private static long asLong(String dateTime) {
|
||||
return DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(dateTime)).toInstant().toEpochMilli();
|
||||
return DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(dateTime)).toInstant().toEpochMilli();
|
||||
}
|
||||
}
|
||||
|
@ -366,6 +366,6 @@ public class CumulativeSumAggregatorTests extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
private static long asLong(String dateTime) {
|
||||
return DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(dateTime)).toInstant().toEpochMilli();
|
||||
return DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(dateTime)).toInstant().toEpochMilli();
|
||||
}
|
||||
}
|
||||
|
@ -200,11 +200,11 @@ public class DateDerivativeIT extends ESIntegTestCase {
|
||||
ZoneId timezone = ZoneId.of("CET");
|
||||
DateFormatter formatter = DateFormatter.forPattern("yyyy-MM-dd'T'HH:mm:ss").withZone(timezone);
|
||||
// epoch millis: 1332547200000
|
||||
addNTimes(1, IDX_DST_START, DateFormatters.toZonedDateTime(formatter.parse("2012-03-24T01:00:00")), builders);
|
||||
addNTimes(1, IDX_DST_START, DateFormatters.from(formatter.parse("2012-03-24T01:00:00")), builders);
|
||||
// day with dst shift, only 23h long
|
||||
addNTimes(2, IDX_DST_START, DateFormatters.toZonedDateTime(formatter.parse("2012-03-25T01:00:00")), builders);
|
||||
addNTimes(3, IDX_DST_START, DateFormatters.toZonedDateTime(formatter.parse("2012-03-26T01:00:00")), builders);
|
||||
addNTimes(4, IDX_DST_START, DateFormatters.toZonedDateTime(formatter.parse("2012-03-27T01:00:00")), builders);
|
||||
addNTimes(2, IDX_DST_START, DateFormatters.from(formatter.parse("2012-03-25T01:00:00")), builders);
|
||||
addNTimes(3, IDX_DST_START, DateFormatters.from(formatter.parse("2012-03-26T01:00:00")), builders);
|
||||
addNTimes(4, IDX_DST_START, DateFormatters.from(formatter.parse("2012-03-27T01:00:00")), builders);
|
||||
indexRandom(true, builders);
|
||||
ensureSearchable();
|
||||
|
||||
@ -251,11 +251,11 @@ public class DateDerivativeIT extends ESIntegTestCase {
|
||||
List<IndexRequestBuilder> builders = new ArrayList<>();
|
||||
|
||||
DateFormatter formatter = DateFormatter.forPattern("yyyy-MM-dd'T'HH:mm:ss").withZone(timezone);
|
||||
addNTimes(1, IDX_DST_END, DateFormatters.toZonedDateTime(formatter.parse("2012-10-27T01:00:00")), builders);
|
||||
addNTimes(1, IDX_DST_END, DateFormatters.from(formatter.parse("2012-10-27T01:00:00")), builders);
|
||||
// day with dst shift -1h, 25h long
|
||||
addNTimes(2, IDX_DST_END, DateFormatters.toZonedDateTime(formatter.parse("2012-10-28T01:00:00")), builders);
|
||||
addNTimes(3, IDX_DST_END, DateFormatters.toZonedDateTime(formatter.parse("2012-10-29T01:00:00")), builders);
|
||||
addNTimes(4, IDX_DST_END, DateFormatters.toZonedDateTime(formatter.parse("2012-10-30T01:00:00")), builders);
|
||||
addNTimes(2, IDX_DST_END, DateFormatters.from(formatter.parse("2012-10-28T01:00:00")), builders);
|
||||
addNTimes(3, IDX_DST_END, DateFormatters.from(formatter.parse("2012-10-29T01:00:00")), builders);
|
||||
addNTimes(4, IDX_DST_END, DateFormatters.from(formatter.parse("2012-10-30T01:00:00")), builders);
|
||||
indexRandom(true, builders);
|
||||
ensureSearchable();
|
||||
|
||||
@ -304,11 +304,11 @@ public class DateDerivativeIT extends ESIntegTestCase {
|
||||
List<IndexRequestBuilder> builders = new ArrayList<>();
|
||||
|
||||
DateFormatter formatter = DateFormatter.forPattern("yyyy-MM-dd'T'HH:mm:ss").withZone(timezone);
|
||||
addNTimes(1, IDX_DST_KATHMANDU, DateFormatters.toZonedDateTime(formatter.parse("1985-12-31T22:30:00")), builders);
|
||||
addNTimes(1, IDX_DST_KATHMANDU, DateFormatters.from(formatter.parse("1985-12-31T22:30:00")), builders);
|
||||
// the shift happens during the next bucket, which includes the 45min that do not start on the full hour
|
||||
addNTimes(2, IDX_DST_KATHMANDU, DateFormatters.toZonedDateTime(formatter.parse("1985-12-31T23:30:00")), builders);
|
||||
addNTimes(3, IDX_DST_KATHMANDU, DateFormatters.toZonedDateTime(formatter.parse("1986-01-01T01:30:00")), builders);
|
||||
addNTimes(4, IDX_DST_KATHMANDU, DateFormatters.toZonedDateTime(formatter.parse("1986-01-01T02:30:00")), builders);
|
||||
addNTimes(2, IDX_DST_KATHMANDU, DateFormatters.from(formatter.parse("1985-12-31T23:30:00")), builders);
|
||||
addNTimes(3, IDX_DST_KATHMANDU, DateFormatters.from(formatter.parse("1986-01-01T01:30:00")), builders);
|
||||
addNTimes(4, IDX_DST_KATHMANDU, DateFormatters.from(formatter.parse("1986-01-01T02:30:00")), builders);
|
||||
indexRandom(true, builders);
|
||||
ensureSearchable();
|
||||
|
||||
|
@ -161,7 +161,7 @@ public class MovFnUnitTests extends AggregatorTestCase {
|
||||
}
|
||||
|
||||
private static long asLong(String dateTime) {
|
||||
return DateFormatters.toZonedDateTime(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(dateTime)).toInstant().toEpochMilli();
|
||||
return DateFormatters.from(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.parse(dateTime)).toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -23,7 +23,7 @@ public class DateUtils {
|
||||
// Try parsing using complete date/time format
|
||||
return dateTimeFormatter.parseMillis(date);
|
||||
} catch (ElasticsearchParseException | IllegalArgumentException ex) {
|
||||
ZonedDateTime dateTime = DateFormatters.toZonedDateTime(dateOnlyFormatter.parse(date));
|
||||
ZonedDateTime dateTime = DateFormatters.from(dateOnlyFormatter.parse(date));
|
||||
dateTime.with(ChronoField.MILLI_OF_DAY, ChronoField.MILLI_OF_DAY.range().getMaximum());
|
||||
return dateTime.toInstant().toEpochMilli();
|
||||
}
|
||||
@ -35,7 +35,7 @@ public class DateUtils {
|
||||
return dateTimeFormatter.parseMillis(date);
|
||||
} catch (ElasticsearchParseException | IllegalArgumentException ex) {
|
||||
// Fall back to the date only format
|
||||
return DateFormatters.toZonedDateTime(dateOnlyFormatter.parse(date)).toInstant().toEpochMilli();
|
||||
return DateFormatters.from(dateOnlyFormatter.parse(date)).toInstant().toEpochMilli();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user