Fixes #1357 - Refactored date/time handling and added tests for RolloverFileOutputStream

This commit is contained in:
Joakim Erdfelt 2017-02-27 11:25:39 -07:00
parent b318f1c6dd
commit 0d4fcd0cb4
2 changed files with 178 additions and 11 deletions

View File

@ -24,7 +24,9 @@ import java.io.FilterOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
@ -173,26 +175,44 @@ public class RolloverFileOutputStream extends FilterOutputStream
_rollTask=new RollTask(); _rollTask=new RollTask();
midnight = Calendar.getInstance(); midnight = toMidnight(ZonedDateTime.now(), zone.toZoneId());
midnight.setTimeZone(zone);
// set to midnight
midnight.set(Calendar.HOUR, 0);
midnight.set(Calendar.MINUTE, 0);
midnight.set(Calendar.SECOND, 0);
midnight.set(Calendar.MILLISECOND, 0);
scheduleNextRollover(); scheduleNextRollover();
} }
} }
private void scheduleNextRollover() /**
* Get the "start of day" for the provided DateTime at the zone specified.
*
* @param dateTime the date time to calculate from
* @param zone the zone to return the date in
* @return start of the day of the date provided
*/
public static ZonedDateTime toMidnight(ZonedDateTime dateTime, ZoneId zone)
{
return dateTime.toLocalDate().atStartOfDay(zone);
}
/**
* Get the next "start of day" for the provided date.
*
* @param dateTime the date to calculate from
* @return the start of the next day
*/
public static ZonedDateTime nextMidnight(ZonedDateTime dateTime)
{ {
// Increment to next day. // Increment to next day.
// Using Calendar.add(DAY, 1) takes in account Daylights Savings // Using Calendar.add(DAY, 1) takes in account Daylights Savings
// differences, and still maintains the "midnight" settings for // differences, and still maintains the "midnight" settings for
// Hour, Minute, Second, Milliseconds // Hour, Minute, Second, Milliseconds
midnight.add(Calendar.DAY_OF_MONTH, 1); return dateTime.toLocalDate().plus(1, ChronoUnit.DAYS).atStartOfDay(dateTime.getZone());
__rollover.schedule(_rollTask,midnight.getTime()); }
private void scheduleNextRollover()
{
long lastMs = midnight.toInstant().toEpochMilli();
midnight = nextMidnight(midnight);
__rollover.schedule(_rollTask,midnight.toInstant().toEpochMilli() - lastMs);
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */

View File

@ -0,0 +1,147 @@
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.TimeZone;
import org.junit.Test;
public class RolloverFileOutputStreamTest
{
private static ZoneId toZoneId(String timezoneId)
{
ZoneId zone = TimeZone.getTimeZone(timezoneId).toZoneId();
// System.out.printf(".toZoneId(\"%s\") = [id=%s,normalized=%s]%n", timezoneId, zone.getId(), zone.normalized());
return zone;
}
private static ZonedDateTime toDateTime(String timendate, ZoneId zone)
{
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd-hh:mm:ss.S a z")
.withZone(zone);
return ZonedDateTime.parse(timendate, formatter);
}
private static String toString(TemporalAccessor date)
{
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd-hh:mm:ss.S a z");
return formatter.format(date);
}
private void assertSequence(ZonedDateTime midnight, Object[][] expected)
{
ZonedDateTime nextEvent = midnight;
for (int i = 0; i < expected.length; i++)
{
long lastMs = nextEvent.toInstant().toEpochMilli();
nextEvent = RolloverFileOutputStream.nextMidnight(nextEvent);
assertThat("Next Event", toString(nextEvent), is(expected[i][0]));
long duration = (nextEvent.toInstant().toEpochMilli() - lastMs);
assertThat("Duration to next event", duration, is((long) expected[i][1]));
}
}
@Test
public void testMidnightRolloverCalc_PST_DST_Start()
{
ZoneId zone = toZoneId("PST");
ZonedDateTime initialDate = toDateTime("2016.03.11-01:23:45.0 PM PST", zone);
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate, zone);
assertThat("Midnight", toString(midnight), is("2016.03.11-12:00:00.0 AM PST"));
Object expected[][] = {
{"2016.03.12-12:00:00.0 AM PST", 86_400_000L},
{"2016.03.13-12:00:00.0 AM PST", 86_400_000L},
{"2016.03.14-12:00:00.0 AM PDT", 82_800_000L}, // the short day
{"2016.03.15-12:00:00.0 AM PDT", 86_400_000L},
{"2016.03.16-12:00:00.0 AM PDT", 86_400_000L},
};
assertSequence(midnight, expected);
}
@Test
public void testMidnightRolloverCalc_PST_DST_End()
{
ZoneId zone = toZoneId("PST");
ZonedDateTime initialDate = toDateTime("2016.11.04-11:22:33.0 AM PDT", zone);
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate, zone);
assertThat("Midnight", toString(midnight), is("2016.11.04-12:00:00.0 AM PDT"));
Object expected[][] = {
{"2016.11.05-12:00:00.0 AM PDT", 86_400_000L},
{"2016.11.06-12:00:00.0 AM PDT", 86_400_000L},
{"2016.11.07-12:00:00.0 AM PST", 90_000_000L}, // the long day
{"2016.11.08-12:00:00.0 AM PST", 86_400_000L},
{"2016.11.09-12:00:00.0 AM PST", 86_400_000L},
};
assertSequence(midnight, expected);
}
@Test
public void testMidnightRolloverCalc_Sydney_DST_Start()
{
ZoneId zone = toZoneId("Australia/Sydney");
ZonedDateTime initialDate = toDateTime("2016.10.01-01:23:45.0 PM AEST", zone);
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate, zone);
assertThat("Midnight", toString(midnight), is("2016.10.01-12:00:00.0 AM AEST"));
Object expected[][] = {
{"2016.10.02-12:00:00.0 AM AEST", 86_400_000L},
{"2016.10.03-12:00:00.0 AM AEDT", 82_800_000L}, // the short day
{"2016.10.04-12:00:00.0 AM AEDT", 86_400_000L},
{"2016.10.05-12:00:00.0 AM AEDT", 86_400_000L},
{"2016.10.06-12:00:00.0 AM AEDT", 86_400_000L},
};
assertSequence(midnight, expected);
}
@Test
public void testMidnightRolloverCalc_Sydney_DST_End()
{
ZoneId zone = toZoneId("Australia/Sydney");
ZonedDateTime initialDate = toDateTime("2016.04.02-11:22:33.0 AM AEDT", zone);
ZonedDateTime midnight = RolloverFileOutputStream.toMidnight(initialDate, zone);
assertThat("Midnight", toString(midnight), is("2016.04.02-12:00:00.0 AM AEDT"));
Object expected[][] = {
{"2016.04.03-12:00:00.0 AM AEDT", 86_400_000L},
{"2016.04.04-12:00:00.0 AM AEST", 90_000_000L}, // The long day
{"2016.04.05-12:00:00.0 AM AEST", 86_400_000L},
{"2016.04.06-12:00:00.0 AM AEST", 86_400_000L},
{"2016.04.07-12:00:00.0 AM AEST", 86_400_000L},
};
assertSequence(midnight, expected);
}
}