Merge pull request #12886 from cbuescher/fix/12278
Make ValueParser.DateMath aware of timezone setting
This commit is contained in:
commit
0fc96ede69
|
@ -69,14 +69,14 @@ 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, DateTimeZone timezone) {
|
public static DateTime format(String format, DateTimeZone timezone) {
|
||||||
return new DateTime(format, new ValueFormatter.DateTime(format, timezone), new ValueParser.DateMath(format));
|
return new DateTime(format, new ValueFormatter.DateTime(format, timezone), new ValueParser.DateMath(format, timezone));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DateTime mapper(DateFieldMapper.DateFieldType fieldType, DateTimeZone timezone) {
|
public static DateTime mapper(DateFieldMapper.DateFieldType fieldType, DateTimeZone timezone) {
|
||||||
return new DateTime(fieldType.dateTimeFormatter().format(), ValueFormatter.DateTime.mapper(fieldType, timezone), ValueParser.DateMath.mapper(fieldType));
|
return new DateTime(fieldType.dateTimeFormatter().format(), ValueFormatter.DateTime.mapper(fieldType, timezone), ValueParser.DateMath.mapper(fieldType, timezone));
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateTime(String pattern, ValueFormatter formatter, ValueParser parser) {
|
private DateTime(String pattern, ValueFormatter formatter, ValueParser parser) {
|
||||||
super(pattern, formatter, parser);
|
super(pattern, formatter, parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
package org.elasticsearch.search.aggregations.support.format;
|
package org.elasticsearch.search.aggregations.support.format;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.joda.DateMathParser;
|
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;
|
||||||
|
@ -25,6 +26,7 @@ import org.elasticsearch.index.mapper.core.DateFieldMapper;
|
||||||
import org.elasticsearch.index.mapper.ip.IpFieldMapper;
|
import org.elasticsearch.index.mapper.ip.IpFieldMapper;
|
||||||
import org.elasticsearch.search.aggregations.AggregationExecutionException;
|
import org.elasticsearch.search.aggregations.AggregationExecutionException;
|
||||||
import org.elasticsearch.search.internal.SearchContext;
|
import org.elasticsearch.search.internal.SearchContext;
|
||||||
|
import org.joda.time.DateTimeZone;
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.text.DecimalFormatSymbols;
|
import java.text.DecimalFormatSymbols;
|
||||||
|
@ -80,16 +82,21 @@ public interface ValueParser {
|
||||||
*/
|
*/
|
||||||
static class DateMath implements ValueParser {
|
static class DateMath implements ValueParser {
|
||||||
|
|
||||||
public static final DateMath DEFAULT = new ValueParser.DateMath(new DateMathParser(DateFieldMapper.Defaults.DATE_TIME_FORMATTER));
|
public static final DateMath DEFAULT = new ValueParser.DateMath(new DateMathParser(DateFieldMapper.Defaults.DATE_TIME_FORMATTER), DateTimeZone.UTC);
|
||||||
|
|
||||||
private DateMathParser parser;
|
private DateMathParser parser;
|
||||||
|
|
||||||
public DateMath(String format) {
|
private DateTimeZone timezone = DateTimeZone.UTC;
|
||||||
this(new DateMathParser(Joda.forPattern(format)));
|
|
||||||
|
public DateMath(String format, DateTimeZone timezone) {
|
||||||
|
this(new DateMathParser(Joda.forPattern(format)), timezone);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DateMath(DateMathParser parser) {
|
public DateMath(DateMathParser parser, @Nullable DateTimeZone timeZone) {
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
|
if (timeZone != null) {
|
||||||
|
this.timezone = timeZone;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -100,7 +107,7 @@ public interface ValueParser {
|
||||||
return searchContext.nowInMillis();
|
return searchContext.nowInMillis();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return parser.parse(value, now);
|
return parser.parse(value, now, false, timezone);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -108,8 +115,8 @@ public interface ValueParser {
|
||||||
return parseLong(value, searchContext);
|
return parseLong(value, searchContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DateMath mapper(DateFieldMapper.DateFieldType fieldType) {
|
public static DateMath mapper(DateFieldMapper.DateFieldType fieldType, @Nullable DateTimeZone timezone) {
|
||||||
return new DateMath(new DateMathParser(fieldType.dateTimeFormatter()));
|
return new DateMath(new DateMathParser(fieldType.dateTimeFormatter()), timezone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,11 @@ package org.elasticsearch.search.aggregations.bucket;
|
||||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
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.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.index.mapper.core.DateFieldMapper;
|
import org.elasticsearch.index.mapper.core.DateFieldMapper;
|
||||||
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
import org.elasticsearch.script.Script;
|
import org.elasticsearch.script.Script;
|
||||||
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
|
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
|
||||||
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
|
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
|
||||||
|
@ -42,6 +44,7 @@ import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -1195,6 +1198,70 @@ public class DateHistogramIT extends ESIntegTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test date histogram aggregation with hour interval, timezone shift and
|
||||||
|
* extended bounds (see https://github.com/elastic/elasticsearch/issues/12278)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void singleValueField_WithExtendedBoundsTimezone() throws Exception {
|
||||||
|
|
||||||
|
String index = "test12278";
|
||||||
|
prepareCreate(index)
|
||||||
|
.setSettings(Settings.builder().put(indexSettings()).put("index.number_of_shards", 1).put("index.number_of_replicas", 0))
|
||||||
|
.execute().actionGet();
|
||||||
|
|
||||||
|
DateMathParser parser = new DateMathParser(Joda.getStrictStandardDateFormatter());
|
||||||
|
|
||||||
|
final Callable<Long> callable = new Callable<Long>() {
|
||||||
|
@Override
|
||||||
|
public Long call() throws Exception {
|
||||||
|
return System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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
|
||||||
|
List<IndexRequestBuilder> builders = new ArrayList<>();
|
||||||
|
int timeZoneHourOffset = randomIntBetween(-12, 12);
|
||||||
|
DateTimeZone timezone = DateTimeZone.forOffsetHours(timeZoneHourOffset);
|
||||||
|
DateTime timeZoneStartToday = new DateTime(parser.parse("now/d", callable, false, timezone), DateTimeZone.UTC);
|
||||||
|
DateTime timeZoneNoonToday = new DateTime(parser.parse("now/d+12h", callable, false, timezone), DateTimeZone.UTC);
|
||||||
|
builders.add(indexDoc(index, timeZoneStartToday, 1));
|
||||||
|
builders.add(indexDoc(index, timeZoneNoonToday, 2));
|
||||||
|
indexRandom(true, builders);
|
||||||
|
ensureSearchable(index);
|
||||||
|
|
||||||
|
SearchResponse response = null;
|
||||||
|
// retrieve those docs with the same time zone and extended bounds
|
||||||
|
response = client()
|
||||||
|
.prepareSearch(index)
|
||||||
|
.setQuery(QueryBuilders.rangeQuery("date").from("now/d").to("now/d").includeLower(true).includeUpper(true).timeZone(timezone.getID()))
|
||||||
|
.addAggregation(
|
||||||
|
dateHistogram("histo").field("date").interval(DateHistogramInterval.hours(1)).timeZone(timezone.getID()).minDocCount(0)
|
||||||
|
.extendedBounds("now/d", "now/d+23h")
|
||||||
|
).execute().actionGet();
|
||||||
|
assertSearchResponse(response);
|
||||||
|
|
||||||
|
assertThat("Expected 24 buckets for one day aggregation with hourly interval", response.getHits().totalHits(), equalTo(2l));
|
||||||
|
|
||||||
|
Histogram histo = response.getAggregations().get("histo");
|
||||||
|
assertThat(histo, notNullValue());
|
||||||
|
assertThat(histo.getName(), equalTo("histo"));
|
||||||
|
List<? extends Bucket> buckets = histo.getBuckets();
|
||||||
|
assertThat(buckets.size(), equalTo(24));
|
||||||
|
|
||||||
|
for (int i = 0; i < buckets.size(); i++) {
|
||||||
|
Histogram.Bucket bucket = buckets.get(i);
|
||||||
|
assertThat(bucket, notNullValue());
|
||||||
|
assertThat("Bucket " + i +" had wrong key", (DateTime) bucket.getKey(), equalTo(new DateTime(timeZoneStartToday.getMillis() + (i * 60 * 60 * 1000), DateTimeZone.UTC)));
|
||||||
|
if (i == 0 || i == 12) {
|
||||||
|
assertThat(bucket.getDocCount(), equalTo(1l));
|
||||||
|
} else {
|
||||||
|
assertThat(bucket.getDocCount(), equalTo(0l));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void singleValue_WithMultipleDateFormatsFromMapping() throws Exception {
|
public void singleValue_WithMultipleDateFormatsFromMapping() throws Exception {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue