Merge pull request #12581 from cbuescher/fix/12531
Fix setting timezone on default DateTime formatter
This commit is contained in:
commit
a269b96799
|
@ -64,6 +64,9 @@ public abstract class TimeZoneRounding extends Rounding {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder timeZone(DateTimeZone timeZone) {
|
public Builder timeZone(DateTimeZone timeZone) {
|
||||||
|
if (timeZone == null) {
|
||||||
|
throw new IllegalArgumentException("Setting null as timezone is not supported");
|
||||||
|
}
|
||||||
this.timeZone = timeZone;
|
this.timeZone = timeZone;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,7 @@ import org.elasticsearch.search.aggregations.AggregatorFactory;
|
||||||
import org.elasticsearch.search.aggregations.support.ValueType;
|
import org.elasticsearch.search.aggregations.support.ValueType;
|
||||||
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
|
import org.elasticsearch.search.aggregations.support.ValuesSourceConfig;
|
||||||
import org.elasticsearch.search.aggregations.support.ValuesSourceParser;
|
import org.elasticsearch.search.aggregations.support.ValuesSourceParser;
|
||||||
import org.elasticsearch.search.aggregations.support.format.ValueFormatter.DateTime;
|
|
||||||
import org.elasticsearch.search.internal.SearchContext;
|
import org.elasticsearch.search.internal.SearchContext;
|
||||||
import org.joda.time.DateTimeZone;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,7 +42,6 @@ import java.io.IOException;
|
||||||
public class DateHistogramParser implements Aggregator.Parser {
|
public class DateHistogramParser implements Aggregator.Parser {
|
||||||
|
|
||||||
static final ParseField EXTENDED_BOUNDS = new ParseField("extended_bounds");
|
static final ParseField EXTENDED_BOUNDS = new ParseField("extended_bounds");
|
||||||
static final ParseField TIME_ZONE = new ParseField("time_zone");
|
|
||||||
static final ParseField OFFSET = new ParseField("offset");
|
static final ParseField OFFSET = new ParseField("offset");
|
||||||
static final ParseField INTERVAL = new ParseField("interval");
|
static final ParseField INTERVAL = new ParseField("interval");
|
||||||
|
|
||||||
|
@ -83,6 +79,7 @@ public class DateHistogramParser implements Aggregator.Parser {
|
||||||
ValuesSourceParser vsParser = ValuesSourceParser.numeric(aggregationName, InternalDateHistogram.TYPE, context)
|
ValuesSourceParser vsParser = ValuesSourceParser.numeric(aggregationName, InternalDateHistogram.TYPE, context)
|
||||||
.targetValueType(ValueType.DATE)
|
.targetValueType(ValueType.DATE)
|
||||||
.formattable(true)
|
.formattable(true)
|
||||||
|
.timezoneAware(true)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
boolean keyed = false;
|
boolean keyed = false;
|
||||||
|
@ -90,7 +87,6 @@ public class DateHistogramParser implements Aggregator.Parser {
|
||||||
ExtendedBounds extendedBounds = null;
|
ExtendedBounds extendedBounds = null;
|
||||||
InternalOrder order = (InternalOrder) Histogram.Order.KEY_ASC;
|
InternalOrder order = (InternalOrder) Histogram.Order.KEY_ASC;
|
||||||
String interval = null;
|
String interval = null;
|
||||||
DateTimeZone timeZone = DateTimeZone.UTC;
|
|
||||||
long offset = 0;
|
long offset = 0;
|
||||||
|
|
||||||
XContentParser.Token token;
|
XContentParser.Token token;
|
||||||
|
@ -101,9 +97,7 @@ public class DateHistogramParser implements Aggregator.Parser {
|
||||||
} else if (vsParser.token(currentFieldName, token, parser)) {
|
} else if (vsParser.token(currentFieldName, token, parser)) {
|
||||||
continue;
|
continue;
|
||||||
} else if (token == XContentParser.Token.VALUE_STRING) {
|
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||||
if (context.parseFieldMatcher().match(currentFieldName, TIME_ZONE)) {
|
if (context.parseFieldMatcher().match(currentFieldName, OFFSET)) {
|
||||||
timeZone = DateTimeZone.forID(parser.text());
|
|
||||||
} else if (context.parseFieldMatcher().match(currentFieldName, OFFSET)) {
|
|
||||||
offset = parseOffset(parser.text());
|
offset = parseOffset(parser.text());
|
||||||
} else if (context.parseFieldMatcher().match(currentFieldName, INTERVAL)) {
|
} else if (context.parseFieldMatcher().match(currentFieldName, INTERVAL)) {
|
||||||
interval = parser.text();
|
interval = parser.text();
|
||||||
|
@ -121,8 +115,6 @@ public class DateHistogramParser implements Aggregator.Parser {
|
||||||
} else if (token == XContentParser.Token.VALUE_NUMBER) {
|
} else if (token == XContentParser.Token.VALUE_NUMBER) {
|
||||||
if ("min_doc_count".equals(currentFieldName) || "minDocCount".equals(currentFieldName)) {
|
if ("min_doc_count".equals(currentFieldName) || "minDocCount".equals(currentFieldName)) {
|
||||||
minDocCount = parser.longValue();
|
minDocCount = parser.longValue();
|
||||||
} else if ("time_zone".equals(currentFieldName) || "timeZone".equals(currentFieldName)) {
|
|
||||||
timeZone = DateTimeZone.forOffsetHours(parser.intValue());
|
|
||||||
} else {
|
} else {
|
||||||
throw new SearchParseException(context, "Unknown key for a " + token + " in [" + aggregationName + "]: ["
|
throw new SearchParseException(context, "Unknown key for a " + token + " in [" + aggregationName + "]: ["
|
||||||
+ currentFieldName + "].", parser.getTokenLocation());
|
+ currentFieldName + "].", parser.getTokenLocation());
|
||||||
|
@ -193,13 +185,10 @@ public class DateHistogramParser implements Aggregator.Parser {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rounding rounding = tzRoundingBuilder
|
Rounding rounding = tzRoundingBuilder
|
||||||
.timeZone(timeZone)
|
.timeZone(vsParser.input().timezone())
|
||||||
.offset(offset).build();
|
.offset(offset).build();
|
||||||
|
|
||||||
ValuesSourceConfig config = vsParser.config();
|
ValuesSourceConfig config = vsParser.config();
|
||||||
if (config.formatter()!=null) {
|
|
||||||
((DateTime) config.formatter()).setTimeZone(timeZone);
|
|
||||||
}
|
|
||||||
return new HistogramAggregator.Factory(aggregationName, config, rounding, order, keyed, minDocCount, extendedBounds,
|
return new HistogramAggregator.Factory(aggregationName, config, rounding, order, keyed, minDocCount, extendedBounds,
|
||||||
new InternalDateHistogram.Factory());
|
new InternalDateHistogram.Factory());
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
package org.elasticsearch.search.aggregations.support;
|
package org.elasticsearch.search.aggregations.support;
|
||||||
|
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.index.fielddata.IndexFieldData;
|
import org.elasticsearch.index.fielddata.IndexFieldData;
|
||||||
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
|
import org.elasticsearch.index.fielddata.IndexGeoPointFieldData;
|
||||||
|
@ -39,6 +40,7 @@ import org.elasticsearch.search.SearchParseException;
|
||||||
import org.elasticsearch.search.aggregations.InternalAggregation;
|
import org.elasticsearch.search.aggregations.InternalAggregation;
|
||||||
import org.elasticsearch.search.aggregations.support.format.ValueFormat;
|
import org.elasticsearch.search.aggregations.support.format.ValueFormat;
|
||||||
import org.elasticsearch.search.internal.SearchContext;
|
import org.elasticsearch.search.internal.SearchContext;
|
||||||
|
import org.joda.time.DateTimeZone;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -50,6 +52,8 @@ import static com.google.common.collect.Maps.newHashMap;
|
||||||
*/
|
*/
|
||||||
public class ValuesSourceParser<VS extends ValuesSource> {
|
public class ValuesSourceParser<VS extends ValuesSource> {
|
||||||
|
|
||||||
|
static final ParseField TIME_ZONE = new ParseField("time_zone");
|
||||||
|
|
||||||
public static Builder any(String aggName, InternalAggregation.Type aggType, SearchContext context) {
|
public static Builder any(String aggName, InternalAggregation.Type aggType, SearchContext context) {
|
||||||
return new Builder<>(aggName, aggType, context, ValuesSource.class);
|
return new Builder<>(aggName, aggType, context, ValuesSource.class);
|
||||||
}
|
}
|
||||||
|
@ -66,14 +70,19 @@ public class ValuesSourceParser<VS extends ValuesSource> {
|
||||||
return new Builder<>(aggName, aggType, context, ValuesSource.GeoPoint.class).targetValueType(ValueType.GEOPOINT).scriptable(false);
|
return new Builder<>(aggName, aggType, context, ValuesSource.GeoPoint.class).targetValueType(ValueType.GEOPOINT).scriptable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Input {
|
public static class Input {
|
||||||
String field = null;
|
private String field = null;
|
||||||
Script script = null;
|
private Script script = null;
|
||||||
@Deprecated
|
@Deprecated
|
||||||
Map<String, Object> params = null; // TODO Remove in 3.0
|
private Map<String, Object> params = null; // TODO Remove in 3.0
|
||||||
ValueType valueType = null;
|
private ValueType valueType = null;
|
||||||
String format = null;
|
private String format = null;
|
||||||
Object missing = null;
|
private Object missing = null;
|
||||||
|
private DateTimeZone timezone = DateTimeZone.UTC;
|
||||||
|
|
||||||
|
public DateTimeZone timezone() {
|
||||||
|
return this.timezone;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String aggName;
|
private final String aggName;
|
||||||
|
@ -83,6 +92,7 @@ public class ValuesSourceParser<VS extends ValuesSource> {
|
||||||
|
|
||||||
private boolean scriptable = true;
|
private boolean scriptable = true;
|
||||||
private boolean formattable = false;
|
private boolean formattable = false;
|
||||||
|
private boolean timezoneAware = false;
|
||||||
private ValueType targetValueType = null;
|
private ValueType targetValueType = null;
|
||||||
private ScriptParameterParser scriptParameterParser = new ScriptParameterParser();
|
private ScriptParameterParser scriptParameterParser = new ScriptParameterParser();
|
||||||
|
|
||||||
|
@ -105,6 +115,8 @@ public class ValuesSourceParser<VS extends ValuesSource> {
|
||||||
input.field = parser.text();
|
input.field = parser.text();
|
||||||
} else if (formattable && "format".equals(currentFieldName)) {
|
} else if (formattable && "format".equals(currentFieldName)) {
|
||||||
input.format = parser.text();
|
input.format = parser.text();
|
||||||
|
} else if (timezoneAware && context.parseFieldMatcher().match(currentFieldName, TIME_ZONE)) {
|
||||||
|
input.timezone = DateTimeZone.forID(parser.text());
|
||||||
} else if (scriptable) {
|
} else if (scriptable) {
|
||||||
if ("value_type".equals(currentFieldName) || "valueType".equals(currentFieldName)) {
|
if ("value_type".equals(currentFieldName) || "valueType".equals(currentFieldName)) {
|
||||||
input.valueType = ValueType.resolveForScript(parser.text());
|
input.valueType = ValueType.resolveForScript(parser.text());
|
||||||
|
@ -123,6 +135,14 @@ public class ValuesSourceParser<VS extends ValuesSource> {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (token == XContentParser.Token.VALUE_NUMBER) {
|
||||||
|
if (timezoneAware && context.parseFieldMatcher().match(currentFieldName, TIME_ZONE)) {
|
||||||
|
input.timezone = DateTimeZone.forOffsetHours(parser.intValue());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (scriptable && token == XContentParser.Token.START_OBJECT) {
|
if (scriptable && token == XContentParser.Token.START_OBJECT) {
|
||||||
if (context.parseFieldMatcher().match(currentFieldName, ScriptField.SCRIPT)) {
|
if (context.parseFieldMatcher().match(currentFieldName, ScriptField.SCRIPT)) {
|
||||||
input.script = Script.parse(parser, context.parseFieldMatcher());
|
input.script = Script.parse(parser, context.parseFieldMatcher());
|
||||||
|
@ -203,7 +223,7 @@ public class ValuesSourceParser<VS extends ValuesSource> {
|
||||||
config.fieldContext = new FieldContext(input.field, indexFieldData, fieldType);
|
config.fieldContext = new FieldContext(input.field, indexFieldData, fieldType);
|
||||||
config.missing = input.missing;
|
config.missing = input.missing;
|
||||||
config.script = createScript();
|
config.script = createScript();
|
||||||
config.format = resolveFormat(input.format, fieldType);
|
config.format = resolveFormat(input.format, input.timezone, fieldType);
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,9 +242,9 @@ public class ValuesSourceParser<VS extends ValuesSource> {
|
||||||
return valueFormat;
|
return valueFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ValueFormat resolveFormat(@Nullable String format, MappedFieldType fieldType) {
|
private static ValueFormat resolveFormat(@Nullable String format, @Nullable DateTimeZone timezone, MappedFieldType fieldType) {
|
||||||
if (fieldType instanceof DateFieldMapper.DateFieldType) {
|
if (fieldType instanceof DateFieldMapper.DateFieldType) {
|
||||||
return format != null ? ValueFormat.DateTime.format(format) : ValueFormat.DateTime.mapper((DateFieldMapper.DateFieldType) fieldType);
|
return format != null ? ValueFormat.DateTime.format(format, timezone) : ValueFormat.DateTime.mapper((DateFieldMapper.DateFieldType) fieldType, timezone);
|
||||||
}
|
}
|
||||||
if (fieldType instanceof IpFieldMapper.IpFieldType) {
|
if (fieldType instanceof IpFieldMapper.IpFieldType) {
|
||||||
return ValueFormat.IPv4;
|
return ValueFormat.IPv4;
|
||||||
|
@ -238,6 +258,10 @@ public class ValuesSourceParser<VS extends ValuesSource> {
|
||||||
return ValueFormat.RAW;
|
return ValueFormat.RAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Input input() {
|
||||||
|
return this.input;
|
||||||
|
}
|
||||||
|
|
||||||
public static class Builder<VS extends ValuesSource> {
|
public static class Builder<VS extends ValuesSource> {
|
||||||
|
|
||||||
private final ValuesSourceParser<VS> parser;
|
private final ValuesSourceParser<VS> parser;
|
||||||
|
@ -256,6 +280,11 @@ public class ValuesSourceParser<VS extends ValuesSource> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder<VS> timezoneAware(boolean timezoneAware) {
|
||||||
|
parser.timezoneAware = timezoneAware;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public Builder<VS> targetValueType(ValueType valueType) {
|
public Builder<VS> targetValueType(ValueType valueType) {
|
||||||
parser.targetValueType = valueType;
|
parser.targetValueType = valueType;
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
package org.elasticsearch.search.aggregations.support.format;
|
package org.elasticsearch.search.aggregations.support.format;
|
||||||
|
|
||||||
import org.elasticsearch.index.mapper.core.DateFieldMapper;
|
import org.elasticsearch.index.mapper.core.DateFieldMapper;
|
||||||
|
import org.joda.time.DateTimeZone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -67,12 +68,12 @@ public class ValueFormat {
|
||||||
|
|
||||||
public static final DateTime DEFAULT = new DateTime(DateFieldMapper.Defaults.DATE_TIME_FORMATTER.format(), ValueFormatter.DateTime.DEFAULT, ValueParser.DateMath.DEFAULT);
|
public static final DateTime DEFAULT = new DateTime(DateFieldMapper.Defaults.DATE_TIME_FORMATTER.format(), ValueFormatter.DateTime.DEFAULT, ValueParser.DateMath.DEFAULT);
|
||||||
|
|
||||||
public static DateTime format(String format) {
|
public static DateTime format(String format, DateTimeZone timezone) {
|
||||||
return new DateTime(format, new ValueFormatter.DateTime(format), new ValueParser.DateMath(format));
|
return new DateTime(format, new ValueFormatter.DateTime(format, timezone), new ValueParser.DateMath(format));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DateTime mapper(DateFieldMapper.DateFieldType fieldType) {
|
public static DateTime mapper(DateFieldMapper.DateFieldType fieldType, DateTimeZone timezone) {
|
||||||
return new DateTime(fieldType.dateTimeFormatter().format(), ValueFormatter.DateTime.mapper(fieldType), ValueParser.DateMath.mapper(fieldType));
|
return new DateTime(fieldType.dateTimeFormatter().format(), ValueFormatter.DateTime.mapper(fieldType, timezone), ValueParser.DateMath.mapper(fieldType));
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime(String pattern, ValueFormatter formatter, ValueParser parser) {
|
public DateTime(String pattern, ValueFormatter formatter, ValueParser parser) {
|
||||||
|
@ -81,7 +82,7 @@ public class ValueFormat {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DateTime create(String pattern) {
|
public DateTime create(String pattern) {
|
||||||
return format(pattern);
|
return format(pattern, DateTimeZone.UTC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ import java.text.DecimalFormat;
|
||||||
import java.text.DecimalFormatSymbols;
|
import java.text.DecimalFormatSymbols;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A strategy for formatting time represented as millis long value to string
|
* A strategy for formatting time represented as millis long value to string
|
||||||
|
@ -61,7 +60,6 @@ public interface ValueFormatter extends Streamable {
|
||||||
String format(long value);
|
String format(long value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The
|
|
||||||
* @param value double The double value to format.
|
* @param value double The double value to format.
|
||||||
* @return The formatted value as string
|
* @return The formatted value as string
|
||||||
*/
|
*/
|
||||||
|
@ -104,8 +102,8 @@ public interface ValueFormatter extends Streamable {
|
||||||
public static final ValueFormatter DEFAULT = new ValueFormatter.DateTime(DateFieldMapper.Defaults.DATE_TIME_FORMATTER);
|
public static final ValueFormatter DEFAULT = new ValueFormatter.DateTime(DateFieldMapper.Defaults.DATE_TIME_FORMATTER);
|
||||||
private DateTimeZone timeZone = DateTimeZone.UTC;
|
private DateTimeZone timeZone = DateTimeZone.UTC;
|
||||||
|
|
||||||
public static DateTime mapper(DateFieldMapper.DateFieldType fieldType) {
|
public static DateTime mapper(DateFieldMapper.DateFieldType fieldType, DateTimeZone timezone) {
|
||||||
return new DateTime(fieldType.dateTimeFormatter());
|
return new DateTime(fieldType.dateTimeFormatter(), timezone);
|
||||||
}
|
}
|
||||||
|
|
||||||
static final byte ID = 2;
|
static final byte ID = 2;
|
||||||
|
@ -122,15 +120,21 @@ public interface ValueFormatter extends Streamable {
|
||||||
this.formatter = formatter;
|
this.formatter = formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DateTime(String format, DateTimeZone timezone) {
|
||||||
|
this.formatter = Joda.forPattern(format);
|
||||||
|
this.timeZone = timezone != null ? timezone : DateTimeZone.UTC;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime(FormatDateTimeFormatter formatter, DateTimeZone timezone) {
|
||||||
|
this.formatter = formatter;
|
||||||
|
this.timeZone = timezone != null ? timezone : DateTimeZone.UTC;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String format(long time) {
|
public String format(long time) {
|
||||||
return formatter.printer().withZone(timeZone).print(time);
|
return formatter.printer().withZone(timeZone).print(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTimeZone(DateTimeZone timeZone) {
|
|
||||||
this.timeZone = timeZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String format(double value) {
|
public String format(double value) {
|
||||||
return format((long) value);
|
return format((long) value);
|
||||||
|
@ -264,7 +268,7 @@ public interface ValueFormatter extends Streamable {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class BooleanFormatter implements ValueFormatter {
|
static class BooleanFormatter implements ValueFormatter {
|
||||||
|
|
||||||
static final byte ID = 10;
|
static final byte ID = 10;
|
||||||
|
|
Loading…
Reference in New Issue