Remove TimeZoneRounding abstraction
Because the Rounding class now only deals with date based rounding of values we can remove the TimeZoneRounding abstraction to simplify the code.
This commit is contained in:
parent
5ab5cc69b8
commit
c14155e4a8
|
@ -22,6 +22,10 @@ import org.elasticsearch.ElasticsearchException;
|
||||||
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.io.stream.Streamable;
|
import org.elasticsearch.common.io.stream.Streamable;
|
||||||
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
import org.joda.time.DateTimeField;
|
||||||
|
import org.joda.time.DateTimeZone;
|
||||||
|
import org.joda.time.IllegalInstantException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -53,6 +57,279 @@ public abstract class Rounding implements Streamable {
|
||||||
@Override
|
@Override
|
||||||
public abstract int hashCode();
|
public abstract int hashCode();
|
||||||
|
|
||||||
|
public static Builder builder(DateTimeUnit unit) {
|
||||||
|
return new Builder(unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder(TimeValue interval) {
|
||||||
|
return new Builder(interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
private final DateTimeUnit unit;
|
||||||
|
private final long interval;
|
||||||
|
|
||||||
|
private DateTimeZone timeZone = DateTimeZone.UTC;
|
||||||
|
|
||||||
|
private long offset;
|
||||||
|
|
||||||
|
public Builder(DateTimeUnit unit) {
|
||||||
|
this.unit = unit;
|
||||||
|
this.interval = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder(TimeValue interval) {
|
||||||
|
this.unit = null;
|
||||||
|
if (interval.millis() < 1)
|
||||||
|
throw new IllegalArgumentException("Zero or negative time interval not supported");
|
||||||
|
this.interval = interval.millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder timeZone(DateTimeZone timeZone) {
|
||||||
|
if (timeZone == null) {
|
||||||
|
throw new IllegalArgumentException("Setting null as timezone is not supported");
|
||||||
|
}
|
||||||
|
this.timeZone = timeZone;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder offset(long offset) {
|
||||||
|
this.offset = offset;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rounding build() {
|
||||||
|
Rounding timeZoneRounding;
|
||||||
|
if (unit != null) {
|
||||||
|
timeZoneRounding = new TimeUnitRounding(unit, timeZone);
|
||||||
|
} else {
|
||||||
|
timeZoneRounding = new TimeIntervalRounding(interval, timeZone);
|
||||||
|
}
|
||||||
|
if (offset != 0) {
|
||||||
|
timeZoneRounding = new OffsetRounding(timeZoneRounding, offset);
|
||||||
|
}
|
||||||
|
return timeZoneRounding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TimeUnitRounding extends Rounding {
|
||||||
|
|
||||||
|
static final byte ID = 1;
|
||||||
|
|
||||||
|
private DateTimeUnit unit;
|
||||||
|
private DateTimeField field;
|
||||||
|
private DateTimeZone timeZone;
|
||||||
|
|
||||||
|
TimeUnitRounding() { // for serialization
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeUnitRounding(DateTimeUnit unit, DateTimeZone timeZone) {
|
||||||
|
this.unit = unit;
|
||||||
|
this.field = unit.field(timeZone);
|
||||||
|
this.timeZone = timeZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte id() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long round(long utcMillis) {
|
||||||
|
long rounded = field.roundFloor(utcMillis);
|
||||||
|
if (timeZone.isFixed() == false && timeZone.getOffset(utcMillis) != timeZone.getOffset(rounded)) {
|
||||||
|
// in this case, we crossed a time zone transition. In some edge
|
||||||
|
// cases this will
|
||||||
|
// result in a value that is not a rounded value itself. We need
|
||||||
|
// to round again
|
||||||
|
// to make sure. This will have no affect in cases where
|
||||||
|
// 'rounded' was already a proper
|
||||||
|
// rounded value
|
||||||
|
rounded = field.roundFloor(rounded);
|
||||||
|
}
|
||||||
|
assert rounded == field.roundFloor(rounded);
|
||||||
|
return rounded;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long nextRoundingValue(long utcMillis) {
|
||||||
|
long floor = round(utcMillis);
|
||||||
|
// add one unit and round to get to next rounded value
|
||||||
|
long next = round(field.add(floor, 1));
|
||||||
|
if (next == floor) {
|
||||||
|
// in rare case we need to add more than one unit
|
||||||
|
next = round(field.add(floor, 2));
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
unit = DateTimeUnit.resolve(in.readByte());
|
||||||
|
timeZone = DateTimeZone.forID(in.readString());
|
||||||
|
field = unit.field(timeZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
out.writeByte(unit.id());
|
||||||
|
out.writeString(timeZone.getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(unit, timeZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TimeUnitRounding other = (TimeUnitRounding) obj;
|
||||||
|
return Objects.equals(unit, other.unit) && Objects.equals(timeZone, other.timeZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[" + timeZone + "][" + unit + "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class TimeIntervalRounding extends Rounding {
|
||||||
|
|
||||||
|
static final byte ID = 2;
|
||||||
|
|
||||||
|
private long interval;
|
||||||
|
private DateTimeZone timeZone;
|
||||||
|
|
||||||
|
TimeIntervalRounding() { // for serialization
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeIntervalRounding(long interval, DateTimeZone timeZone) {
|
||||||
|
if (interval < 1)
|
||||||
|
throw new IllegalArgumentException("Zero or negative time interval not supported");
|
||||||
|
this.interval = interval;
|
||||||
|
this.timeZone = timeZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte id() {
|
||||||
|
return ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long round(long utcMillis) {
|
||||||
|
long timeLocal = timeZone.convertUTCToLocal(utcMillis);
|
||||||
|
long rounded = roundKey(timeLocal, interval) * interval;
|
||||||
|
long roundedUTC;
|
||||||
|
if (isInDSTGap(rounded) == false) {
|
||||||
|
roundedUTC = timeZone.convertLocalToUTC(rounded, true, utcMillis);
|
||||||
|
// check if we crossed DST transition, in this case we want the
|
||||||
|
// last rounded value before the transition
|
||||||
|
long transition = timeZone.previousTransition(utcMillis);
|
||||||
|
if (transition != utcMillis && transition > roundedUTC) {
|
||||||
|
roundedUTC = round(transition - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Edge case where the rounded local time is illegal and landed
|
||||||
|
* in a DST gap. In this case, we choose 1ms tick after the
|
||||||
|
* transition date. We don't want the transition date itself
|
||||||
|
* because those dates, when rounded themselves, fall into the
|
||||||
|
* previous interval. This would violate the invariant that the
|
||||||
|
* rounding operation should be idempotent.
|
||||||
|
*/
|
||||||
|
roundedUTC = timeZone.previousTransition(utcMillis) + 1;
|
||||||
|
}
|
||||||
|
return roundedUTC;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long roundKey(long value, long interval) {
|
||||||
|
if (value < 0) {
|
||||||
|
return (value - interval + 1) / interval;
|
||||||
|
} else {
|
||||||
|
return value / interval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the local instant is a valid instant in the given
|
||||||
|
* time zone. The logic for this is taken from
|
||||||
|
* {@link DateTimeZone#convertLocalToUTC(long, boolean)} for the
|
||||||
|
* `strict` mode case, but instead of throwing an
|
||||||
|
* {@link IllegalInstantException}, which is costly, we want to return a
|
||||||
|
* flag indicating that the value is illegal in that time zone.
|
||||||
|
*/
|
||||||
|
private boolean isInDSTGap(long instantLocal) {
|
||||||
|
if (timeZone.isFixed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// get the offset at instantLocal (first estimate)
|
||||||
|
int offsetLocal = timeZone.getOffset(instantLocal);
|
||||||
|
// adjust instantLocal using the estimate and recalc the offset
|
||||||
|
int offset = timeZone.getOffset(instantLocal - offsetLocal);
|
||||||
|
// if the offsets differ, we must be near a DST boundary
|
||||||
|
if (offsetLocal != offset) {
|
||||||
|
// determine if we are in the DST gap
|
||||||
|
long nextLocal = timeZone.nextTransition(instantLocal - offsetLocal);
|
||||||
|
if (nextLocal == (instantLocal - offsetLocal)) {
|
||||||
|
nextLocal = Long.MAX_VALUE;
|
||||||
|
}
|
||||||
|
long nextAdjusted = timeZone.nextTransition(instantLocal - offset);
|
||||||
|
if (nextAdjusted == (instantLocal - offset)) {
|
||||||
|
nextAdjusted = Long.MAX_VALUE;
|
||||||
|
}
|
||||||
|
if (nextLocal != nextAdjusted) {
|
||||||
|
// we are in the DST gap
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long nextRoundingValue(long time) {
|
||||||
|
long timeLocal = time;
|
||||||
|
timeLocal = timeZone.convertUTCToLocal(time);
|
||||||
|
long next = timeLocal + interval;
|
||||||
|
return timeZone.convertLocalToUTC(next, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
interval = in.readVLong();
|
||||||
|
timeZone = DateTimeZone.forID(in.readString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
out.writeVLong(interval);
|
||||||
|
out.writeString(timeZone.getID());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(interval, timeZone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
TimeIntervalRounding other = (TimeIntervalRounding) obj;
|
||||||
|
return Objects.equals(interval, other.interval) && Objects.equals(timeZone, other.timeZone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class OffsetRounding extends Rounding {
|
public static class OffsetRounding extends Rounding {
|
||||||
|
|
||||||
static final byte ID = 8;
|
static final byte ID = 8;
|
||||||
|
@ -126,8 +403,8 @@ public abstract class Rounding implements Streamable {
|
||||||
Rounding rounding = null;
|
Rounding rounding = null;
|
||||||
byte id = in.readByte();
|
byte id = in.readByte();
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case TimeZoneRounding.TimeUnitRounding.ID: rounding = new TimeZoneRounding.TimeUnitRounding(); break;
|
case TimeUnitRounding.ID: rounding = new TimeUnitRounding(); break;
|
||||||
case TimeZoneRounding.TimeIntervalRounding.ID: rounding = new TimeZoneRounding.TimeIntervalRounding(); break;
|
case TimeIntervalRounding.ID: rounding = new TimeIntervalRounding(); break;
|
||||||
case OffsetRounding.ID: rounding = new OffsetRounding(); break;
|
case OffsetRounding.ID: rounding = new OffsetRounding(); break;
|
||||||
default: throw new ElasticsearchException("unknown rounding id [" + id + "]");
|
default: throw new ElasticsearchException("unknown rounding id [" + id + "]");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,309 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.rounding;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
|
||||||
import org.joda.time.DateTimeField;
|
|
||||||
import org.joda.time.DateTimeZone;
|
|
||||||
import org.joda.time.IllegalInstantException;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A rounding strategy for dates. It is typically used to group together dates
|
|
||||||
* that are part of the same hour/day/month, taking into account time zones and
|
|
||||||
* daylight saving times.
|
|
||||||
*/
|
|
||||||
public abstract class TimeZoneRounding extends Rounding {
|
|
||||||
|
|
||||||
public static Builder builder(DateTimeUnit unit) {
|
|
||||||
return new Builder(unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Builder builder(TimeValue interval) {
|
|
||||||
return new Builder(interval);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Builder {
|
|
||||||
|
|
||||||
private final DateTimeUnit unit;
|
|
||||||
private final long interval;
|
|
||||||
|
|
||||||
private DateTimeZone timeZone = DateTimeZone.UTC;
|
|
||||||
|
|
||||||
private long offset;
|
|
||||||
|
|
||||||
public Builder(DateTimeUnit unit) {
|
|
||||||
this.unit = unit;
|
|
||||||
this.interval = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder(TimeValue interval) {
|
|
||||||
this.unit = null;
|
|
||||||
if (interval.millis() < 1)
|
|
||||||
throw new IllegalArgumentException("Zero or negative time interval not supported");
|
|
||||||
this.interval = interval.millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder timeZone(DateTimeZone timeZone) {
|
|
||||||
if (timeZone == null) {
|
|
||||||
throw new IllegalArgumentException("Setting null as timezone is not supported");
|
|
||||||
}
|
|
||||||
this.timeZone = timeZone;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder offset(long offset) {
|
|
||||||
this.offset = offset;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Rounding build() {
|
|
||||||
Rounding timeZoneRounding;
|
|
||||||
if (unit != null) {
|
|
||||||
timeZoneRounding = new TimeUnitRounding(unit, timeZone);
|
|
||||||
} else {
|
|
||||||
timeZoneRounding = new TimeIntervalRounding(interval, timeZone);
|
|
||||||
}
|
|
||||||
if (offset != 0) {
|
|
||||||
timeZoneRounding = new OffsetRounding(timeZoneRounding, offset);
|
|
||||||
}
|
|
||||||
return timeZoneRounding;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TimeUnitRounding extends TimeZoneRounding {
|
|
||||||
|
|
||||||
static final byte ID = 1;
|
|
||||||
|
|
||||||
private DateTimeUnit unit;
|
|
||||||
private DateTimeField field;
|
|
||||||
private DateTimeZone timeZone;
|
|
||||||
|
|
||||||
TimeUnitRounding() { // for serialization
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeUnitRounding(DateTimeUnit unit, DateTimeZone timeZone) {
|
|
||||||
this.unit = unit;
|
|
||||||
this.field = unit.field(timeZone);
|
|
||||||
this.timeZone = timeZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte id() {
|
|
||||||
return ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long round(long utcMillis) {
|
|
||||||
long rounded = field.roundFloor(utcMillis);
|
|
||||||
if (timeZone.isFixed() == false && timeZone.getOffset(utcMillis) != timeZone.getOffset(rounded)) {
|
|
||||||
// in this case, we crossed a time zone transition. In some edge cases this will
|
|
||||||
// result in a value that is not a rounded value itself. We need to round again
|
|
||||||
// to make sure. This will have no affect in cases where 'rounded' was already a proper
|
|
||||||
// rounded value
|
|
||||||
rounded = field.roundFloor(rounded);
|
|
||||||
}
|
|
||||||
assert rounded == field.roundFloor(rounded);
|
|
||||||
return rounded;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long nextRoundingValue(long utcMillis) {
|
|
||||||
long floor = round(utcMillis);
|
|
||||||
// add one unit and round to get to next rounded value
|
|
||||||
long next = round(field.add(floor, 1));
|
|
||||||
if (next == floor) {
|
|
||||||
// in rare case we need to add more than one unit
|
|
||||||
next = round(field.add(floor, 2));
|
|
||||||
}
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readFrom(StreamInput in) throws IOException {
|
|
||||||
unit = DateTimeUnit.resolve(in.readByte());
|
|
||||||
timeZone = DateTimeZone.forID(in.readString());
|
|
||||||
field = unit.field(timeZone);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeTo(StreamOutput out) throws IOException {
|
|
||||||
out.writeByte(unit.id());
|
|
||||||
out.writeString(timeZone.getID());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(unit, timeZone);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
TimeUnitRounding other = (TimeUnitRounding) obj;
|
|
||||||
return Objects.equals(unit, other.unit)
|
|
||||||
&& Objects.equals(timeZone, other.timeZone);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "[" + timeZone + "][" + unit +"]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class TimeIntervalRounding extends TimeZoneRounding {
|
|
||||||
|
|
||||||
static final byte ID = 2;
|
|
||||||
|
|
||||||
private long interval;
|
|
||||||
private DateTimeZone timeZone;
|
|
||||||
|
|
||||||
TimeIntervalRounding() { // for serialization
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeIntervalRounding(long interval, DateTimeZone timeZone) {
|
|
||||||
if (interval < 1)
|
|
||||||
throw new IllegalArgumentException("Zero or negative time interval not supported");
|
|
||||||
this.interval = interval;
|
|
||||||
this.timeZone = timeZone;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public byte id() {
|
|
||||||
return ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long round(long utcMillis) {
|
|
||||||
long timeLocal = timeZone.convertUTCToLocal(utcMillis);
|
|
||||||
long rounded = roundKey(timeLocal, interval) * interval;
|
|
||||||
long roundedUTC;
|
|
||||||
if (isInDSTGap(rounded) == false) {
|
|
||||||
roundedUTC = timeZone.convertLocalToUTC(rounded, true, utcMillis);
|
|
||||||
// check if we crossed DST transition, in this case we want the last rounded value before the transition
|
|
||||||
long transition = timeZone.previousTransition(utcMillis);
|
|
||||||
if (transition != utcMillis && transition > roundedUTC) {
|
|
||||||
roundedUTC = round(transition - 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* Edge case where the rounded local time is illegal and landed
|
|
||||||
* in a DST gap. In this case, we choose 1ms tick after the
|
|
||||||
* transition date. We don't want the transition date itself
|
|
||||||
* because those dates, when rounded themselves, fall into the
|
|
||||||
* previous interval. This would violate the invariant that the
|
|
||||||
* rounding operation should be idempotent.
|
|
||||||
*/
|
|
||||||
roundedUTC = timeZone.previousTransition(utcMillis) + 1;
|
|
||||||
}
|
|
||||||
return roundedUTC;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static long roundKey(long value, long interval) {
|
|
||||||
if (value < 0) {
|
|
||||||
return (value - interval + 1) / interval;
|
|
||||||
} else {
|
|
||||||
return value / interval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether the local instant is a valid instant in the given
|
|
||||||
* time zone. The logic for this is taken from
|
|
||||||
* {@link DateTimeZone#convertLocalToUTC(long, boolean)} for the
|
|
||||||
* `strict` mode case, but instead of throwing an
|
|
||||||
* {@link IllegalInstantException}, which is costly, we want to return a
|
|
||||||
* flag indicating that the value is illegal in that time zone.
|
|
||||||
*/
|
|
||||||
private boolean isInDSTGap(long instantLocal) {
|
|
||||||
if (timeZone.isFixed()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// get the offset at instantLocal (first estimate)
|
|
||||||
int offsetLocal = timeZone.getOffset(instantLocal);
|
|
||||||
// adjust instantLocal using the estimate and recalc the offset
|
|
||||||
int offset = timeZone.getOffset(instantLocal - offsetLocal);
|
|
||||||
// if the offsets differ, we must be near a DST boundary
|
|
||||||
if (offsetLocal != offset) {
|
|
||||||
// determine if we are in the DST gap
|
|
||||||
long nextLocal = timeZone.nextTransition(instantLocal - offsetLocal);
|
|
||||||
if (nextLocal == (instantLocal - offsetLocal)) {
|
|
||||||
nextLocal = Long.MAX_VALUE;
|
|
||||||
}
|
|
||||||
long nextAdjusted = timeZone.nextTransition(instantLocal - offset);
|
|
||||||
if (nextAdjusted == (instantLocal - offset)) {
|
|
||||||
nextAdjusted = Long.MAX_VALUE;
|
|
||||||
}
|
|
||||||
if (nextLocal != nextAdjusted) {
|
|
||||||
// we are in the DST gap
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long nextRoundingValue(long time) {
|
|
||||||
long timeLocal = time;
|
|
||||||
timeLocal = timeZone.convertUTCToLocal(time);
|
|
||||||
long next = timeLocal + interval;
|
|
||||||
return timeZone.convertLocalToUTC(next, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readFrom(StreamInput in) throws IOException {
|
|
||||||
interval = in.readVLong();
|
|
||||||
timeZone = DateTimeZone.forID(in.readString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeTo(StreamOutput out) throws IOException {
|
|
||||||
out.writeVLong(interval);
|
|
||||||
out.writeString(timeZone.getID());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(interval, timeZone);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (obj == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
TimeIntervalRounding other = (TimeIntervalRounding) obj;
|
|
||||||
return Objects.equals(interval, other.interval)
|
|
||||||
&& Objects.equals(timeZone, other.timeZone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -24,7 +24,6 @@ import org.apache.lucene.util.CollectionUtil;
|
||||||
import org.elasticsearch.common.inject.internal.Nullable;
|
import org.elasticsearch.common.inject.internal.Nullable;
|
||||||
import org.elasticsearch.common.lease.Releasables;
|
import org.elasticsearch.common.lease.Releasables;
|
||||||
import org.elasticsearch.common.rounding.Rounding;
|
import org.elasticsearch.common.rounding.Rounding;
|
||||||
import org.elasticsearch.common.rounding.TimeZoneRounding;
|
|
||||||
import org.elasticsearch.common.util.LongHash;
|
import org.elasticsearch.common.util.LongHash;
|
||||||
import org.elasticsearch.search.DocValueFormat;
|
import org.elasticsearch.search.DocValueFormat;
|
||||||
import org.elasticsearch.search.aggregations.Aggregator;
|
import org.elasticsearch.search.aggregations.Aggregator;
|
||||||
|
@ -45,8 +44,9 @@ import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An aggregator for date values. Every date is rounded down using a configured
|
* An aggregator for date values. Every date is rounded down using a configured
|
||||||
* {@link TimeZoneRounding}.
|
* {@link Rounding}.
|
||||||
* @see TimeZoneRounding
|
*
|
||||||
|
* @see Rounding
|
||||||
*/
|
*/
|
||||||
class DateHistogramAggregator extends BucketsAggregator {
|
class DateHistogramAggregator extends BucketsAggregator {
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ package org.elasticsearch.search.aggregations.bucket.histogram;
|
||||||
|
|
||||||
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.rounding.TimeZoneRounding;
|
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.search.aggregations.Aggregator;
|
import org.elasticsearch.search.aggregations.Aggregator;
|
||||||
import org.elasticsearch.search.aggregations.AggregatorFactories;
|
import org.elasticsearch.search.aggregations.AggregatorFactories;
|
||||||
|
@ -95,19 +94,19 @@ public final class DateHistogramAggregatorFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
private Rounding createRounding() {
|
private Rounding createRounding() {
|
||||||
TimeZoneRounding.Builder tzRoundingBuilder;
|
Rounding.Builder tzRoundingBuilder;
|
||||||
if (dateHistogramInterval != null) {
|
if (dateHistogramInterval != null) {
|
||||||
DateTimeUnit dateTimeUnit = DATE_FIELD_UNITS.get(dateHistogramInterval.toString());
|
DateTimeUnit dateTimeUnit = DATE_FIELD_UNITS.get(dateHistogramInterval.toString());
|
||||||
if (dateTimeUnit != null) {
|
if (dateTimeUnit != null) {
|
||||||
tzRoundingBuilder = TimeZoneRounding.builder(dateTimeUnit);
|
tzRoundingBuilder = Rounding.builder(dateTimeUnit);
|
||||||
} else {
|
} else {
|
||||||
// the interval is a time value?
|
// the interval is a time value?
|
||||||
tzRoundingBuilder = TimeZoneRounding.builder(
|
tzRoundingBuilder = Rounding.builder(
|
||||||
TimeValue.parseTimeValue(dateHistogramInterval.toString(), null, getClass().getSimpleName() + ".interval"));
|
TimeValue.parseTimeValue(dateHistogramInterval.toString(), null, getClass().getSimpleName() + ".interval"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// the interval is an integer time value in millis?
|
// the interval is an integer time value in millis?
|
||||||
tzRoundingBuilder = TimeZoneRounding.builder(TimeValue.timeValueMillis(interval));
|
tzRoundingBuilder = Rounding.builder(TimeValue.timeValueMillis(interval));
|
||||||
}
|
}
|
||||||
if (timeZone() != null) {
|
if (timeZone() != null) {
|
||||||
tzRoundingBuilder.timeZone(timeZone());
|
tzRoundingBuilder.timeZone(timeZone());
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class OffsetRoundingTests extends ESTestCase {
|
||||||
final long interval = 10;
|
final long interval = 10;
|
||||||
final long offset = 7;
|
final long offset = 7;
|
||||||
Rounding.OffsetRounding rounding = new Rounding.OffsetRounding(
|
Rounding.OffsetRounding rounding = new Rounding.OffsetRounding(
|
||||||
new TimeZoneRounding.TimeIntervalRounding(interval, DateTimeZone.UTC), offset);
|
new Rounding.TimeIntervalRounding(interval, DateTimeZone.UTC), offset);
|
||||||
assertEquals(-3, rounding.round(6));
|
assertEquals(-3, rounding.round(6));
|
||||||
assertEquals(7, rounding.nextRoundingValue(-3));
|
assertEquals(7, rounding.nextRoundingValue(-3));
|
||||||
assertEquals(7, rounding.round(7));
|
assertEquals(7, rounding.round(7));
|
||||||
|
@ -53,7 +53,7 @@ public class OffsetRoundingTests extends ESTestCase {
|
||||||
public void testOffsetRoundingRandom() {
|
public void testOffsetRoundingRandom() {
|
||||||
for (int i = 0; i < 1000; ++i) {
|
for (int i = 0; i < 1000; ++i) {
|
||||||
final long interval = randomIntBetween(1, 100);
|
final long interval = randomIntBetween(1, 100);
|
||||||
Rounding internalRounding = new TimeZoneRounding.TimeIntervalRounding(interval, DateTimeZone.UTC);
|
Rounding internalRounding = new Rounding.TimeIntervalRounding(interval, DateTimeZone.UTC);
|
||||||
final long offset = randomIntBetween(-100, 100);
|
final long offset = randomIntBetween(-100, 100);
|
||||||
Rounding.OffsetRounding rounding = new Rounding.OffsetRounding(internalRounding, offset);
|
Rounding.OffsetRounding rounding = new Rounding.OffsetRounding(internalRounding, offset);
|
||||||
long safetyMargin = Math.abs(interval) + Math.abs(offset); // to prevent range overflow
|
long safetyMargin = Math.abs(interval) + Math.abs(offset); // to prevent range overflow
|
||||||
|
|
|
@ -20,8 +20,8 @@
|
||||||
package org.elasticsearch.common.rounding;
|
package org.elasticsearch.common.rounding;
|
||||||
|
|
||||||
import org.elasticsearch.common.collect.Tuple;
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
import org.elasticsearch.common.rounding.TimeZoneRounding.TimeIntervalRounding;
|
import org.elasticsearch.common.rounding.Rounding.TimeIntervalRounding;
|
||||||
import org.elasticsearch.common.rounding.TimeZoneRounding.TimeUnitRounding;
|
import org.elasticsearch.common.rounding.Rounding.TimeUnitRounding;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.hamcrest.Description;
|
import org.hamcrest.Description;
|
||||||
|
@ -47,29 +47,29 @@ import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
||||||
public class TimeZoneRoundingTests extends ESTestCase {
|
public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
|
|
||||||
public void testUTCTimeUnitRounding() {
|
public void testUTCTimeUnitRounding() {
|
||||||
Rounding tzRounding = TimeZoneRounding.builder(DateTimeUnit.MONTH_OF_YEAR).build();
|
Rounding tzRounding = Rounding.builder(DateTimeUnit.MONTH_OF_YEAR).build();
|
||||||
DateTimeZone tz = DateTimeZone.UTC;
|
DateTimeZone tz = DateTimeZone.UTC;
|
||||||
assertThat(tzRounding.round(time("2009-02-03T01:01:01")), isDate(time("2009-02-01T00:00:00.000Z"), tz));
|
assertThat(tzRounding.round(time("2009-02-03T01:01:01")), isDate(time("2009-02-01T00:00:00.000Z"), tz));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2009-02-01T00:00:00.000Z")), isDate(time("2009-03-01T00:00:00.000Z"), tz));
|
assertThat(tzRounding.nextRoundingValue(time("2009-02-01T00:00:00.000Z")), isDate(time("2009-03-01T00:00:00.000Z"), tz));
|
||||||
|
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.WEEK_OF_WEEKYEAR).build();
|
tzRounding = Rounding.builder(DateTimeUnit.WEEK_OF_WEEKYEAR).build();
|
||||||
assertThat(tzRounding.round(time("2012-01-10T01:01:01")), isDate(time("2012-01-09T00:00:00.000Z"), tz));
|
assertThat(tzRounding.round(time("2012-01-10T01:01:01")), isDate(time("2012-01-09T00:00:00.000Z"), tz));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2012-01-09T00:00:00.000Z")), isDate(time("2012-01-16T00:00:00.000Z"), tz));
|
assertThat(tzRounding.nextRoundingValue(time("2012-01-09T00:00:00.000Z")), isDate(time("2012-01-16T00:00:00.000Z"), tz));
|
||||||
|
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.WEEK_OF_WEEKYEAR).offset(-TimeValue.timeValueHours(24).millis()).build();
|
tzRounding = Rounding.builder(DateTimeUnit.WEEK_OF_WEEKYEAR).offset(-TimeValue.timeValueHours(24).millis()).build();
|
||||||
assertThat(tzRounding.round(time("2012-01-10T01:01:01")), isDate(time("2012-01-08T00:00:00.000Z"), tz));
|
assertThat(tzRounding.round(time("2012-01-10T01:01:01")), isDate(time("2012-01-08T00:00:00.000Z"), tz));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2012-01-08T00:00:00.000Z")), isDate(time("2012-01-15T00:00:00.000Z"), tz));
|
assertThat(tzRounding.nextRoundingValue(time("2012-01-08T00:00:00.000Z")), isDate(time("2012-01-15T00:00:00.000Z"), tz));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testUTCIntervalRounding() {
|
public void testUTCIntervalRounding() {
|
||||||
Rounding tzRounding = TimeZoneRounding.builder(TimeValue.timeValueHours(12)).build();
|
Rounding tzRounding = Rounding.builder(TimeValue.timeValueHours(12)).build();
|
||||||
DateTimeZone tz = DateTimeZone.UTC;
|
DateTimeZone tz = DateTimeZone.UTC;
|
||||||
assertThat(tzRounding.round(time("2009-02-03T01:01:01")), isDate(time("2009-02-03T00:00:00.000Z"), tz));
|
assertThat(tzRounding.round(time("2009-02-03T01:01:01")), isDate(time("2009-02-03T00:00:00.000Z"), tz));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2009-02-03T00:00:00.000Z")), isDate(time("2009-02-03T12:00:00.000Z"), tz));
|
assertThat(tzRounding.nextRoundingValue(time("2009-02-03T00:00:00.000Z")), isDate(time("2009-02-03T12:00:00.000Z"), tz));
|
||||||
assertThat(tzRounding.round(time("2009-02-03T13:01:01")), isDate(time("2009-02-03T12:00:00.000Z"), tz));
|
assertThat(tzRounding.round(time("2009-02-03T13:01:01")), isDate(time("2009-02-03T12:00:00.000Z"), tz));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2009-02-03T12:00:00.000Z")), isDate(time("2009-02-04T00:00:00.000Z"), tz));
|
assertThat(tzRounding.nextRoundingValue(time("2009-02-03T12:00:00.000Z")), isDate(time("2009-02-04T00:00:00.000Z"), tz));
|
||||||
|
|
||||||
tzRounding = TimeZoneRounding.builder(TimeValue.timeValueHours(48)).build();
|
tzRounding = Rounding.builder(TimeValue.timeValueHours(48)).build();
|
||||||
assertThat(tzRounding.round(time("2009-02-03T01:01:01")), isDate(time("2009-02-03T00:00:00.000Z"), tz));
|
assertThat(tzRounding.round(time("2009-02-03T01:01:01")), isDate(time("2009-02-03T00:00:00.000Z"), tz));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2009-02-03T00:00:00.000Z")), isDate(time("2009-02-05T00:00:00.000Z"), tz));
|
assertThat(tzRounding.nextRoundingValue(time("2009-02-03T00:00:00.000Z")), isDate(time("2009-02-05T00:00:00.000Z"), tz));
|
||||||
assertThat(tzRounding.round(time("2009-02-05T13:01:01")), isDate(time("2009-02-05T00:00:00.000Z"), tz));
|
assertThat(tzRounding.round(time("2009-02-05T13:01:01")), isDate(time("2009-02-05T00:00:00.000Z"), tz));
|
||||||
|
@ -77,11 +77,11 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test TimeIntervalTimeZoneRounding, (interval < 12h) with time zone shift
|
* test TimeIntervalRounding, (interval < 12h) with time zone shift
|
||||||
*/
|
*/
|
||||||
public void testTimeIntervalTimeZoneRounding() {
|
public void testTimeIntervalRounding() {
|
||||||
DateTimeZone tz = DateTimeZone.forOffsetHours(-1);
|
DateTimeZone tz = DateTimeZone.forOffsetHours(-1);
|
||||||
Rounding tzRounding = TimeZoneRounding.builder(TimeValue.timeValueHours(6)).timeZone(tz).build();
|
Rounding tzRounding = Rounding.builder(TimeValue.timeValueHours(6)).timeZone(tz).build();
|
||||||
assertThat(tzRounding.round(time("2009-02-03T00:01:01")), isDate(time("2009-02-02T19:00:00.000Z"), tz));
|
assertThat(tzRounding.round(time("2009-02-03T00:01:01")), isDate(time("2009-02-02T19:00:00.000Z"), tz));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2009-02-02T19:00:00.000Z")), isDate(time("2009-02-03T01:00:00.000Z"), tz));
|
assertThat(tzRounding.nextRoundingValue(time("2009-02-02T19:00:00.000Z")), isDate(time("2009-02-03T01:00:00.000Z"), tz));
|
||||||
|
|
||||||
|
@ -90,11 +90,11 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* test DayIntervalTimeZoneRounding, (interval >= 12h) with time zone shift
|
* test DayIntervalRounding, (interval >= 12h) with time zone shift
|
||||||
*/
|
*/
|
||||||
public void testDayIntervalTimeZoneRounding() {
|
public void testDayIntervalRounding() {
|
||||||
DateTimeZone tz = DateTimeZone.forOffsetHours(-8);
|
DateTimeZone tz = DateTimeZone.forOffsetHours(-8);
|
||||||
Rounding tzRounding = TimeZoneRounding.builder(TimeValue.timeValueHours(12)).timeZone(tz).build();
|
Rounding tzRounding = Rounding.builder(TimeValue.timeValueHours(12)).timeZone(tz).build();
|
||||||
assertThat(tzRounding.round(time("2009-02-03T00:01:01")), isDate(time("2009-02-02T20:00:00.000Z"), tz));
|
assertThat(tzRounding.round(time("2009-02-03T00:01:01")), isDate(time("2009-02-02T20:00:00.000Z"), tz));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2009-02-02T20:00:00.000Z")), isDate(time("2009-02-03T08:00:00.000Z"), tz));
|
assertThat(tzRounding.nextRoundingValue(time("2009-02-02T20:00:00.000Z")), isDate(time("2009-02-03T08:00:00.000Z"), tz));
|
||||||
|
|
||||||
|
@ -102,37 +102,37 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2009-02-03T08:00:00.000Z")), isDate(time("2009-02-03T20:00:00.000Z"), tz));
|
assertThat(tzRounding.nextRoundingValue(time("2009-02-03T08:00:00.000Z")), isDate(time("2009-02-03T20:00:00.000Z"), tz));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testDayTimeZoneRounding() {
|
public void testDayRounding() {
|
||||||
int timezoneOffset = -2;
|
int timezoneOffset = -2;
|
||||||
Rounding tzRounding = TimeZoneRounding.builder(DateTimeUnit.DAY_OF_MONTH).timeZone(DateTimeZone.forOffsetHours(timezoneOffset))
|
Rounding tzRounding = Rounding.builder(DateTimeUnit.DAY_OF_MONTH).timeZone(DateTimeZone.forOffsetHours(timezoneOffset))
|
||||||
.build();
|
.build();
|
||||||
assertThat(tzRounding.round(0), equalTo(0L - TimeValue.timeValueHours(24 + timezoneOffset).millis()));
|
assertThat(tzRounding.round(0), equalTo(0L - TimeValue.timeValueHours(24 + timezoneOffset).millis()));
|
||||||
assertThat(tzRounding.nextRoundingValue(0L - TimeValue.timeValueHours(24 + timezoneOffset).millis()), equalTo(0L - TimeValue
|
assertThat(tzRounding.nextRoundingValue(0L - TimeValue.timeValueHours(24 + timezoneOffset).millis()), equalTo(0L - TimeValue
|
||||||
.timeValueHours(timezoneOffset).millis()));
|
.timeValueHours(timezoneOffset).millis()));
|
||||||
|
|
||||||
DateTimeZone tz = DateTimeZone.forID("-08:00");
|
DateTimeZone tz = DateTimeZone.forID("-08:00");
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.DAY_OF_MONTH).timeZone(tz).build();
|
tzRounding = Rounding.builder(DateTimeUnit.DAY_OF_MONTH).timeZone(tz).build();
|
||||||
assertThat(tzRounding.round(time("2012-04-01T04:15:30Z")), isDate(time("2012-03-31T08:00:00Z"), tz));
|
assertThat(tzRounding.round(time("2012-04-01T04:15:30Z")), isDate(time("2012-03-31T08:00:00Z"), tz));
|
||||||
|
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.MONTH_OF_YEAR).timeZone(tz).build();
|
tzRounding = Rounding.builder(DateTimeUnit.MONTH_OF_YEAR).timeZone(tz).build();
|
||||||
assertThat(tzRounding.round(time("2012-04-01T04:15:30Z")), equalTo(time("2012-03-01T08:00:00Z")));
|
assertThat(tzRounding.round(time("2012-04-01T04:15:30Z")), equalTo(time("2012-03-01T08:00:00Z")));
|
||||||
|
|
||||||
// date in Feb-3rd, but still in Feb-2nd in -02:00 timezone
|
// date in Feb-3rd, but still in Feb-2nd in -02:00 timezone
|
||||||
tz = DateTimeZone.forID("-02:00");
|
tz = DateTimeZone.forID("-02:00");
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.DAY_OF_MONTH).timeZone(tz).build();
|
tzRounding = Rounding.builder(DateTimeUnit.DAY_OF_MONTH).timeZone(tz).build();
|
||||||
assertThat(tzRounding.round(time("2009-02-03T01:01:01")), isDate(time("2009-02-02T02:00:00"), tz));
|
assertThat(tzRounding.round(time("2009-02-03T01:01:01")), isDate(time("2009-02-02T02:00:00"), tz));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2009-02-02T02:00:00")), isDate(time("2009-02-03T02:00:00"), tz));
|
assertThat(tzRounding.nextRoundingValue(time("2009-02-02T02:00:00")), isDate(time("2009-02-03T02:00:00"), tz));
|
||||||
|
|
||||||
// date in Feb-3rd, also in -02:00 timezone
|
// date in Feb-3rd, also in -02:00 timezone
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.DAY_OF_MONTH).timeZone(tz).build();
|
tzRounding = Rounding.builder(DateTimeUnit.DAY_OF_MONTH).timeZone(tz).build();
|
||||||
assertThat(tzRounding.round(time("2009-02-03T02:01:01")), isDate(time("2009-02-03T02:00:00"), tz));
|
assertThat(tzRounding.round(time("2009-02-03T02:01:01")), isDate(time("2009-02-03T02:00:00"), tz));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2009-02-03T02:00:00")), isDate(time("2009-02-04T02:00:00"), tz));
|
assertThat(tzRounding.nextRoundingValue(time("2009-02-03T02:00:00")), isDate(time("2009-02-04T02:00:00"), tz));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testTimeTimeZoneRounding() {
|
public void testTimeRounding() {
|
||||||
// hour unit
|
// hour unit
|
||||||
DateTimeZone tz = DateTimeZone.forOffsetHours(-2);
|
DateTimeZone tz = DateTimeZone.forOffsetHours(-2);
|
||||||
Rounding tzRounding = TimeZoneRounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(tz).build();
|
Rounding tzRounding = Rounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(tz).build();
|
||||||
assertThat(tzRounding.round(0), equalTo(0L));
|
assertThat(tzRounding.round(0), equalTo(0L));
|
||||||
assertThat(tzRounding.nextRoundingValue(0L), equalTo(TimeValue.timeValueHours(1L).getMillis()));
|
assertThat(tzRounding.nextRoundingValue(0L), equalTo(TimeValue.timeValueHours(1L).getMillis()));
|
||||||
|
|
||||||
|
@ -144,23 +144,23 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
Rounding tzRounding;
|
Rounding tzRounding;
|
||||||
// testing savings to non savings switch
|
// testing savings to non savings switch
|
||||||
DateTimeZone cet = DateTimeZone.forID("CET");
|
DateTimeZone cet = DateTimeZone.forID("CET");
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(cet).build();
|
tzRounding = Rounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(cet).build();
|
||||||
assertThat(tzRounding.round(time("2014-10-26T01:01:01", cet)), isDate(time("2014-10-26T01:00:00+02:00"), cet));
|
assertThat(tzRounding.round(time("2014-10-26T01:01:01", cet)), isDate(time("2014-10-26T01:00:00+02:00"), cet));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2014-10-26T01:00:00", cet)),isDate(time("2014-10-26T02:00:00+02:00"), cet));
|
assertThat(tzRounding.nextRoundingValue(time("2014-10-26T01:00:00", cet)),isDate(time("2014-10-26T02:00:00+02:00"), cet));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2014-10-26T02:00:00", cet)), isDate(time("2014-10-26T02:00:00+01:00"), cet));
|
assertThat(tzRounding.nextRoundingValue(time("2014-10-26T02:00:00", cet)), isDate(time("2014-10-26T02:00:00+01:00"), cet));
|
||||||
|
|
||||||
// testing non savings to savings switch
|
// testing non savings to savings switch
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(cet).build();
|
tzRounding = Rounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(cet).build();
|
||||||
assertThat(tzRounding.round(time("2014-03-30T01:01:01", cet)), isDate(time("2014-03-30T01:00:00+01:00"), cet));
|
assertThat(tzRounding.round(time("2014-03-30T01:01:01", cet)), isDate(time("2014-03-30T01:00:00+01:00"), cet));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2014-03-30T01:00:00", cet)), isDate(time("2014-03-30T03:00:00", cet), cet));
|
assertThat(tzRounding.nextRoundingValue(time("2014-03-30T01:00:00", cet)), isDate(time("2014-03-30T03:00:00", cet), cet));
|
||||||
assertThat(tzRounding.nextRoundingValue(time("2014-03-30T03:00:00", cet)), isDate(time("2014-03-30T04:00:00", cet), cet));
|
assertThat(tzRounding.nextRoundingValue(time("2014-03-30T03:00:00", cet)), isDate(time("2014-03-30T04:00:00", cet), cet));
|
||||||
|
|
||||||
// testing non savings to savings switch (America/Chicago)
|
// testing non savings to savings switch (America/Chicago)
|
||||||
DateTimeZone chg = DateTimeZone.forID("America/Chicago");
|
DateTimeZone chg = DateTimeZone.forID("America/Chicago");
|
||||||
Rounding tzRounding_utc = TimeZoneRounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(DateTimeZone.UTC).build();
|
Rounding tzRounding_utc = Rounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(DateTimeZone.UTC).build();
|
||||||
assertThat(tzRounding.round(time("2014-03-09T03:01:01", chg)), isDate(time("2014-03-09T03:00:00", chg), chg));
|
assertThat(tzRounding.round(time("2014-03-09T03:01:01", chg)), isDate(time("2014-03-09T03:00:00", chg), chg));
|
||||||
|
|
||||||
Rounding tzRounding_chg = TimeZoneRounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(chg).build();
|
Rounding tzRounding_chg = Rounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(chg).build();
|
||||||
assertThat(tzRounding_chg.round(time("2014-03-09T03:01:01", chg)), isDate(time("2014-03-09T03:00:00", chg), chg));
|
assertThat(tzRounding_chg.round(time("2014-03-09T03:01:01", chg)), isDate(time("2014-03-09T03:00:00", chg), chg));
|
||||||
|
|
||||||
// testing savings to non savings switch 2013 (America/Chicago)
|
// testing savings to non savings switch 2013 (America/Chicago)
|
||||||
|
@ -173,18 +173,21 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Randomized test on TimeUnitRounding.
|
* Randomized test on TimeUnitRounding. Test uses random
|
||||||
* Test uses random {@link DateTimeUnit} and {@link DateTimeZone} and often (50% of the time) chooses
|
* {@link DateTimeUnit} and {@link DateTimeZone} and often (50% of the time)
|
||||||
* test dates that are exactly on or close to offset changes (e.g. DST) in the chosen time zone.
|
* chooses test dates that are exactly on or close to offset changes (e.g.
|
||||||
|
* DST) in the chosen time zone.
|
||||||
*
|
*
|
||||||
* It rounds the test date down and up and performs various checks on the rounding unit interval that is
|
* It rounds the test date down and up and performs various checks on the
|
||||||
* defined by this. Assumptions tested are described in {@link #assertInterval(long, long, long, TimeZoneRounding, DateTimeZone)}
|
* rounding unit interval that is defined by this. Assumptions tested are
|
||||||
|
* described in
|
||||||
|
* {@link #assertInterval(long, long, long, Rounding, DateTimeZone)}
|
||||||
*/
|
*/
|
||||||
public void testTimeZoneRoundingRandom() {
|
public void testRoundingRandom() {
|
||||||
for (int i = 0; i < 1000; ++i) {
|
for (int i = 0; i < 1000; ++i) {
|
||||||
DateTimeUnit timeUnit = randomTimeUnit();
|
DateTimeUnit timeUnit = randomTimeUnit();
|
||||||
DateTimeZone tz = randomDateTimeZone();
|
DateTimeZone tz = randomDateTimeZone();
|
||||||
TimeZoneRounding rounding = new TimeZoneRounding.TimeUnitRounding(timeUnit, tz);
|
Rounding rounding = new Rounding.TimeUnitRounding(timeUnit, tz);
|
||||||
long date = Math.abs(randomLong() % (2 * (long) 10e11)); // 1970-01-01T00:00:00Z - 2033-05-18T05:33:20.000+02:00
|
long date = Math.abs(randomLong() % (2 * (long) 10e11)); // 1970-01-01T00:00:00Z - 2033-05-18T05:33:20.000+02:00
|
||||||
long unitMillis = timeUnit.field(tz).getDurationField().getUnitMillis();
|
long unitMillis = timeUnit.field(tz).getDurationField().getUnitMillis();
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
|
@ -226,7 +229,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
public void testTimeIntervalCET_DST_End() {
|
public void testTimeIntervalCET_DST_End() {
|
||||||
long interval = TimeUnit.MINUTES.toMillis(20);
|
long interval = TimeUnit.MINUTES.toMillis(20);
|
||||||
DateTimeZone tz = DateTimeZone.forID("CET");
|
DateTimeZone tz = DateTimeZone.forID("CET");
|
||||||
TimeZoneRounding rounding = new TimeIntervalRounding(interval, tz);
|
Rounding rounding = new TimeIntervalRounding(interval, tz);
|
||||||
|
|
||||||
assertThat(rounding.round(time("2015-10-25T01:55:00+02:00")), isDate(time("2015-10-25T01:40:00+02:00"), tz));
|
assertThat(rounding.round(time("2015-10-25T01:55:00+02:00")), isDate(time("2015-10-25T01:40:00+02:00"), tz));
|
||||||
assertThat(rounding.round(time("2015-10-25T02:15:00+02:00")), isDate(time("2015-10-25T02:00:00+02:00"), tz));
|
assertThat(rounding.round(time("2015-10-25T02:15:00+02:00")), isDate(time("2015-10-25T02:00:00+02:00"), tz));
|
||||||
|
@ -246,7 +249,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
public void testTimeIntervalCET_DST_Start() {
|
public void testTimeIntervalCET_DST_Start() {
|
||||||
long interval = TimeUnit.MINUTES.toMillis(20);
|
long interval = TimeUnit.MINUTES.toMillis(20);
|
||||||
DateTimeZone tz = DateTimeZone.forID("CET");
|
DateTimeZone tz = DateTimeZone.forID("CET");
|
||||||
TimeZoneRounding rounding = new TimeIntervalRounding(interval, tz);
|
Rounding rounding = new TimeIntervalRounding(interval, tz);
|
||||||
// test DST start
|
// test DST start
|
||||||
assertThat(rounding.round(time("2016-03-27T01:55:00+01:00")), isDate(time("2016-03-27T01:40:00+01:00"), tz));
|
assertThat(rounding.round(time("2016-03-27T01:55:00+01:00")), isDate(time("2016-03-27T01:40:00+01:00"), tz));
|
||||||
assertThat(rounding.round(time("2016-03-27T02:00:00+01:00")), isDate(time("2016-03-27T03:00:00+02:00"), tz));
|
assertThat(rounding.round(time("2016-03-27T02:00:00+01:00")), isDate(time("2016-03-27T03:00:00+02:00"), tz));
|
||||||
|
@ -263,7 +266,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
public void testTimeInterval_Kathmandu_DST_Start() {
|
public void testTimeInterval_Kathmandu_DST_Start() {
|
||||||
long interval = TimeUnit.MINUTES.toMillis(20);
|
long interval = TimeUnit.MINUTES.toMillis(20);
|
||||||
DateTimeZone tz = DateTimeZone.forID("Asia/Kathmandu");
|
DateTimeZone tz = DateTimeZone.forID("Asia/Kathmandu");
|
||||||
TimeZoneRounding rounding = new TimeIntervalRounding(interval, tz);
|
Rounding rounding = new TimeIntervalRounding(interval, tz);
|
||||||
assertThat(rounding.round(time("1985-12-31T23:55:00+05:30")), isDate(time("1985-12-31T23:40:00+05:30"), tz));
|
assertThat(rounding.round(time("1985-12-31T23:55:00+05:30")), isDate(time("1985-12-31T23:40:00+05:30"), tz));
|
||||||
assertThat(rounding.round(time("1986-01-01T00:16:00+05:45")), isDate(time("1986-01-01T00:15:00+05:45"), tz));
|
assertThat(rounding.round(time("1986-01-01T00:16:00+05:45")), isDate(time("1986-01-01T00:15:00+05:45"), tz));
|
||||||
assertThat(time("1986-01-01T00:15:00+05:45") - time("1985-12-31T23:40:00+05:30"), equalTo(TimeUnit.MINUTES.toMillis(20)));
|
assertThat(time("1986-01-01T00:15:00+05:45") - time("1985-12-31T23:40:00+05:30"), equalTo(TimeUnit.MINUTES.toMillis(20)));
|
||||||
|
@ -281,7 +284,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
public void testIntervalRounding_NotDivisibleInteval() {
|
public void testIntervalRounding_NotDivisibleInteval() {
|
||||||
DateTimeZone tz = DateTimeZone.forID("CET");
|
DateTimeZone tz = DateTimeZone.forID("CET");
|
||||||
long interval = TimeUnit.MINUTES.toMillis(14);
|
long interval = TimeUnit.MINUTES.toMillis(14);
|
||||||
TimeZoneRounding rounding = new TimeZoneRounding.TimeIntervalRounding(interval, tz);
|
Rounding rounding = new Rounding.TimeIntervalRounding(interval, tz);
|
||||||
|
|
||||||
assertThat(rounding.round(time("2016-03-27T01:41:00+01:00")), isDate(time("2016-03-27T01:30:00+01:00"), tz));
|
assertThat(rounding.round(time("2016-03-27T01:41:00+01:00")), isDate(time("2016-03-27T01:30:00+01:00"), tz));
|
||||||
assertThat(rounding.round(time("2016-03-27T01:51:00+01:00")), isDate(time("2016-03-27T01:44:00+01:00"), tz));
|
assertThat(rounding.round(time("2016-03-27T01:51:00+01:00")), isDate(time("2016-03-27T01:44:00+01:00"), tz));
|
||||||
|
@ -298,7 +301,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
public void testIntervalRounding_HalfDay_DST() {
|
public void testIntervalRounding_HalfDay_DST() {
|
||||||
DateTimeZone tz = DateTimeZone.forID("CET");
|
DateTimeZone tz = DateTimeZone.forID("CET");
|
||||||
long interval = TimeUnit.HOURS.toMillis(12);
|
long interval = TimeUnit.HOURS.toMillis(12);
|
||||||
TimeZoneRounding rounding = new TimeZoneRounding.TimeIntervalRounding(interval, tz);
|
Rounding rounding = new Rounding.TimeIntervalRounding(interval, tz);
|
||||||
|
|
||||||
assertThat(rounding.round(time("2016-03-26T01:00:00+01:00")), isDate(time("2016-03-26T00:00:00+01:00"), tz));
|
assertThat(rounding.round(time("2016-03-26T01:00:00+01:00")), isDate(time("2016-03-26T00:00:00+01:00"), tz));
|
||||||
assertThat(rounding.round(time("2016-03-26T13:00:00+01:00")), isDate(time("2016-03-26T12:00:00+01:00"), tz));
|
assertThat(rounding.round(time("2016-03-26T13:00:00+01:00")), isDate(time("2016-03-26T12:00:00+01:00"), tz));
|
||||||
|
@ -316,7 +319,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
TimeUnit unit = randomFrom(new TimeUnit[] {TimeUnit.MINUTES, TimeUnit.HOURS, TimeUnit.DAYS});
|
TimeUnit unit = randomFrom(new TimeUnit[] {TimeUnit.MINUTES, TimeUnit.HOURS, TimeUnit.DAYS});
|
||||||
long interval = unit.toMillis(randomIntBetween(1, 365));
|
long interval = unit.toMillis(randomIntBetween(1, 365));
|
||||||
DateTimeZone tz = randomDateTimeZone();
|
DateTimeZone tz = randomDateTimeZone();
|
||||||
TimeZoneRounding rounding = new TimeZoneRounding.TimeIntervalRounding(interval, tz);
|
Rounding rounding = new Rounding.TimeIntervalRounding(interval, tz);
|
||||||
long mainDate = Math.abs(randomLong() % (2 * (long) 10e11)); // 1970-01-01T00:00:00Z - 2033-05-18T05:33:20.000+02:00
|
long mainDate = Math.abs(randomLong() % (2 * (long) 10e11)); // 1970-01-01T00:00:00Z - 2033-05-18T05:33:20.000+02:00
|
||||||
if (randomBoolean()) {
|
if (randomBoolean()) {
|
||||||
mainDate = nastyDate(mainDate, tz, interval);
|
mainDate = nastyDate(mainDate, tz, interval);
|
||||||
|
@ -356,8 +359,8 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
public void testIntervalRoundingMonotonic_CET() {
|
public void testIntervalRoundingMonotonic_CET() {
|
||||||
long interval = TimeUnit.MINUTES.toMillis(45);
|
long interval = TimeUnit.MINUTES.toMillis(45);
|
||||||
DateTimeZone tz = DateTimeZone.forID("CET");
|
DateTimeZone tz = DateTimeZone.forID("CET");
|
||||||
TimeZoneRounding rounding = new TimeZoneRounding.TimeIntervalRounding(interval, tz);
|
Rounding rounding = new Rounding.TimeIntervalRounding(interval, tz);
|
||||||
List<Tuple<String, String>> expectedDates = new ArrayList<Tuple<String, String>>();
|
List<Tuple<String, String>> expectedDates = new ArrayList<>();
|
||||||
// first date is the date to be rounded, second the expected result
|
// first date is the date to be rounded, second the expected result
|
||||||
expectedDates.add(new Tuple<>("2011-10-30T01:40:00.000+02:00", "2011-10-30T01:30:00.000+02:00"));
|
expectedDates.add(new Tuple<>("2011-10-30T01:40:00.000+02:00", "2011-10-30T01:30:00.000+02:00"));
|
||||||
expectedDates.add(new Tuple<>("2011-10-30T02:02:30.000+02:00", "2011-10-30T01:30:00.000+02:00"));
|
expectedDates.add(new Tuple<>("2011-10-30T02:02:30.000+02:00", "2011-10-30T01:30:00.000+02:00"));
|
||||||
|
@ -387,7 +390,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
public void testAmbiguousHoursAfterDSTSwitch() {
|
public void testAmbiguousHoursAfterDSTSwitch() {
|
||||||
Rounding tzRounding;
|
Rounding tzRounding;
|
||||||
final DateTimeZone tz = DateTimeZone.forID("Asia/Jerusalem");
|
final DateTimeZone tz = DateTimeZone.forID("Asia/Jerusalem");
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(tz).build();
|
tzRounding = Rounding.builder(DateTimeUnit.HOUR_OF_DAY).timeZone(tz).build();
|
||||||
assertThat(tzRounding.round(time("2014-10-26T00:30:00+03:00")), isDate(time("2014-10-26T00:00:00+03:00"), tz));
|
assertThat(tzRounding.round(time("2014-10-26T00:30:00+03:00")), isDate(time("2014-10-26T00:00:00+03:00"), tz));
|
||||||
assertThat(tzRounding.round(time("2014-10-26T01:30:00+03:00")), isDate(time("2014-10-26T01:00:00+03:00"), tz));
|
assertThat(tzRounding.round(time("2014-10-26T01:30:00+03:00")), isDate(time("2014-10-26T01:00:00+03:00"), tz));
|
||||||
// the utc date for "2014-10-25T03:00:00+03:00" and "2014-10-25T03:00:00+02:00" is the same, local time turns back 1h here
|
// the utc date for "2014-10-25T03:00:00+03:00" and "2014-10-25T03:00:00+02:00" is the same, local time turns back 1h here
|
||||||
|
@ -396,7 +399,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
assertThat(tzRounding.round(time("2014-10-26T02:30:00+02:00")), isDate(time("2014-10-26T02:00:00+02:00"), tz));
|
assertThat(tzRounding.round(time("2014-10-26T02:30:00+02:00")), isDate(time("2014-10-26T02:00:00+02:00"), tz));
|
||||||
|
|
||||||
// Day interval
|
// Day interval
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.DAY_OF_MONTH).timeZone(tz).build();
|
tzRounding = Rounding.builder(DateTimeUnit.DAY_OF_MONTH).timeZone(tz).build();
|
||||||
assertThat(tzRounding.round(time("2014-11-11T17:00:00", tz)), isDate(time("2014-11-11T00:00:00", tz), tz));
|
assertThat(tzRounding.round(time("2014-11-11T17:00:00", tz)), isDate(time("2014-11-11T00:00:00", tz), tz));
|
||||||
// DST on
|
// DST on
|
||||||
assertThat(tzRounding.round(time("2014-08-11T17:00:00", tz)), isDate(time("2014-08-11T00:00:00", tz), tz));
|
assertThat(tzRounding.round(time("2014-08-11T17:00:00", tz)), isDate(time("2014-08-11T00:00:00", tz), tz));
|
||||||
|
@ -406,17 +409,17 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
assertThat(tzRounding.round(time("2015-03-27T17:00:00", tz)), isDate(time("2015-03-27T00:00:00", tz), tz));
|
assertThat(tzRounding.round(time("2015-03-27T17:00:00", tz)), isDate(time("2015-03-27T00:00:00", tz), tz));
|
||||||
|
|
||||||
// Month interval
|
// Month interval
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.MONTH_OF_YEAR).timeZone(tz).build();
|
tzRounding = Rounding.builder(DateTimeUnit.MONTH_OF_YEAR).timeZone(tz).build();
|
||||||
assertThat(tzRounding.round(time("2014-11-11T17:00:00", tz)), isDate(time("2014-11-01T00:00:00", tz), tz));
|
assertThat(tzRounding.round(time("2014-11-11T17:00:00", tz)), isDate(time("2014-11-01T00:00:00", tz), tz));
|
||||||
// DST on
|
// DST on
|
||||||
assertThat(tzRounding.round(time("2014-10-10T17:00:00", tz)), isDate(time("2014-10-01T00:00:00", tz), tz));
|
assertThat(tzRounding.round(time("2014-10-10T17:00:00", tz)), isDate(time("2014-10-01T00:00:00", tz), tz));
|
||||||
|
|
||||||
// Year interval
|
// Year interval
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.YEAR_OF_CENTURY).timeZone(tz).build();
|
tzRounding = Rounding.builder(DateTimeUnit.YEAR_OF_CENTURY).timeZone(tz).build();
|
||||||
assertThat(tzRounding.round(time("2014-11-11T17:00:00", tz)), isDate(time("2014-01-01T00:00:00", tz), tz));
|
assertThat(tzRounding.round(time("2014-11-11T17:00:00", tz)), isDate(time("2014-01-01T00:00:00", tz), tz));
|
||||||
|
|
||||||
// Two timestamps in same year and different timezone offset ("Double buckets" issue - #9491)
|
// Two timestamps in same year and different timezone offset ("Double buckets" issue - #9491)
|
||||||
tzRounding = TimeZoneRounding.builder(DateTimeUnit.YEAR_OF_CENTURY).timeZone(tz).build();
|
tzRounding = Rounding.builder(DateTimeUnit.YEAR_OF_CENTURY).timeZone(tz).build();
|
||||||
assertThat(tzRounding.round(time("2014-11-11T17:00:00", tz)),
|
assertThat(tzRounding.round(time("2014-11-11T17:00:00", tz)),
|
||||||
isDate(tzRounding.round(time("2014-08-11T17:00:00", tz)), tz));
|
isDate(tzRounding.round(time("2014-08-11T17:00:00", tz)), tz));
|
||||||
}
|
}
|
||||||
|
@ -429,8 +432,8 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
DateTimeZone tz = DateTimeZone.forID("America/Sao_Paulo");
|
DateTimeZone tz = DateTimeZone.forID("America/Sao_Paulo");
|
||||||
long start = time("2014-10-18T20:50:00.000", tz);
|
long start = time("2014-10-18T20:50:00.000", tz);
|
||||||
long end = time("2014-10-19T01:00:00.000", tz);
|
long end = time("2014-10-19T01:00:00.000", tz);
|
||||||
Rounding tzRounding = new TimeZoneRounding.TimeUnitRounding(DateTimeUnit.MINUTES_OF_HOUR, tz);
|
Rounding tzRounding = new Rounding.TimeUnitRounding(DateTimeUnit.MINUTES_OF_HOUR, tz);
|
||||||
Rounding dayTzRounding = new TimeZoneRounding.TimeIntervalRounding(60000, tz);
|
Rounding dayTzRounding = new Rounding.TimeIntervalRounding(60000, tz);
|
||||||
for (long time = start; time < end; time = time + 60000) {
|
for (long time = start; time < end; time = time + 60000) {
|
||||||
assertThat(tzRounding.nextRoundingValue(time), greaterThan(time));
|
assertThat(tzRounding.nextRoundingValue(time), greaterThan(time));
|
||||||
assertThat(dayTzRounding.nextRoundingValue(time), greaterThan(time));
|
assertThat(dayTzRounding.nextRoundingValue(time), greaterThan(time));
|
||||||
|
@ -442,7 +445,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
// standard +/-1 hour DST transition, CET
|
// standard +/-1 hour DST transition, CET
|
||||||
DateTimeUnit timeUnit = DateTimeUnit.HOUR_OF_DAY;
|
DateTimeUnit timeUnit = DateTimeUnit.HOUR_OF_DAY;
|
||||||
DateTimeZone tz = DateTimeZone.forID("CET");
|
DateTimeZone tz = DateTimeZone.forID("CET");
|
||||||
TimeZoneRounding rounding = new TimeZoneRounding.TimeUnitRounding(timeUnit, tz);
|
Rounding rounding = new Rounding.TimeUnitRounding(timeUnit, tz);
|
||||||
|
|
||||||
// 29 Mar 2015 - Daylight Saving Time Started
|
// 29 Mar 2015 - Daylight Saving Time Started
|
||||||
// at 02:00:00 clocks were turned forward 1 hour to 03:00:00
|
// at 02:00:00 clocks were turned forward 1 hour to 03:00:00
|
||||||
|
@ -466,7 +469,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
// which is not a round value for hourly rounding
|
// which is not a round value for hourly rounding
|
||||||
DateTimeUnit timeUnit = DateTimeUnit.HOUR_OF_DAY;
|
DateTimeUnit timeUnit = DateTimeUnit.HOUR_OF_DAY;
|
||||||
DateTimeZone tz = DateTimeZone.forID("Asia/Kathmandu");
|
DateTimeZone tz = DateTimeZone.forID("Asia/Kathmandu");
|
||||||
TimeZoneRounding rounding = new TimeZoneRounding.TimeUnitRounding(timeUnit, tz);
|
Rounding rounding = new Rounding.TimeUnitRounding(timeUnit, tz);
|
||||||
|
|
||||||
assertInterval(time("1985-12-31T22:00:00.000+05:30"), time("1985-12-31T23:00:00.000+05:30"), rounding, 60, tz);
|
assertInterval(time("1985-12-31T22:00:00.000+05:30"), time("1985-12-31T23:00:00.000+05:30"), rounding, 60, tz);
|
||||||
assertInterval(time("1985-12-31T23:00:00.000+05:30"), time("1986-01-01T01:00:00.000+05:45"), rounding, 105, tz);
|
assertInterval(time("1985-12-31T23:00:00.000+05:30"), time("1986-01-01T01:00:00.000+05:45"), rounding, 105, tz);
|
||||||
|
@ -479,7 +482,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
// at 02:00:00 clocks were turned backward 0:30 hours to Sunday, 3 March 1991, 01:30:00
|
// at 02:00:00 clocks were turned backward 0:30 hours to Sunday, 3 March 1991, 01:30:00
|
||||||
DateTimeUnit timeUnit = DateTimeUnit.HOUR_OF_DAY;
|
DateTimeUnit timeUnit = DateTimeUnit.HOUR_OF_DAY;
|
||||||
DateTimeZone tz = DateTimeZone.forID("Australia/Lord_Howe");
|
DateTimeZone tz = DateTimeZone.forID("Australia/Lord_Howe");
|
||||||
TimeZoneRounding rounding = new TimeZoneRounding.TimeUnitRounding(timeUnit, tz);
|
Rounding rounding = new Rounding.TimeUnitRounding(timeUnit, tz);
|
||||||
|
|
||||||
assertInterval(time("1991-03-03T00:00:00.000+11:00"), time("1991-03-03T01:00:00.000+11:00"), rounding, 60, tz);
|
assertInterval(time("1991-03-03T00:00:00.000+11:00"), time("1991-03-03T01:00:00.000+11:00"), rounding, 60, tz);
|
||||||
assertInterval(time("1991-03-03T01:00:00.000+11:00"), time("1991-03-03T02:00:00.000+10:30"), rounding, 90, tz);
|
assertInterval(time("1991-03-03T01:00:00.000+11:00"), time("1991-03-03T02:00:00.000+10:30"), rounding, 90, tz);
|
||||||
|
@ -499,7 +502,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
// at 03:45:00 clocks were turned backward 1 hour to 02:45:00
|
// at 03:45:00 clocks were turned backward 1 hour to 02:45:00
|
||||||
DateTimeUnit timeUnit = DateTimeUnit.HOUR_OF_DAY;
|
DateTimeUnit timeUnit = DateTimeUnit.HOUR_OF_DAY;
|
||||||
DateTimeZone tz = DateTimeZone.forID("Pacific/Chatham");
|
DateTimeZone tz = DateTimeZone.forID("Pacific/Chatham");
|
||||||
TimeZoneRounding rounding = new TimeZoneRounding.TimeUnitRounding(timeUnit, tz);
|
Rounding rounding = new Rounding.TimeUnitRounding(timeUnit, tz);
|
||||||
|
|
||||||
assertInterval(time("2015-04-05T02:00:00.000+13:45"), time("2015-04-05T03:00:00.000+13:45"), rounding, 60, tz);
|
assertInterval(time("2015-04-05T02:00:00.000+13:45"), time("2015-04-05T03:00:00.000+13:45"), rounding, 60, tz);
|
||||||
assertInterval(time("2015-04-05T03:00:00.000+13:45"), time("2015-04-05T03:00:00.000+12:45"), rounding, 60, tz);
|
assertInterval(time("2015-04-05T03:00:00.000+13:45"), time("2015-04-05T03:00:00.000+12:45"), rounding, 60, tz);
|
||||||
|
@ -514,7 +517,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertInterval(long rounded, long nextRoundingValue, TimeZoneRounding rounding, int minutes,
|
private static void assertInterval(long rounded, long nextRoundingValue, Rounding rounding, int minutes,
|
||||||
DateTimeZone tz) {
|
DateTimeZone tz) {
|
||||||
assertInterval(rounded, dateBetween(rounded, nextRoundingValue), nextRoundingValue, rounding, tz);
|
assertInterval(rounded, dateBetween(rounded, nextRoundingValue), nextRoundingValue, rounding, tz);
|
||||||
assertEquals(DateTimeConstants.MILLIS_PER_MINUTE * minutes, nextRoundingValue - rounded);
|
assertEquals(DateTimeConstants.MILLIS_PER_MINUTE * minutes, nextRoundingValue - rounded);
|
||||||
|
@ -527,7 +530,7 @@ public class TimeZoneRoundingTests extends ESTestCase {
|
||||||
* @param nextRoundingValue the expected upper end of the rounding interval
|
* @param nextRoundingValue the expected upper end of the rounding interval
|
||||||
* @param rounding the rounding instance
|
* @param rounding the rounding instance
|
||||||
*/
|
*/
|
||||||
private static void assertInterval(long rounded, long unrounded, long nextRoundingValue, TimeZoneRounding rounding,
|
private static void assertInterval(long rounded, long unrounded, long nextRoundingValue, Rounding rounding,
|
||||||
DateTimeZone tz) {
|
DateTimeZone tz) {
|
||||||
assert rounded <= unrounded && unrounded <= nextRoundingValue;
|
assert rounded <= unrounded && unrounded <= nextRoundingValue;
|
||||||
assertThat("rounding should be idempotent ", rounding.round(rounded), isDate(rounded, tz));
|
assertThat("rounding should be idempotent ", rounding.round(rounded), isDate(rounded, tz));
|
||||||
|
|
Loading…
Reference in New Issue