public Rounding build() { Rounding timeZoneRounding; if (unit != null) { if (preTz.equals(DateTimeZone.UTC) && postTz.equals(DateTimeZone.UTC)) { timeZoneRounding = new UTCTimeZoneRoundingFloor(unit); } else if (preZoneAdjustLargeInterval || unit.field().getDurationField().getUnitMillis() < DateTimeConstants.MILLIS_PER_HOUR * 12) { timeZoneRounding = new TimeTimeZoneRoundingFloor(unit, preTz, postTz); } else { timeZoneRounding = new DayTimeZoneRoundingFloor(unit, preTz, postTz); } } else { if (preTz.equals(DateTimeZone.UTC) && postTz.equals(DateTimeZone.UTC)) { timeZoneRounding = new UTCIntervalTimeZoneRounding(interval); } else if (preZoneAdjustLargeInterval || interval < DateTimeConstants.MILLIS_PER_HOUR * 12) { timeZoneRounding = new TimeIntervalTimeZoneRounding(interval, preTz, postTz); } else { timeZoneRounding = new DayIntervalTimeZoneRounding(interval, preTz, postTz); } } if (preOffset != 0 || postOffset != 0) { timeZoneRounding = new PrePostRounding(timeZoneRounding, preOffset, postOffset); } if (factor != 1.0f) { timeZoneRounding = new FactorRounding(timeZoneRounding, factor); } return timeZoneRounding; }
/** * Randomized test on TimeUnitRounding. Test uses random {@link DateTimeUnit} and {@link * DateTimeZone} and often (50% of the time) chooses test dates that are exactly on or close to * offset changes (e.g. DST) in the chosen time zone. * * <p>It rounds the test date down and up and performs various checks on the rounding unit * interval that is defined by this. Assumptions tested are described in {@link * #assertInterval(long, long, long, Rounding, DateTimeZone)} */ public void testRoundingRandom() { for (int i = 0; i < 1000; ++i) { DateTimeUnit timeUnit = randomTimeUnit(); DateTimeZone tz = randomDateTimeZone(); 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 unitMillis = timeUnit.field(tz).getDurationField().getUnitMillis(); if (randomBoolean()) { nastyDate(date, tz, unitMillis); } final long roundedDate = rounding.round(date); final long nextRoundingValue = rounding.nextRoundingValue(roundedDate); assertInterval(roundedDate, date, nextRoundingValue, rounding, tz); // check correct unit interval width for units smaller than a day, they should be fixed size // except for transitions if (unitMillis <= DateTimeConstants.MILLIS_PER_DAY) { // if the interval defined didn't cross timezone offset transition, it should cover // unitMillis width if (tz.getOffset(roundedDate - 1) == tz.getOffset(nextRoundingValue + 1)) { assertThat( "unit interval width not as expected for [" + timeUnit + "], [" + tz + "] at " + new DateTime(roundedDate), nextRoundingValue - roundedDate, equalTo(unitMillis)); } } } }
private static DateTimeUnit randomTimeUnit() { byte id = (byte) randomIntBetween(1, 8); return DateTimeUnit.resolve(id); }
@Override public void writeTo(StreamOutput out) throws IOException { out.writeByte(unit.id()); out.writeSharedString(preTz.getID()); out.writeSharedString(postTz.getID()); }
@Override public long nextRoundingValue(long value) { return unit.field().getDurationField().getUnitMillis() + value; }
@Override public void readFrom(StreamInput in) throws IOException { unit = DateTimeUnit.resolve(in.readByte()); preTz = DateTimeZone.forID(in.readSharedString()); postTz = DateTimeZone.forID(in.readSharedString()); }
@Override public long roundKey(long utcMillis) { long time = utcMillis + preTz.getOffset(utcMillis); return unit.field().roundFloor(time); }
@Override public void writeTo(StreamOutput out) throws IOException { out.writeByte(unit.id()); }
@Override public void readFrom(StreamInput in) throws IOException { unit = DateTimeUnit.resolve(in.readByte()); }
@Override public long nextRoundingValue(long value) { return unit.field().roundCeiling(value + 1); }
@Override public long roundKey(long utcMillis) { return unit.field().roundFloor(utcMillis); }