Skip to content

Commit dff19cb

Browse files
author
Christoph Büscher
committed
DateMath: Fix using time zone when rounding.
Currently rounding in DateMathParser This always done in UTC, even when another time zone is specified. This is fixed by passing the time zone down to the rounding logic when it is specified. Closes #9814 Closes #9885
1 parent 2d20fd8 commit dff19cb

File tree

2 files changed

+84
-6
lines changed

2 files changed

+84
-6
lines changed

src/main/java/org/elasticsearch/common/joda/DateMathParser.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,14 @@ public long parse(String text, Callable<Long> now, boolean roundCeil, DateTimeZo
9494
if (mathString.isEmpty()) {
9595
return time;
9696
}
97-
98-
return parseMath(mathString, time, roundCeil);
97+
return parseMath(mathString, time, roundCeil, timeZone);
9998
}
10099

101-
private long parseMath(String mathString, long time, boolean roundUp) throws ElasticsearchParseException {
102-
MutableDateTime dateTime = new MutableDateTime(time, DateTimeZone.UTC);
100+
private long parseMath(String mathString, long time, boolean roundUp, DateTimeZone timeZone) throws ElasticsearchParseException {
101+
if (timeZone == null) {
102+
timeZone = DateTimeZone.UTC;
103+
}
104+
MutableDateTime dateTime = new MutableDateTime(time, timeZone);
103105
try {
104106
for (int i = 0; i < mathString.length(); ) {
105107
char c = mathString.charAt(i++);

src/test/java/org/elasticsearch/common/joda/DateMathParserTests.java

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.elasticsearch.common.joda;
2121

2222
import org.elasticsearch.test.ElasticsearchTestCase;
23+
import org.joda.time.DateTimeZone;
2324
import org.junit.Test;
2425

2526
import java.util.concurrent.Callable;
@@ -32,6 +33,9 @@
3233
*/
3334
public class DateMathParserTests extends ElasticsearchTestCase {
3435

36+
FormatDateTimeFormatter formatter = Joda.forPattern("dateOptionalTime");
37+
DateMathParser parser = new DateMathParser(formatter, TimeUnit.MILLISECONDS);
38+
3539
private static Callable<Long> callable(final long value) {
3640
return new Callable<Long>() {
3741
@Override
@@ -41,6 +45,27 @@ public Long call() throws Exception {
4145
};
4246
}
4347

48+
void assertDateMathEquals(String toTest, String expected) {
49+
assertDateMathEquals(toTest, expected, 0, false, null);
50+
}
51+
52+
void assertDateMathEquals(String toTest, String expected, final long now, boolean roundUp, DateTimeZone timeZone) {
53+
long gotMillis = parser.parse(toTest, callable(now), roundUp, timeZone);
54+
assertDateEquals(gotMillis, toTest, expected);
55+
}
56+
57+
void assertDateEquals(long gotMillis, String original, String expected) {
58+
long expectedMillis = parser.parse(expected, callable(0));
59+
if (gotMillis != expectedMillis) {
60+
fail("Date math not equal\n" +
61+
"Original : " + original + "\n" +
62+
"Parsed : " + formatter.printer().print(gotMillis) + "\n" +
63+
"Expected : " + expected + "\n" +
64+
"Expected milliseconds : " + expectedMillis + "\n" +
65+
"Actual milliseconds : " + gotMillis + "\n");
66+
}
67+
}
68+
4469
@Test
4570
public void dataMathTests() {
4671
DateMathParser parser = new DateMathParser(Joda.forPattern("dateOptionalTime"), TimeUnit.MILLISECONDS);
@@ -57,18 +82,69 @@ public void dataMathTests() {
5782

5883
assertThat(parser.parse("now+1m+1s/m", callable(0)), equalTo(TimeUnit.MINUTES.toMillis(1)));
5984
assertThat(parser.parseRoundCeil("now+1m+1s/m", callable(0)), equalTo(TimeUnit.MINUTES.toMillis(2)));
60-
85+
6186
assertThat(parser.parse("now+4y", callable(0)), equalTo(TimeUnit.DAYS.toMillis(4*365 + 1)));
6287
}
6388

89+
public void testRounding() {
90+
assertDateMathEquals("2014-11-18||/y", "2014-01-01", 0, false, null);
91+
assertDateMathEquals("2014-11-18||/y", "2015-01-01T00:00:00.000", 0, true, null);
92+
assertDateMathEquals("2014||/y", "2014-01-01", 0, false, null);
93+
assertDateMathEquals("2014-01-01T00:00:00.001||/y", "2015-01-01T00:00:00.000", 0, true, null);
94+
// rounding should also take into account time zone
95+
assertDateMathEquals("2014-11-18||/y", "2013-12-31T23:00:00.000Z", 0, false, DateTimeZone.forID("CET"));
96+
assertDateMathEquals("2014-11-18||/y", "2014-12-31T23:00:00.000", 0, true, DateTimeZone.forID("CET"));
97+
98+
assertDateMathEquals("2014-11-18||/M", "2014-11-01", 0, false, null);
99+
assertDateMathEquals("2014-11-18||/M", "2014-12-01T00:00:00.000", 0, true, null);
100+
assertDateMathEquals("2014-11||/M", "2014-11-01", 0, false, null);
101+
assertDateMathEquals("2014-11||/M", "2014-12-01T00:00:00.000", 0, true, null);
102+
assertDateMathEquals("2014-11-18||/M", "2014-10-31T23:00:00.000Z", 0, false, DateTimeZone.forID("CET"));
103+
assertDateMathEquals("2014-11-18||/M", "2014-11-30T23:00:00.000Z", 0, true, DateTimeZone.forID("CET"));
104+
105+
assertDateMathEquals("2014-11-18T14||/w", "2014-11-17", 0, false, null);
106+
assertDateMathEquals("2014-11-18T14||/w", "2014-11-24T00:00:00.000", 0, true, null);
107+
assertDateMathEquals("2014-11-18||/w", "2014-11-17", 0, false, null);
108+
assertDateMathEquals("2014-11-18||/w", "2014-11-24T00:00:00.000", 0, true, null);
109+
assertDateMathEquals("2014-11-18||/w", "2014-11-16T23:00:00.000Z", 0, false, DateTimeZone.forID("+01:00"));
110+
assertDateMathEquals("2014-11-18||/w", "2014-11-17T01:00:00.000Z", 0, false, DateTimeZone.forID("-01:00"));
111+
assertDateMathEquals("2014-11-18||/w", "2014-11-16T23:00:00.000Z", 0, false, DateTimeZone.forID("CET"));
112+
assertDateMathEquals("2014-11-18||/w", "2014-11-23T23:00:00.000Z", 0, true, DateTimeZone.forID("CET"));
113+
assertDateMathEquals("2014-07-22||/w", "2014-07-20T22:00:00.000Z", 0, false, DateTimeZone.forID("CET")); // with DST
114+
115+
assertDateMathEquals("2014-11-18T14||/d", "2014-11-18", 0, false, null);
116+
assertDateMathEquals("2014-11-18T14||/d", "2014-11-19T00:00:00.000", 0, true, null);
117+
assertDateMathEquals("2014-11-18||/d", "2014-11-18", 0, false, null);
118+
assertDateMathEquals("2014-11-18||/d", "2014-11-19T00:00:00.000", 0, true, null);
119+
120+
assertDateMathEquals("2014-11-18T14:27||/h", "2014-11-18T14", 0, false, null);
121+
assertDateMathEquals("2014-11-18T14:27||/h", "2014-11-18T15:00:00.000", 0, true, null);
122+
assertDateMathEquals("2014-11-18T14||/H", "2014-11-18T14", 0, false, null);
123+
assertDateMathEquals("2014-11-18T14||/H", "2014-11-18T15:00:00.000", 0, true, null);
124+
assertDateMathEquals("2014-11-18T14:27||/h", "2014-11-18T14", 0, false, null);
125+
assertDateMathEquals("2014-11-18T14:27||/h", "2014-11-18T15:00:00.000", 0, true, null);
126+
assertDateMathEquals("2014-11-18T14||/H", "2014-11-18T14", 0, false, null);
127+
assertDateMathEquals("2014-11-18T14||/H", "2014-11-18T15:00:00.000", 0, true, null);
128+
129+
assertDateMathEquals("2014-11-18T14:27:32||/m", "2014-11-18T14:27", 0, false, null);
130+
assertDateMathEquals("2014-11-18T14:27:32||/m", "2014-11-18T14:28:00.000", 0, true, null);
131+
assertDateMathEquals("2014-11-18T14:27||/m", "2014-11-18T14:27", 0, false, null);
132+
assertDateMathEquals("2014-11-18T14:27||/m", "2014-11-18T14:28:00.000", 0, true, null);
133+
134+
assertDateMathEquals("2014-11-18T14:27:32.123||/s", "2014-11-18T14:27:32", 0, false, null);
135+
assertDateMathEquals("2014-11-18T14:27:32.123||/s", "2014-11-18T14:27:33.000", 0, true, null);
136+
assertDateMathEquals("2014-11-18T14:27:32||/s", "2014-11-18T14:27:32", 0, false, null);
137+
assertDateMathEquals("2014-11-18T14:27:32||/s", "2014-11-18T14:27:33.000", 0, true, null);
138+
}
139+
64140
@Test
65141
public void actualDateTests() {
66142
DateMathParser parser = new DateMathParser(Joda.forPattern("dateOptionalTime"), TimeUnit.MILLISECONDS);
67143

68144
assertThat(parser.parse("1970-01-01", callable(0)), equalTo(0l));
69145
assertThat(parser.parse("1970-01-01||+1m", callable(0)), equalTo(TimeUnit.MINUTES.toMillis(1)));
70146
assertThat(parser.parse("1970-01-01||+1m+1s", callable(0)), equalTo(TimeUnit.MINUTES.toMillis(1) + TimeUnit.SECONDS.toMillis(1)));
71-
147+
72148
assertThat(parser.parse("2013-01-01||+1y", callable(0)), equalTo(parser.parse("2013-01-01", callable(0)) + TimeUnit.DAYS.toMillis(365)));
73149
assertThat(parser.parse("2013-03-03||/y", callable(0)), equalTo(parser.parse("2013-01-01", callable(0))));
74150
assertThat(parser.parseRoundCeil("2013-03-03||/y", callable(0)), equalTo(parser.parse("2014-01-01", callable(0))));

0 commit comments

Comments
 (0)