blob: fdfcdcf5ca72483f22b24c65698fafa2cabc908e [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed 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 libcore.java.util;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import junit.framework.TestCase;
/**
* Tests for {@link SimpleTimeZone}.
*
* <p>The methods starting {@code testDstParis2014_...} and {@code testDstNewYork2014} check
* various different ways to specify the same instants when DST starts and ends in the associated
* real world time zone in 2014, i.e. Europe/Paris and America/New_York respectively.
*/
public class SimpleTimeZoneTest extends TestCase {
private static final int NEW_YORK_RAW_OFFSET = -18000000;
private static final int PARIS_RAW_OFFSET = 3600000;
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
/**
* Sanity check to ensure that the standard TimeZone for Europe/Paris has the correct DST
* transition times.
*/
public void testStandardParis2014() {
TimeZone timeZone = TimeZone.getTimeZone("Europe/Paris");
checkDstParis2014(timeZone);
}
public void testDstParis2014_LastSundayMarch_LastSundayOctober_UtcTime() {
TimeZone timeZone = new SimpleTimeZone(PARIS_RAW_OFFSET, "Europe/Paris",
Calendar.MARCH, -1, Calendar.SUNDAY, 3600000, SimpleTimeZone.UTC_TIME,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 3600000, SimpleTimeZone.UTC_TIME, 3600000);
checkDstParis2014(timeZone);
}
public void testDstParis2014_SundayAfter25thMarch_SundayAfter25thOctober_UtcTime() {
TimeZone timeZone = new SimpleTimeZone(PARIS_RAW_OFFSET, "Europe/Paris",
Calendar.MARCH, 25, -Calendar.SUNDAY, 3600000, SimpleTimeZone.UTC_TIME,
Calendar.OCTOBER, 25, -Calendar.SUNDAY, 3600000, SimpleTimeZone.UTC_TIME, 3600000);
checkDstParis2014(timeZone);
}
public void testDstParis2014_30thMarch_26thOctober_UtcTime() {
TimeZone timeZone = new SimpleTimeZone(PARIS_RAW_OFFSET, "Europe/Paris",
Calendar.MARCH, 30, 0, 3600000, SimpleTimeZone.UTC_TIME,
Calendar.OCTOBER, 26, 0, 3600000, SimpleTimeZone.UTC_TIME, 3600000);
checkDstParis2014(timeZone);
}
/**
* Check that the DST transitions in the supplied {@link TimeZone} are as expected for
* Europe/Paris in 2014.
*/
private void checkDstParis2014(TimeZone timeZone) {
checkDstTransitionTimes(timeZone, 2014,
"2014-03-30T01:00:00.000+0000",
"2014-10-26T01:00:00.000+0000");
}
public void testDst_1stSundayApril_1stSundayOctober_DefaultTime() {
TimeZone timeZone = new SimpleTimeZone(-18000000, "EST",
Calendar.APRIL, 1, -Calendar.SUNDAY, 7200000,
Calendar.OCTOBER, -1, Calendar.SUNDAY, 7200000,
3600000);
checkDstTransitionTimes(timeZone, 1998,
"1998-04-05T07:00:00.000+0000",
"1998-10-25T06:00:00.000+0000");
checkDstTransitionTimes(timeZone, 2014,
"2014-04-06T07:00:00.000+0000",
"2014-10-26T06:00:00.000+0000");
}
/**
* Sanity check to ensure that the standard TimeZone for America/New_York has the correct DST
* transition times.
*/
public void testStandardNewYork2014() {
TimeZone timeZone = TimeZone.getTimeZone("America/New_York");
checkDstNewYork2014(timeZone);
}
public void testDstNewYork2014_2ndSundayMarch_1stSundayNovember_StandardTime() {
TimeZone timeZone = new SimpleTimeZone(NEW_YORK_RAW_OFFSET, "EST",
Calendar.MARCH, 2, Calendar.SUNDAY, 7200000, SimpleTimeZone.STANDARD_TIME,
Calendar.NOVEMBER, 1, Calendar.SUNDAY, 3600000, SimpleTimeZone.STANDARD_TIME,
3600000);
checkDstNewYork2014(timeZone);
}
public void testDstNewYork2014_2ndSundayMarch_1stSundayNovember_UtcTime() {
TimeZone timeZone = new SimpleTimeZone(NEW_YORK_RAW_OFFSET, "EST",
Calendar.MARCH, 2, Calendar.SUNDAY, 25200000, SimpleTimeZone.UTC_TIME,
Calendar.NOVEMBER, 1, Calendar.SUNDAY, 21600000, SimpleTimeZone.UTC_TIME,
3600000);
checkDstNewYork2014(timeZone);
}
public void testDstNewYork2014_2ndSundayMarch_1stSundayNovember_WallTime() {
TimeZone timeZone = new SimpleTimeZone(NEW_YORK_RAW_OFFSET, "EST",
Calendar.MARCH, 2, Calendar.SUNDAY, 7200000, SimpleTimeZone.WALL_TIME,
Calendar.NOVEMBER, 1, Calendar.SUNDAY, 7200000, SimpleTimeZone.WALL_TIME,
3600000);
checkDstNewYork2014(timeZone);
}
public void testDstNewYork2014_2ndSundayMarch_1stSundayNovember_DefaultTime() {
TimeZone timeZone = new SimpleTimeZone(NEW_YORK_RAW_OFFSET, "EST",
Calendar.MARCH, 2, Calendar.SUNDAY, 7200000,
Calendar.NOVEMBER, 1, Calendar.SUNDAY, 7200000,
3600000);
checkDstNewYork2014(timeZone);
}
public void testDstNewYork2014_9thMarch_2ndNovember_StandardTime() {
TimeZone timeZone = new SimpleTimeZone(NEW_YORK_RAW_OFFSET, "EST",
Calendar.MARCH, 9, 0, 7200000, SimpleTimeZone.STANDARD_TIME,
Calendar.NOVEMBER, 2, 0, 3600000, SimpleTimeZone.STANDARD_TIME,
3600000);
checkDstNewYork2014(timeZone);
}
public void testDstNewYork2014_9thMarch_2ndNovember_UtcTime() {
TimeZone timeZone = new SimpleTimeZone(NEW_YORK_RAW_OFFSET, "EST",
Calendar.MARCH, 9, 0, 25200000, SimpleTimeZone.UTC_TIME,
Calendar.NOVEMBER, 2, 0, 21600000, SimpleTimeZone.UTC_TIME,
3600000);
checkDstNewYork2014(timeZone);
}
public void testDstNewYork2014_9thMarch_2ndNovember_WallTime() {
TimeZone timeZone = new SimpleTimeZone(NEW_YORK_RAW_OFFSET, "EST",
Calendar.MARCH, 9, 0, 7200000, SimpleTimeZone.WALL_TIME,
Calendar.NOVEMBER, 2, 0, 7200000, SimpleTimeZone.WALL_TIME,
3600000);
checkDstNewYork2014(timeZone);
}
public void testDstNewYork2014_9thMarch_2ndNovember_DefaultTime() {
TimeZone timeZone = new SimpleTimeZone(NEW_YORK_RAW_OFFSET, "EST",
Calendar.MARCH, 9, 0, 7200000,
Calendar.NOVEMBER, 2, 0, 7200000,
3600000);
checkDstNewYork2014(timeZone);
}
/**
* Check that the DST transitions in the supplied {@link TimeZone} are as expected for
* America/New_York in 2014.
*/
private void checkDstNewYork2014(TimeZone timeZone) {
checkDstTransitionTimes(timeZone, 2014,
"2014-03-09T07:00:00.000+0000",
"2014-11-02T06:00:00.000+0000");
}
/**
* Scan from the start of the year to the end to find the DST transition points.
*
* @param timeZone the {@link TimeZone} whose transition points are being found.
* @param startOfYearMillis the start of the calendar year in {@code timeZone} to scan, in
* milliseconds.
* @return an array of the entry and exit time in millis.
*/
private static long[] findDstEntryAndExit(TimeZone timeZone, long startOfYearMillis) {
if (!timeZone.useDaylightTime()) {
throw new IllegalStateException("Time zone " + timeZone
+ " doesn't support daylight savings time");
}
long[] transitions = new long[2];
GregorianCalendar cal = new GregorianCalendar(timeZone, Locale.ENGLISH);
cal.setTimeInMillis(startOfYearMillis);
int year = cal.get(Calendar.YEAR);
while (!timeZone.inDaylightTime(new Date(cal.getTimeInMillis()))) {
// Make sure that this doesn't loop forever.
if (cal.get(Calendar.YEAR) != year) {
throw new IllegalStateException(
"Doesn't enter daylight savings time in " + year + " in " + timeZone);
}
cal.add(Calendar.HOUR_OF_DAY, 1);
}
cal.add(Calendar.MILLISECOND, -1);
assertFalse(timeZone.inDaylightTime(cal.getTime()));
cal.add(Calendar.MILLISECOND, 1);
long entryPoint = cal.getTimeInMillis();
while (timeZone.inDaylightTime(new Date(cal.getTimeInMillis()))) {
if (cal.get(Calendar.YEAR) != year) {
throw new IllegalStateException(
"Doesn't exit daylight savings time in " + year + " in " + timeZone);
}
cal.add(Calendar.HOUR_OF_DAY, 1);
}
cal.add(Calendar.MILLISECOND, -1);
assertTrue(timeZone.inDaylightTime(cal.getTime()));
cal.add(Calendar.MILLISECOND, 1);
long exitPoint = cal.getTimeInMillis();
transitions[0] = entryPoint;
transitions[1] = exitPoint;
return transitions;
}
public static String formatCalendar(Calendar cal) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ",
Locale.ENGLISH);
format.setTimeZone(cal.getTimeZone());
return format.format(new Date(cal.getTimeInMillis()));
}
private static String formatTime(TimeZone timeZone, long millis) {
Calendar cal = new GregorianCalendar(timeZone, Locale.ENGLISH);
cal.setTimeInMillis(millis);
return formatCalendar(cal);
}
private void checkDstTransitionTimes(TimeZone timeZone, int year,
String expectedUtcEntryTime, String expectedUtcExitTime) {
// Find the start of the year in the supplied time zone.
GregorianCalendar calendar = new GregorianCalendar(timeZone, Locale.ENGLISH);
calendar.set(year, Calendar.JANUARY, 1, 0, 0, 0);
calendar.set(Calendar.MILLISECOND, 0);
long start = calendar.getTimeInMillis();
// Find the DST transitions instants.
long[] simpleTransitions = findDstEntryAndExit(timeZone, start);
String actualUtcEntryTime = formatTime(UTC, simpleTransitions[0]);
String actualUtcExitTime = formatTime(UTC, simpleTransitions[1]);
assertEquals("Transition point mismatch: ",
describeTransitions(expectedUtcEntryTime, expectedUtcExitTime),
describeTransitions(actualUtcEntryTime, actualUtcExitTime));
}
/**
* Create a string representation of the transition information to allow all aspects to be
* compared in one go providing a better error message.
*/
private String describeTransitions(String utcEntryTime, String utcExitTime) {
return "{Entry: " + utcEntryTime + ", Exit: " + utcExitTime + "}";
}
}