Core: Abstract DateMathParser in an interface (#33905)

This commits creates a DateMathParser interface, which is already
implemented for both joda and java time. While currently the java time
DateMathParser is not used, this change will allow a followup which will
create a DateMathParser from a DateFormatter, so the caller does not
need to know the internals of the DateFormatter they have.
This commit is contained in:
Ryan Ernst 2018-09-26 07:56:25 -07:00 committed by GitHub
parent ff2bbdf765
commit 7800b4fa91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 476 additions and 293 deletions

View File

@ -27,10 +27,11 @@ import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.regex.Regex; import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.time.DateUtils;
import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.IndexNotFoundException;
@ -923,8 +924,9 @@ public class IndexNameExpressionResolver extends AbstractComponent {
} }
DateTimeFormatter parser = dateFormatter.withZone(timeZone); DateTimeFormatter parser = dateFormatter.withZone(timeZone);
FormatDateTimeFormatter formatter = new FormatDateTimeFormatter(dateFormatterPattern, parser, Locale.ROOT); FormatDateTimeFormatter formatter = new FormatDateTimeFormatter(dateFormatterPattern, parser, Locale.ROOT);
DateMathParser dateMathParser = new DateMathParser(formatter); DateMathParser dateMathParser = formatter.toDateMathParser();
long millis = dateMathParser.parse(mathExpression, context::getStartTime, false, timeZone); long millis = dateMathParser.parse(mathExpression, context::getStartTime, false,
DateUtils.dateTimeZoneToZoneId(timeZone));
String time = formatter.printer().print(millis); String time = formatter.printer().print(millis);
beforePlaceHolderSb.append(time); beforePlaceHolderSb.append(time);

View File

@ -19,6 +19,7 @@
package org.elasticsearch.common.joda; package org.elasticsearch.common.joda;
import org.elasticsearch.common.time.DateMathParser;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import java.util.Locale; import java.util.Locale;
@ -64,4 +65,8 @@ public class FormatDateTimeFormatter {
public Locale locale() { public Locale locale() {
return locale; return locale;
} }
public DateMathParser toDateMathParser() {
return new JodaDateMathParser(this);
}
} }

View File

@ -20,10 +20,13 @@
package org.elasticsearch.common.joda; package org.elasticsearch.common.joda;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.time.DateUtils;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.joda.time.MutableDateTime; import org.joda.time.MutableDateTime;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import java.time.ZoneId;
import java.util.Objects; import java.util.Objects;
import java.util.function.LongSupplier; import java.util.function.LongSupplier;
@ -34,23 +37,21 @@ import java.util.function.LongSupplier;
* is appended to a datetime with the following syntax: * is appended to a datetime with the following syntax:
* <code>||[+-/](\d+)?[yMwdhHms]</code>. * <code>||[+-/](\d+)?[yMwdhHms]</code>.
*/ */
public class DateMathParser { public class JodaDateMathParser implements DateMathParser {
private final FormatDateTimeFormatter dateTimeFormatter; private final FormatDateTimeFormatter dateTimeFormatter;
public DateMathParser(FormatDateTimeFormatter dateTimeFormatter) { public JodaDateMathParser(FormatDateTimeFormatter dateTimeFormatter) {
Objects.requireNonNull(dateTimeFormatter); Objects.requireNonNull(dateTimeFormatter);
this.dateTimeFormatter = dateTimeFormatter; this.dateTimeFormatter = dateTimeFormatter;
} }
public long parse(String text, LongSupplier now) {
return parse(text, now, false, null);
}
// Note: we take a callable here for the timestamp in order to be able to figure out // Note: we take a callable here for the timestamp in order to be able to figure out
// if it has been used. For instance, the request cache does not cache requests that make // if it has been used. For instance, the request cache does not cache requests that make
// use of `now`. // use of `now`.
public long parse(String text, LongSupplier now, boolean roundUp, DateTimeZone timeZone) { @Override
public long parse(String text, LongSupplier now, boolean roundUp, ZoneId tz) {
final DateTimeZone timeZone = tz == null ? null : DateUtils.zoneIdToDateTimeZone(tz);
long time; long time;
String mathString; String mathString;
if (text.startsWith("now")) { if (text.startsWith("now")) {

View File

@ -19,56 +19,31 @@
package org.elasticsearch.common.time; package org.elasticsearch.common.time;
import org.elasticsearch.ElasticsearchParseException; import org.joda.time.DateTimeZone;
import java.time.DateTimeException;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalTime;
import java.time.ZoneId; import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQueries;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.LongSupplier; import java.util.function.LongSupplier;
/** /**
* A parser for date/time formatted text with optional date math. * An abstraction over date math parsing to allow different implementation for joda and java time.
*
* The format of the datetime is configurable, and unix timestamps can also be used. Datemath
* is appended to a datetime with the following syntax:
* <code>||[+-/](\d+)?[yMwdhHms]</code>.
*/ */
public class DateMathParser { public interface DateMathParser {
// base fields which should be used for default parsing, when we round up /**
private static final Map<TemporalField, Long> ROUND_UP_BASE_FIELDS = new HashMap<>(6); * Parse a date math expression without timzeone info and rounding down.
{ */
ROUND_UP_BASE_FIELDS.put(ChronoField.MONTH_OF_YEAR, 1L); default long parse(String text, LongSupplier now) {
ROUND_UP_BASE_FIELDS.put(ChronoField.DAY_OF_MONTH, 1L); return parse(text, now, false, (ZoneId) null);
ROUND_UP_BASE_FIELDS.put(ChronoField.HOUR_OF_DAY, 23L);
ROUND_UP_BASE_FIELDS.put(ChronoField.MINUTE_OF_HOUR, 59L);
ROUND_UP_BASE_FIELDS.put(ChronoField.SECOND_OF_MINUTE, 59L);
ROUND_UP_BASE_FIELDS.put(ChronoField.MILLI_OF_SECOND, 999L);
} }
private final DateFormatter formatter; // Note: we take a callable here for the timestamp in order to be able to figure out
private final DateFormatter roundUpFormatter; // if it has been used. For instance, the request cache does not cache requests that make
// use of `now`.
public DateMathParser(DateFormatter formatter) { // exists for backcompat, do not use!
Objects.requireNonNull(formatter); @Deprecated
this.formatter = formatter; default long parse(String text, LongSupplier now, boolean roundUp, DateTimeZone tz) {
this.roundUpFormatter = formatter.parseDefaulting(ROUND_UP_BASE_FIELDS); return parse(text, now, roundUp, tz == null ? null : ZoneId.of(tz.getID()));
}
public long parse(String text, LongSupplier now) {
return parse(text, now, false, null);
} }
/** /**
@ -92,176 +67,8 @@ public class DateMathParser {
* @param text the input * @param text the input
* @param now a supplier to retrieve the current date in milliseconds, if needed for additions * @param now a supplier to retrieve the current date in milliseconds, if needed for additions
* @param roundUp should the result be rounded up * @param roundUp should the result be rounded up
* @param timeZone an optional timezone that should be applied before returning the milliseconds since the epoch * @param tz an optional timezone that should be applied before returning the milliseconds since the epoch
* @return the parsed date in milliseconds since the epoch * @return the parsed date in milliseconds since the epoch
*/ */
public long parse(String text, LongSupplier now, boolean roundUp, ZoneId timeZone) { long parse(String text, LongSupplier now, boolean roundUp, ZoneId tz);
long time;
String mathString;
if (text.startsWith("now")) {
try {
time = now.getAsLong();
} catch (Exception e) {
throw new ElasticsearchParseException("could not read the current timestamp", e);
}
mathString = text.substring("now".length());
} else {
int index = text.indexOf("||");
if (index == -1) {
return parseDateTime(text, timeZone, roundUp);
}
time = parseDateTime(text.substring(0, index), timeZone, false);
mathString = text.substring(index + 2);
}
return parseMath(mathString, time, roundUp, timeZone);
}
private long parseMath(final String mathString, final long time, final boolean roundUp,
ZoneId timeZone) throws ElasticsearchParseException {
if (timeZone == null) {
timeZone = ZoneOffset.UTC;
}
ZonedDateTime dateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(time), timeZone);
for (int i = 0; i < mathString.length(); ) {
char c = mathString.charAt(i++);
final boolean round;
final int sign;
if (c == '/') {
round = true;
sign = 1;
} else {
round = false;
if (c == '+') {
sign = 1;
} else if (c == '-') {
sign = -1;
} else {
throw new ElasticsearchParseException("operator not supported for date math [{}]", mathString);
}
}
if (i >= mathString.length()) {
throw new ElasticsearchParseException("truncated date math [{}]", mathString);
}
final int num;
if (!Character.isDigit(mathString.charAt(i))) {
num = 1;
} else {
int numFrom = i;
while (i < mathString.length() && Character.isDigit(mathString.charAt(i))) {
i++;
}
if (i >= mathString.length()) {
throw new ElasticsearchParseException("truncated date math [{}]", mathString);
}
num = Integer.parseInt(mathString.substring(numFrom, i));
}
if (round) {
if (num != 1) {
throw new ElasticsearchParseException("rounding `/` can only be used on single unit types [{}]", mathString);
}
}
char unit = mathString.charAt(i++);
switch (unit) {
case 'y':
if (round) {
dateTime = dateTime.withDayOfYear(1).with(LocalTime.MIN);
} else {
dateTime = dateTime.plusYears(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusYears(1);
}
break;
case 'M':
if (round) {
dateTime = dateTime.withDayOfMonth(1).with(LocalTime.MIN);
} else {
dateTime = dateTime.plusMonths(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusMonths(1);
}
break;
case 'w':
if (round) {
dateTime = dateTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).with(LocalTime.MIN);
} else {
dateTime = dateTime.plusWeeks(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusWeeks(1);
}
break;
case 'd':
if (round) {
dateTime = dateTime.with(LocalTime.MIN);
} else {
dateTime = dateTime.plusDays(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusDays(1);
}
break;
case 'h':
case 'H':
if (round) {
dateTime = dateTime.withMinute(0).withSecond(0).withNano(0);
} else {
dateTime = dateTime.plusHours(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusHours(1);
}
break;
case 'm':
if (round) {
dateTime = dateTime.withSecond(0).withNano(0);
} else {
dateTime = dateTime.plusMinutes(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusMinutes(1);
}
break;
case 's':
if (round) {
dateTime = dateTime.withNano(0);
} else {
dateTime = dateTime.plusSeconds(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusSeconds(1);
}
break;
default:
throw new ElasticsearchParseException("unit [{}] not supported for date math [{}]", unit, mathString);
}
if (roundUp) {
dateTime = dateTime.minus(1, ChronoField.MILLI_OF_SECOND.getBaseUnit());
}
}
return dateTime.toInstant().toEpochMilli();
}
private long parseDateTime(String value, ZoneId timeZone, boolean roundUpIfNoTime) {
DateFormatter formatter = roundUpIfNoTime ? this.roundUpFormatter : this.formatter;
try {
if (timeZone == null) {
return DateFormatters.toZonedDateTime(formatter.parse(value)).toInstant().toEpochMilli();
} else {
TemporalAccessor accessor = formatter.parse(value);
ZoneId zoneId = TemporalQueries.zone().queryFrom(accessor);
if (zoneId != null) {
timeZone = zoneId;
}
return DateFormatters.toZonedDateTime(accessor).withZoneSameLocal(timeZone).toInstant().toEpochMilli();
}
} catch (IllegalArgumentException | DateTimeException e) {
throw new ElasticsearchParseException("failed to parse date field [{}]: [{}]", e, value, e.getMessage());
}
}
} }

View File

@ -0,0 +1,70 @@
/*
* 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.common.time;
import org.apache.logging.log4j.LogManager;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.joda.time.DateTimeZone;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class DateUtils {
public static DateTimeZone zoneIdToDateTimeZone(ZoneId zoneId) {
if (zoneId == null) {
return null;
}
if (zoneId instanceof ZoneOffset) {
// the id for zoneoffset is not ISO compatible, so cannot be read by ZoneId.of
return DateTimeZone.forOffsetMillis(((ZoneOffset)zoneId).getTotalSeconds() * 1000);
}
return DateTimeZone.forID(zoneId.getId());
}
private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(LogManager.getLogger(DateFormatters.class));
// pkg private for tests
static final Map<String, String> DEPRECATED_SHORT_TIMEZONES;
static {
Map<String, String> tzs = new HashMap<>();
tzs.put("EST", "-05:00"); // eastern time without daylight savings
tzs.put("HST", "-10:00");
tzs.put("MST", "-07:00");
tzs.put("ROC", "Asia/Taipei");
tzs.put("Eire", "Europe/London");
DEPRECATED_SHORT_TIMEZONES = Collections.unmodifiableMap(tzs);
}
public static ZoneId dateTimeZoneToZoneId(DateTimeZone timeZone) {
if (timeZone == null) {
return null;
}
String deprecatedId = DEPRECATED_SHORT_TIMEZONES.get(timeZone.getID());
if (deprecatedId != null) {
DEPRECATION_LOGGER.deprecatedAndMaybeLog("timezone",
"Use of short timezone id " + timeZone.getID() + " is deprecated. Use " + deprecatedId + " instead");
return ZoneId.of(deprecatedId);
}
return ZoneId.of(timeZone.getID());
}
}

View File

@ -0,0 +1,240 @@
/*
* 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.common.time;
import org.elasticsearch.ElasticsearchParseException;
import java.time.DateTimeException;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalField;
import java.time.temporal.TemporalQueries;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.LongSupplier;
/**
* A parser for date/time formatted text with optional date math.
*
* The format of the datetime is configurable, and unix timestamps can also be used. Datemath
* is appended to a datetime with the following syntax:
* <code>||[+-/](\d+)?[yMwdhHms]</code>.
*/
public class JavaDateMathParser implements DateMathParser {
// base fields which should be used for default parsing, when we round up
private static final Map<TemporalField, Long> ROUND_UP_BASE_FIELDS = new HashMap<>(6);
{
ROUND_UP_BASE_FIELDS.put(ChronoField.MONTH_OF_YEAR, 1L);
ROUND_UP_BASE_FIELDS.put(ChronoField.DAY_OF_MONTH, 1L);
ROUND_UP_BASE_FIELDS.put(ChronoField.HOUR_OF_DAY, 23L);
ROUND_UP_BASE_FIELDS.put(ChronoField.MINUTE_OF_HOUR, 59L);
ROUND_UP_BASE_FIELDS.put(ChronoField.SECOND_OF_MINUTE, 59L);
ROUND_UP_BASE_FIELDS.put(ChronoField.MILLI_OF_SECOND, 999L);
}
private final DateFormatter formatter;
private final DateFormatter roundUpFormatter;
public JavaDateMathParser(DateFormatter formatter) {
Objects.requireNonNull(formatter);
this.formatter = formatter;
this.roundUpFormatter = formatter.parseDefaulting(ROUND_UP_BASE_FIELDS);
}
@Override
public long parse(String text, LongSupplier now, boolean roundUp, ZoneId timeZone) {
long time;
String mathString;
if (text.startsWith("now")) {
try {
time = now.getAsLong();
} catch (Exception e) {
throw new ElasticsearchParseException("could not read the current timestamp", e);
}
mathString = text.substring("now".length());
} else {
int index = text.indexOf("||");
if (index == -1) {
return parseDateTime(text, timeZone, roundUp);
}
time = parseDateTime(text.substring(0, index), timeZone, false);
mathString = text.substring(index + 2);
}
return parseMath(mathString, time, roundUp, timeZone);
}
private long parseMath(final String mathString, final long time, final boolean roundUp,
ZoneId timeZone) throws ElasticsearchParseException {
if (timeZone == null) {
timeZone = ZoneOffset.UTC;
}
ZonedDateTime dateTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(time), timeZone);
for (int i = 0; i < mathString.length(); ) {
char c = mathString.charAt(i++);
final boolean round;
final int sign;
if (c == '/') {
round = true;
sign = 1;
} else {
round = false;
if (c == '+') {
sign = 1;
} else if (c == '-') {
sign = -1;
} else {
throw new ElasticsearchParseException("operator not supported for date math [{}]", mathString);
}
}
if (i >= mathString.length()) {
throw new ElasticsearchParseException("truncated date math [{}]", mathString);
}
final int num;
if (!Character.isDigit(mathString.charAt(i))) {
num = 1;
} else {
int numFrom = i;
while (i < mathString.length() && Character.isDigit(mathString.charAt(i))) {
i++;
}
if (i >= mathString.length()) {
throw new ElasticsearchParseException("truncated date math [{}]", mathString);
}
num = Integer.parseInt(mathString.substring(numFrom, i));
}
if (round) {
if (num != 1) {
throw new ElasticsearchParseException("rounding `/` can only be used on single unit types [{}]", mathString);
}
}
char unit = mathString.charAt(i++);
switch (unit) {
case 'y':
if (round) {
dateTime = dateTime.withDayOfYear(1).with(LocalTime.MIN);
} else {
dateTime = dateTime.plusYears(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusYears(1);
}
break;
case 'M':
if (round) {
dateTime = dateTime.withDayOfMonth(1).with(LocalTime.MIN);
} else {
dateTime = dateTime.plusMonths(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusMonths(1);
}
break;
case 'w':
if (round) {
dateTime = dateTime.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).with(LocalTime.MIN);
} else {
dateTime = dateTime.plusWeeks(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusWeeks(1);
}
break;
case 'd':
if (round) {
dateTime = dateTime.with(LocalTime.MIN);
} else {
dateTime = dateTime.plusDays(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusDays(1);
}
break;
case 'h':
case 'H':
if (round) {
dateTime = dateTime.withMinute(0).withSecond(0).withNano(0);
} else {
dateTime = dateTime.plusHours(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusHours(1);
}
break;
case 'm':
if (round) {
dateTime = dateTime.withSecond(0).withNano(0);
} else {
dateTime = dateTime.plusMinutes(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusMinutes(1);
}
break;
case 's':
if (round) {
dateTime = dateTime.withNano(0);
} else {
dateTime = dateTime.plusSeconds(sign * num);
}
if (roundUp) {
dateTime = dateTime.plusSeconds(1);
}
break;
default:
throw new ElasticsearchParseException("unit [{}] not supported for date math [{}]", unit, mathString);
}
if (roundUp) {
dateTime = dateTime.minus(1, ChronoField.MILLI_OF_SECOND.getBaseUnit());
}
}
return dateTime.toInstant().toEpochMilli();
}
private long parseDateTime(String value, ZoneId timeZone, boolean roundUpIfNoTime) {
DateFormatter formatter = roundUpIfNoTime ? this.roundUpFormatter : this.formatter;
try {
if (timeZone == null) {
return DateFormatters.toZonedDateTime(formatter.parse(value)).toInstant().toEpochMilli();
} else {
TemporalAccessor accessor = formatter.parse(value);
ZoneId zoneId = TemporalQueries.zone().queryFrom(accessor);
if (zoneId != null) {
timeZone = zoneId;
}
return DateFormatters.toZonedDateTime(accessor).withZoneSameLocal(timeZone).toInstant().toEpochMilli();
}
} catch (IllegalArgumentException | DateTimeException e) {
throw new ElasticsearchParseException("failed to parse date field [{}]: [{}]", e, value, e.getMessage());
}
}
}

View File

@ -36,10 +36,11 @@ import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.Explicit; import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.time.DateUtils;
import org.elasticsearch.common.util.LocaleUtils; import org.elasticsearch.common.util.LocaleUtils;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.common.xcontent.support.XContentMapValues;
@ -231,7 +232,7 @@ public class DateFieldMapper extends FieldMapper {
public void setDateTimeFormatter(FormatDateTimeFormatter dateTimeFormatter) { public void setDateTimeFormatter(FormatDateTimeFormatter dateTimeFormatter) {
checkIfFrozen(); checkIfFrozen();
this.dateTimeFormatter = dateTimeFormatter; this.dateTimeFormatter = dateTimeFormatter;
this.dateMathParser = new DateMathParser(dateTimeFormatter); this.dateMathParser = dateTimeFormatter.toDateMathParser();
} }
protected DateMathParser dateMathParser() { protected DateMathParser dateMathParser() {
@ -296,8 +297,8 @@ public class DateFieldMapper extends FieldMapper {
return query; return query;
} }
public long parseToMilliseconds(Object value, boolean roundUp, public long parseToMilliseconds(Object value, boolean roundUp, @Nullable DateTimeZone zone,
@Nullable DateTimeZone zone, @Nullable DateMathParser forcedDateParser, QueryRewriteContext context) { @Nullable DateMathParser forcedDateParser, QueryRewriteContext context) {
DateMathParser dateParser = dateMathParser(); DateMathParser dateParser = dateMathParser();
if (forcedDateParser != null) { if (forcedDateParser != null) {
dateParser = forcedDateParser; dateParser = forcedDateParser;
@ -309,13 +310,13 @@ public class DateFieldMapper extends FieldMapper {
} else { } else {
strValue = value.toString(); strValue = value.toString();
} }
return dateParser.parse(strValue, context::nowInMillis, roundUp, zone); return dateParser.parse(strValue, context::nowInMillis, roundUp, DateUtils.dateTimeZoneToZoneId(zone));
} }
@Override @Override
public Relation isFieldWithinQuery(IndexReader reader, public Relation isFieldWithinQuery(IndexReader reader, Object from, Object to, boolean includeLower, boolean includeUpper,
Object from, Object to, boolean includeLower, boolean includeUpper, DateTimeZone timeZone, DateMathParser dateParser,
DateTimeZone timeZone, DateMathParser dateParser, QueryRewriteContext context) throws IOException { QueryRewriteContext context) throws IOException {
if (dateParser == null) { if (dateParser == null) {
dateParser = this.dateMathParser; dateParser = this.dateMathParser;
} }

View File

@ -38,7 +38,7 @@ import org.apache.lucene.util.BytesRef;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.joda.DateMathParser; import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.unit.Fuzziness; import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.index.analysis.NamedAnalyzer; import org.elasticsearch.index.analysis.NamedAnalyzer;
import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.IndexFieldData;

View File

@ -44,11 +44,12 @@ import org.elasticsearch.common.Explicit;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.network.InetAddresses; import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.time.DateUtils;
import org.elasticsearch.common.util.LocaleUtils; import org.elasticsearch.common.util.LocaleUtils;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -60,6 +61,7 @@ import org.joda.time.DateTimeZone;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.time.ZoneId;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
@ -257,7 +259,7 @@ public class RangeFieldMapper extends FieldMapper {
public void setDateTimeFormatter(FormatDateTimeFormatter dateTimeFormatter) { public void setDateTimeFormatter(FormatDateTimeFormatter dateTimeFormatter) {
checkIfFrozen(); checkIfFrozen();
this.dateTimeFormatter = dateTimeFormatter; this.dateTimeFormatter = dateTimeFormatter;
this.dateMathParser = new DateMathParser(dateTimeFormatter); this.dateMathParser = dateTimeFormatter.toDateMathParser();
} }
protected DateMathParser dateMathParser() { protected DateMathParser dateMathParser() {
@ -588,14 +590,15 @@ public class RangeFieldMapper extends FieldMapper {
boolean includeUpper, ShapeRelation relation, @Nullable DateTimeZone timeZone, boolean includeUpper, ShapeRelation relation, @Nullable DateTimeZone timeZone,
@Nullable DateMathParser parser, QueryShardContext context) { @Nullable DateMathParser parser, QueryShardContext context) {
DateTimeZone zone = (timeZone == null) ? DateTimeZone.UTC : timeZone; DateTimeZone zone = (timeZone == null) ? DateTimeZone.UTC : timeZone;
ZoneId zoneId = DateUtils.dateTimeZoneToZoneId(zone);
DateMathParser dateMathParser = (parser == null) ? DateMathParser dateMathParser = (parser == null) ?
new DateMathParser(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER) : parser; DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.toDateMathParser() : parser;
Long low = lowerTerm == null ? Long.MIN_VALUE : Long low = lowerTerm == null ? Long.MIN_VALUE :
dateMathParser.parse(lowerTerm instanceof BytesRef ? ((BytesRef) lowerTerm).utf8ToString() : lowerTerm.toString(), dateMathParser.parse(lowerTerm instanceof BytesRef ? ((BytesRef) lowerTerm).utf8ToString() : lowerTerm.toString(),
context::nowInMillis, false, zone); context::nowInMillis, false, zoneId);
Long high = upperTerm == null ? Long.MAX_VALUE : Long high = upperTerm == null ? Long.MAX_VALUE :
dateMathParser.parse(upperTerm instanceof BytesRef ? ((BytesRef) upperTerm).utf8ToString() : upperTerm.toString(), dateMathParser.parse(upperTerm instanceof BytesRef ? ((BytesRef) upperTerm).utf8ToString() : upperTerm.toString(),
context::nowInMillis, false, zone); context::nowInMillis, false, zoneId);
return super.rangeQuery(field, hasDocValues, low, high, includeLower, includeUpper, relation, zone, return super.rangeQuery(field, hasDocValues, low, high, includeLower, includeUpper, relation, zone,
dateMathParser, context); dateMathParser, context);

View File

@ -21,7 +21,7 @@ package org.elasticsearch.index.mapper;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.joda.DateMathParser; import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardContext;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;

View File

@ -29,10 +29,10 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.geo.ShapeRelation; import org.elasticsearch.common.geo.ShapeRelation;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.lucene.BytesRefs; import org.elasticsearch.common.lucene.BytesRefs;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.FieldNamesFieldMapper; import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
@ -302,7 +302,7 @@ public class RangeQueryBuilder extends AbstractQueryBuilder<RangeQueryBuilder> i
DateMathParser getForceDateParser() { // pkg private for testing DateMathParser getForceDateParser() { // pkg private for testing
if (this.format != null) { if (this.format != null) {
return new DateMathParser(this.format); return this.format.toDateMathParser();
} }
return null; return null;
} }

View File

@ -25,11 +25,12 @@ import org.elasticsearch.common.geo.GeoHashUtils;
import org.elasticsearch.common.io.stream.NamedWriteable; import org.elasticsearch.common.io.stream.NamedWriteable;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.network.InetAddresses; import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.common.network.NetworkAddress; import org.elasticsearch.common.network.NetworkAddress;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.time.DateUtils;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import java.io.IOException; import java.io.IOException;
@ -171,13 +172,14 @@ public interface DocValueFormat extends NamedWriteable {
public static final String NAME = "date_time"; public static final String NAME = "date_time";
final FormatDateTimeFormatter formatter; final FormatDateTimeFormatter formatter;
// TODO: change this to ZoneId, but will require careful change to serialization
final DateTimeZone timeZone; final DateTimeZone timeZone;
private final DateMathParser parser; private final DateMathParser parser;
public DateTime(FormatDateTimeFormatter formatter, DateTimeZone timeZone) { public DateTime(FormatDateTimeFormatter formatter, DateTimeZone timeZone) {
this.formatter = Objects.requireNonNull(formatter); this.formatter = Objects.requireNonNull(formatter);
this.timeZone = Objects.requireNonNull(timeZone); this.timeZone = Objects.requireNonNull(timeZone);
this.parser = new DateMathParser(formatter); this.parser = formatter.toDateMathParser();
} }
public DateTime(StreamInput in) throws IOException { public DateTime(StreamInput in) throws IOException {
@ -212,7 +214,7 @@ public interface DocValueFormat extends NamedWriteable {
@Override @Override
public long parseLong(String value, boolean roundUp, LongSupplier now) { public long parseLong(String value, boolean roundUp, LongSupplier now) {
return parser.parse(value, now, roundUp, timeZone); return parser.parse(value, now, roundUp, DateUtils.dateTimeZoneToZoneId(timeZone));
} }
@Override @Override

View File

@ -25,10 +25,10 @@ import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.search.DocIdSetIterator; import org.apache.lucene.search.DocIdSetIterator;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.rounding.DateTimeUnit; import org.elasticsearch.common.rounding.DateTimeUnit;
import org.elasticsearch.common.rounding.Rounding; import org.elasticsearch.common.rounding.Rounding;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
@ -72,7 +72,7 @@ import static java.util.Collections.unmodifiableMap;
public class DateHistogramAggregationBuilder extends ValuesSourceAggregationBuilder<ValuesSource.Numeric, DateHistogramAggregationBuilder> public class DateHistogramAggregationBuilder extends ValuesSourceAggregationBuilder<ValuesSource.Numeric, DateHistogramAggregationBuilder>
implements MultiBucketAggregationBuilder { implements MultiBucketAggregationBuilder {
public static final String NAME = "date_histogram"; public static final String NAME = "date_histogram";
private static DateMathParser EPOCH_MILLIS_PARSER = new DateMathParser(Joda.forPattern("epoch_millis", Locale.ROOT)); private static DateMathParser EPOCH_MILLIS_PARSER = Joda.forPattern("epoch_millis", Locale.ROOT).toDateMathParser();
public static final Map<String, DateTimeUnit> DATE_FIELD_UNITS; public static final Map<String, DateTimeUnit> DATE_FIELD_UNITS;

View File

@ -24,17 +24,17 @@ import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import java.util.TimeZone; import java.time.ZoneId;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.LongSupplier; import java.util.function.LongSupplier;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
public class DateMathParserTests extends ESTestCase { public class JodaDateMathParserTests extends ESTestCase {
FormatDateTimeFormatter formatter = Joda.forPattern("dateOptionalTime||epoch_millis"); FormatDateTimeFormatter formatter = Joda.forPattern("dateOptionalTime||epoch_millis");
DateMathParser parser = new DateMathParser(formatter); JodaDateMathParser parser = new JodaDateMathParser(formatter);
void assertDateMathEquals(String toTest, String expected) { void assertDateMathEquals(String toTest, String expected) {
assertDateMathEquals(toTest, expected, 0, false, null); assertDateMathEquals(toTest, expected, 0, false, null);
@ -145,7 +145,7 @@ public class DateMathParserTests extends ESTestCase {
public void testNow() { public void testNow() {
final long now = parser.parse("2014-11-18T14:27:32", () -> 0, false, null); final long now = parser.parse("2014-11-18T14:27:32", () -> 0, false, (ZoneId) null);
assertDateMathEquals("now", "2014-11-18T14:27:32", now, false, null); assertDateMathEquals("now", "2014-11-18T14:27:32", now, false, null);
assertDateMathEquals("now+M", "2014-12-18T14:27:32", now, false, null); assertDateMathEquals("now+M", "2014-12-18T14:27:32", now, false, null);
@ -159,13 +159,13 @@ public class DateMathParserTests extends ESTestCase {
public void testRoundingPreservesEpochAsBaseDate() { public void testRoundingPreservesEpochAsBaseDate() {
// If a user only specifies times, then the date needs to always be 1970-01-01 regardless of rounding // If a user only specifies times, then the date needs to always be 1970-01-01 regardless of rounding
FormatDateTimeFormatter formatter = Joda.forPattern("HH:mm:ss"); FormatDateTimeFormatter formatter = Joda.forPattern("HH:mm:ss");
DateMathParser parser = new DateMathParser(formatter); JodaDateMathParser parser = new JodaDateMathParser(formatter);
assertEquals( assertEquals(
this.formatter.parser().parseMillis("1970-01-01T04:52:20.000Z"), this.formatter.parser().parseMillis("1970-01-01T04:52:20.000Z"),
parser.parse("04:52:20", () -> 0, false, null)); parser.parse("04:52:20", () -> 0, false, (ZoneId) null));
assertEquals( assertEquals(
this.formatter.parser().parseMillis("1970-01-01T04:52:20.999Z"), this.formatter.parser().parseMillis("1970-01-01T04:52:20.999Z"),
parser.parse("04:52:20", () -> 0, true, null)); parser.parse("04:52:20", () -> 0, true, (ZoneId) null));
} }
// Implicit rounding happening when parts of the date are not specified // Implicit rounding happening when parts of the date are not specified
@ -184,10 +184,10 @@ public class DateMathParserTests extends ESTestCase {
// implicit rounding with explicit timezone in the date format // implicit rounding with explicit timezone in the date format
FormatDateTimeFormatter formatter = Joda.forPattern("YYYY-MM-ddZ"); FormatDateTimeFormatter formatter = Joda.forPattern("YYYY-MM-ddZ");
DateMathParser parser = new DateMathParser(formatter); JodaDateMathParser parser = new JodaDateMathParser(formatter);
long time = parser.parse("2011-10-09+01:00", () -> 0, false, null); long time = parser.parse("2011-10-09+01:00", () -> 0, false, (ZoneId) null);
assertEquals(this.parser.parse("2011-10-09T00:00:00.000+01:00", () -> 0), time); assertEquals(this.parser.parse("2011-10-09T00:00:00.000+01:00", () -> 0), time);
time = parser.parse("2011-10-09+01:00", () -> 0, true, null); time = parser.parse("2011-10-09+01:00", () -> 0, true, (ZoneId) null);
assertEquals(this.parser.parse("2011-10-09T23:59:59.999+01:00", () -> 0), time); assertEquals(this.parser.parse("2011-10-09T23:59:59.999+01:00", () -> 0), time);
} }
@ -258,7 +258,7 @@ public class DateMathParserTests extends ESTestCase {
assertDateMathEquals("1418248078000||/m", "2014-12-10T21:47:00.000"); assertDateMathEquals("1418248078000||/m", "2014-12-10T21:47:00.000");
// also check other time units // also check other time units
DateMathParser parser = new DateMathParser(Joda.forPattern("epoch_second||dateOptionalTime")); JodaDateMathParser parser = new JodaDateMathParser(Joda.forPattern("epoch_second||dateOptionalTime"));
long datetime = parser.parse("1418248078", () -> 0); long datetime = parser.parse("1418248078", () -> 0);
assertDateEquals(datetime, "1418248078", "2014-12-10T21:47:58.000"); assertDateEquals(datetime, "1418248078", "2014-12-10T21:47:58.000");
@ -298,16 +298,16 @@ public class DateMathParserTests extends ESTestCase {
called.set(true); called.set(true);
return 42L; return 42L;
}; };
parser.parse("2014-11-18T14:27:32", now, false, null); parser.parse("2014-11-18T14:27:32", now, false, (ZoneId) null);
assertFalse(called.get()); assertFalse(called.get());
parser.parse("now/d", now, false, null); parser.parse("now/d", now, false, (ZoneId) null);
assertTrue(called.get()); assertTrue(called.get());
} }
public void testThatUnixTimestampMayNotHaveTimeZone() { public void testThatUnixTimestampMayNotHaveTimeZone() {
DateMathParser parser = new DateMathParser(Joda.forPattern("epoch_millis")); JodaDateMathParser parser = new JodaDateMathParser(Joda.forPattern("epoch_millis"));
try { try {
parser.parse("1234567890123", () -> 42, false, DateTimeZone.forTimeZone(TimeZone.getTimeZone("CET"))); parser.parse("1234567890123", () -> 42, false, ZoneId.of("CET"));
fail("Expected ElasticsearchParseException"); fail("Expected ElasticsearchParseException");
} catch(ElasticsearchParseException e) { } catch(ElasticsearchParseException e) {
assertThat(e.getMessage(), containsString("failed to parse date field")); assertThat(e.getMessage(), containsString("failed to parse date field"));

View File

@ -0,0 +1,54 @@
/*
* 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.common.time;
import org.elasticsearch.test.ESTestCase;
import org.joda.time.DateTimeZone;
import java.time.Instant;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import static org.hamcrest.Matchers.equalTo;
public class DateUtilsTests extends ESTestCase {
private static final Set<String> IGNORE = new HashSet<>(Arrays.asList(
"Eire", "Europe/Dublin" // dublin timezone in joda does not account for DST
));
public void testTimezoneIds() {
assertNull(DateUtils.dateTimeZoneToZoneId(null));
assertNull(DateUtils.zoneIdToDateTimeZone(null));
for (String jodaId : DateTimeZone.getAvailableIDs()) {
if (IGNORE.contains(jodaId)) continue;
DateTimeZone jodaTz = DateTimeZone.forID(jodaId);
ZoneId zoneId = DateUtils.dateTimeZoneToZoneId(jodaTz); // does not throw
long now = 0;
assertThat(jodaId, zoneId.getRules().getOffset(Instant.ofEpochMilli(now)).getTotalSeconds() * 1000,
equalTo(jodaTz.getOffset(now)));
if (DateUtils.DEPRECATED_SHORT_TIMEZONES.containsKey(jodaTz.getID())) {
assertWarnings("Use of short timezone id " + jodaId + " is deprecated. Use " + zoneId.getId() + " instead");
}
// roundtrip does not throw either
assertNotNull(DateUtils.zoneIdToDateTimeZone(zoneId));
}
}
}

View File

@ -33,10 +33,10 @@ import java.util.function.LongSupplier;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
public class DateMathParserTests extends ESTestCase { public class JavaDateMathParserTests extends ESTestCase {
private final DateFormatter formatter = DateFormatters.forPattern("dateOptionalTime||epoch_millis"); private final DateFormatter formatter = DateFormatters.forPattern("dateOptionalTime||epoch_millis");
private final DateMathParser parser = new DateMathParser(formatter); private final JavaDateMathParser parser = new JavaDateMathParser(formatter);
public void testBasicDates() { public void testBasicDates() {
assertDateMathEquals("2014", "2014-01-01T00:00:00.000"); assertDateMathEquals("2014", "2014-01-01T00:00:00.000");
@ -125,7 +125,7 @@ public class DateMathParserTests extends ESTestCase {
} }
public void testNow() { public void testNow() {
final long now = parser.parse("2014-11-18T14:27:32", () -> 0, false, null); final long now = parser.parse("2014-11-18T14:27:32", () -> 0, false, (ZoneId) null);
assertDateMathEquals("now", "2014-11-18T14:27:32", now, false, null); assertDateMathEquals("now", "2014-11-18T14:27:32", now, false, null);
assertDateMathEquals("now+M", "2014-12-18T14:27:32", now, false, null); assertDateMathEquals("now+M", "2014-12-18T14:27:32", now, false, null);
@ -139,14 +139,14 @@ public class DateMathParserTests extends ESTestCase {
public void testRoundingPreservesEpochAsBaseDate() { public void testRoundingPreservesEpochAsBaseDate() {
// If a user only specifies times, then the date needs to always be 1970-01-01 regardless of rounding // 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"); DateFormatter formatter = DateFormatters.forPattern("HH:mm:ss");
DateMathParser parser = new DateMathParser(formatter); JavaDateMathParser parser = new JavaDateMathParser(formatter);
ZonedDateTime zonedDateTime = DateFormatters.toZonedDateTime(formatter.parse("04:52:20")); ZonedDateTime zonedDateTime = DateFormatters.toZonedDateTime(formatter.parse("04:52:20"));
assertThat(zonedDateTime.getYear(), is(1970)); assertThat(zonedDateTime.getYear(), is(1970));
long millisStart = zonedDateTime.toInstant().toEpochMilli(); long millisStart = zonedDateTime.toInstant().toEpochMilli();
assertEquals(millisStart, parser.parse("04:52:20", () -> 0, false, null)); 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 // 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.toZonedDateTime(formatter.parse("04:52:20")).toInstant().toEpochMilli() + 999;
assertEquals(millisEnd, parser.parse("04:52:20", () -> 0, true, null)); assertEquals(millisEnd, parser.parse("04:52:20", () -> 0, true, (ZoneId) null));
} }
// Implicit rounding happening when parts of the date are not specified // Implicit rounding happening when parts of the date are not specified
@ -165,10 +165,10 @@ public class DateMathParserTests extends ESTestCase {
// implicit rounding with explicit timezone in the date format // implicit rounding with explicit timezone in the date format
DateFormatter formatter = DateFormatters.forPattern("yyyy-MM-ddXXX"); DateFormatter formatter = DateFormatters.forPattern("yyyy-MM-ddXXX");
DateMathParser parser = new DateMathParser(formatter); JavaDateMathParser parser = new JavaDateMathParser(formatter);
long time = parser.parse("2011-10-09+01:00", () -> 0, false, null); long time = parser.parse("2011-10-09+01:00", () -> 0, false, (ZoneId) null);
assertEquals(this.parser.parse("2011-10-09T00:00:00.000+01:00", () -> 0), time); assertEquals(this.parser.parse("2011-10-09T00:00:00.000+01:00", () -> 0), time);
time = parser.parse("2011-10-09+01:00", () -> 0, true, null); time = parser.parse("2011-10-09+01:00", () -> 0, true, (ZoneId) null);
assertEquals(this.parser.parse("2011-10-09T23:59:59.999+01:00", () -> 0), time); assertEquals(this.parser.parse("2011-10-09T23:59:59.999+01:00", () -> 0), time);
} }
@ -239,7 +239,7 @@ public class DateMathParserTests extends ESTestCase {
assertDateMathEquals("1418248078000||/m", "2014-12-10T21:47:00.000"); assertDateMathEquals("1418248078000||/m", "2014-12-10T21:47:00.000");
// also check other time units // also check other time units
DateMathParser parser = new DateMathParser(DateFormatters.forPattern("epoch_second||dateOptionalTime")); JavaDateMathParser parser = new JavaDateMathParser(DateFormatters.forPattern("epoch_second||dateOptionalTime"));
long datetime = parser.parse("1418248078", () -> 0); long datetime = parser.parse("1418248078", () -> 0);
assertDateEquals(datetime, "1418248078", "2014-12-10T21:47:58.000"); assertDateEquals(datetime, "1418248078", "2014-12-10T21:47:58.000");
@ -279,9 +279,9 @@ public class DateMathParserTests extends ESTestCase {
called.set(true); called.set(true);
return 42L; return 42L;
}; };
parser.parse("2014-11-18T14:27:32", now, false, null); parser.parse("2014-11-18T14:27:32", now, false, (ZoneId) null);
assertFalse(called.get()); assertFalse(called.get());
parser.parse("now/d", now, false, null); parser.parse("now/d", now, false, (ZoneId) null);
assertTrue(called.get()); assertTrue(called.get());
} }

View File

@ -29,12 +29,12 @@ import org.apache.lucene.index.MultiReader;
import org.apache.lucene.search.IndexOrDocValuesQuery; import org.apache.lucene.search.IndexOrDocValuesQuery;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.store.Directory; import org.apache.lucene.store.Directory;
import org.elasticsearch.core.internal.io.IOUtils;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.core.internal.io.IOUtils;
import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType; import org.elasticsearch.index.mapper.DateFieldMapper.DateFieldType;
import org.elasticsearch.index.mapper.MappedFieldType.Relation; import org.elasticsearch.index.mapper.MappedFieldType.Relation;
@ -121,7 +121,7 @@ public class DateFieldTypeTests extends FieldTypeTestCase {
DirectoryReader reader = DirectoryReader.open(w); DirectoryReader reader = DirectoryReader.open(w);
DateFieldType ft = new DateFieldType(); DateFieldType ft = new DateFieldType();
ft.setName("my_date"); ft.setName("my_date");
DateMathParser alternateFormat = new DateMathParser(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER); DateMathParser alternateFormat = DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.toDateMathParser();
doTestIsFieldWithinQuery(ft, reader, null, null); doTestIsFieldWithinQuery(ft, reader, null, null);
doTestIsFieldWithinQuery(ft, reader, null, alternateFormat); doTestIsFieldWithinQuery(ft, reader, null, alternateFormat);
doTestIsFieldWithinQuery(ft, reader, DateTimeZone.UTC, null); doTestIsFieldWithinQuery(ft, reader, DateTimeZone.UTC, null);

View File

@ -31,8 +31,8 @@ import org.apache.lucene.search.Query;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.network.InetAddresses; import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryStringQueryBuilder; import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.internal.SearchContext;

View File

@ -23,9 +23,9 @@ import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchPhaseExecutionException; import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.mapper.DateFieldMapper; import org.elasticsearch.index.mapper.DateFieldMapper;
import org.elasticsearch.index.query.MatchNoneQueryBuilder; import org.elasticsearch.index.query.MatchNoneQueryBuilder;
@ -1120,7 +1120,7 @@ public class DateHistogramIT extends ESIntegTestCase {
.setSettings(Settings.builder().put(indexSettings()).put("index.number_of_shards", 1).put("index.number_of_replicas", 0)) .setSettings(Settings.builder().put(indexSettings()).put("index.number_of_shards", 1).put("index.number_of_replicas", 0))
.execute().actionGet(); .execute().actionGet();
DateMathParser parser = new DateMathParser(Joda.getStrictStandardDateFormatter()); DateMathParser parser = Joda.getStrictStandardDateFormatter().toDateMathParser();
// we pick a random timezone offset of +12/-12 hours and insert two documents // we pick a random timezone offset of +12/-12 hours and insert two documents
// one at 00:00 in that time zone and one at 12:00 // one at 00:00 in that time zone and one at 12:00

View File

@ -408,7 +408,7 @@ public abstract class ESTestCase extends LuceneTestCase {
} }
try { try {
final List<String> actualWarnings = threadContext.getResponseHeaders().get("Warning"); final List<String> actualWarnings = threadContext.getResponseHeaders().get("Warning");
assertNotNull(actualWarnings); assertNotNull("no warnings, expected: " + Arrays.asList(expectedWarnings), actualWarnings);
final Set<String> actualWarningValues = final Set<String> actualWarningValues =
actualWarnings.stream().map(DeprecationLogger::extractWarningValueFromWarningHeader).collect(Collectors.toSet()); actualWarnings.stream().map(DeprecationLogger::extractWarningValueFromWarningHeader).collect(Collectors.toSet());
for (String msg : expectedWarnings) { for (String msg : expectedWarnings) {

View File

@ -6,9 +6,9 @@
package org.elasticsearch.license.licensor; package org.elasticsearch.license.licensor;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
@ -38,8 +38,7 @@ public class TestUtils {
private static final FormatDateTimeFormatter formatDateTimeFormatter = private static final FormatDateTimeFormatter formatDateTimeFormatter =
Joda.forPattern("yyyy-MM-dd"); Joda.forPattern("yyyy-MM-dd");
private static final DateMathParser dateMathParser = private static final DateMathParser dateMathParser = formatDateTimeFormatter.toDateMathParser();
new DateMathParser(formatDateTimeFormatter);
private static final DateTimeFormatter dateTimeFormatter = formatDateTimeFormatter.printer(); private static final DateTimeFormatter dateTimeFormatter = formatDateTimeFormatter.printer();
public static String dumpLicense(License license) throws Exception { public static String dumpLicense(License license) throws Exception {

View File

@ -16,7 +16,7 @@ import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.joda.DateMathParser; import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.ToXContentObject;
@ -88,7 +88,7 @@ public class GetOverallBucketsAction extends Action<GetOverallBucketsAction.Resp
} }
static long parseDateOrThrow(String date, ParseField paramName, LongSupplier now) { static long parseDateOrThrow(String date, ParseField paramName, LongSupplier now) {
DateMathParser dateMathParser = new DateMathParser(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER); DateMathParser dateMathParser = DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.toDateMathParser();
try { try {
return dateMathParser.parse(date, now); return dateMathParser.parse(date, now);

View File

@ -17,7 +17,7 @@ import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.joda.DateMathParser; import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
@ -153,7 +153,7 @@ public class StartDatafeedAction extends Action<AcknowledgedResponse> {
} }
static long parseDateOrThrow(String date, ParseField paramName, LongSupplier now) { static long parseDateOrThrow(String date, ParseField paramName, LongSupplier now) {
DateMathParser dateMathParser = new DateMathParser(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER); DateMathParser dateMathParser = DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER.toDateMathParser();
try { try {
return dateMathParser.parse(date, now); return dateMathParser.parse(date, now);

View File

@ -9,8 +9,8 @@ import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -26,7 +26,7 @@ import java.util.concurrent.TimeUnit;
public class WatcherDateTimeUtils { public class WatcherDateTimeUtils {
public static final FormatDateTimeFormatter dateTimeFormatter = DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER; public static final FormatDateTimeFormatter dateTimeFormatter = DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER;
public static final DateMathParser dateMathParser = new DateMathParser(dateTimeFormatter); public static final DateMathParser dateMathParser = dateTimeFormatter.toDateMathParser();
private WatcherDateTimeUtils() { private WatcherDateTimeUtils() {
} }

View File

@ -10,10 +10,10 @@ import org.elasticsearch.Version;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.FormatDateTimeFormatter; import org.elasticsearch.common.joda.FormatDateTimeFormatter;
import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.time.DateMathParser;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
@ -50,7 +50,7 @@ import static org.junit.Assert.assertThat;
public class TestUtils { public class TestUtils {
private static final FormatDateTimeFormatter formatDateTimeFormatter = Joda.forPattern("yyyy-MM-dd"); private static final FormatDateTimeFormatter formatDateTimeFormatter = Joda.forPattern("yyyy-MM-dd");
private static final DateMathParser dateMathParser = new DateMathParser(formatDateTimeFormatter); private static final DateMathParser dateMathParser = formatDateTimeFormatter.toDateMathParser();
private static final DateTimeFormatter dateTimeFormatter = formatDateTimeFormatter.printer(); private static final DateTimeFormatter dateTimeFormatter = formatDateTimeFormatter.printer();
public static String dateMathString(String time, final long now) { public static String dateMathString(String time, final long now) {

View File

@ -29,7 +29,6 @@ import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchResponseSections; import org.elasticsearch.action.search.SearchResponseSections;
import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.action.search.ShardSearchFailure;
import org.elasticsearch.common.joda.DateMathParser;
import org.elasticsearch.common.joda.Joda; import org.elasticsearch.common.joda.Joda;
import org.elasticsearch.common.rounding.Rounding; import org.elasticsearch.common.rounding.Rounding;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
@ -47,13 +46,13 @@ import org.elasticsearch.search.aggregations.AggregatorTestCase;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregation; import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregation;
import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval; import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.xpack.core.indexing.IndexerState;
import org.elasticsearch.xpack.core.rollup.ConfigTestHelpers; import org.elasticsearch.xpack.core.rollup.ConfigTestHelpers;
import org.elasticsearch.xpack.core.rollup.job.DateHistogramGroupConfig; import org.elasticsearch.xpack.core.rollup.job.DateHistogramGroupConfig;
import org.elasticsearch.xpack.core.rollup.job.GroupConfig; import org.elasticsearch.xpack.core.rollup.job.GroupConfig;
import org.elasticsearch.xpack.core.rollup.job.MetricConfig; import org.elasticsearch.xpack.core.rollup.job.MetricConfig;
import org.elasticsearch.xpack.core.rollup.job.RollupJob; import org.elasticsearch.xpack.core.rollup.job.RollupJob;
import org.elasticsearch.xpack.core.rollup.job.RollupJobConfig; import org.elasticsearch.xpack.core.rollup.job.RollupJobConfig;
import org.elasticsearch.xpack.core.indexing.IndexerState;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.junit.Before; import org.junit.Before;
@ -601,7 +600,7 @@ public class RollupIndexerIndexingTests extends AggregatorTestCase {
RangeQueryBuilder range = (RangeQueryBuilder) request.source().query(); RangeQueryBuilder range = (RangeQueryBuilder) request.source().query();
final DateTimeZone timeZone = range.timeZone() != null ? DateTimeZone.forID(range.timeZone()) : null; final DateTimeZone timeZone = range.timeZone() != null ? DateTimeZone.forID(range.timeZone()) : null;
Query query = timestampField.rangeQuery(range.from(), range.to(), range.includeLower(), range.includeUpper(), Query query = timestampField.rangeQuery(range.from(), range.to(), range.includeLower(), range.includeUpper(),
null, timeZone, new DateMathParser(Joda.forPattern(range.format())), queryShardContext); null, timeZone, Joda.forPattern(range.format()).toDateMathParser(), queryShardContext);
// extract composite agg // extract composite agg
assertThat(request.source().aggregations().getAggregatorFactories().size(), equalTo(1)); assertThat(request.source().aggregations().getAggregatorFactories().size(), equalTo(1));