Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/util/TimeZone/TimeZoneBoundaryTest.java
38821 views
/*1* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @library /java/text/testlib26* @summary test Time Zone Boundary27*/2829import java.text.*;30import java.util.*;3132/**33* A test which discovers the boundaries of DST programmatically and verifies34* that they are correct.35*/36public class TimeZoneBoundaryTest extends IntlTest37{38static final int ONE_SECOND = 1000;39static final int ONE_MINUTE = 60*ONE_SECOND;40static final int ONE_HOUR = 60*ONE_MINUTE;41static final long ONE_DAY = 24*ONE_HOUR;42static final long ONE_YEAR = (long)(365.25 * ONE_DAY);43static final long SIX_MONTHS = ONE_YEAR / 2;4445static final int MONTH_LENGTH[] = {31,29,31,30,31,30,31,31,30,31,30,31};4647// These values are empirically determined to be correct48static final long PST_1997_BEG = 860320800000L;49static final long PST_1997_END = 877856400000L;5051// Minimum interval for binary searches in ms; should be no larger52// than 1000.53static final long INTERVAL = 10; // Milliseconds5455static final String AUSTRALIA = "Australia/Adelaide";56static final long AUSTRALIA_1997_BEG = 877797000000L;57static final long AUSTRALIA_1997_END = 859653000000L;5859public static void main(String[] args) throws Exception {60new TimeZoneBoundaryTest().run(args);61}6263/**64* Date.toString().substring() Boundary Test65* Look for a DST changeover to occur within 6 months of the given Date.66* The initial Date.toString() should yield a string containing the67* startMode as a SUBSTRING. The boundary will be tested to be68* at the expectedBoundary value.69*/70void findDaylightBoundaryUsingDate(Date d, String startMode, long expectedBoundary)71{72// Given a date with a year start, find the Daylight onset73// and end. The given date should be 1/1/xx in some year.7475if (d.toString().indexOf(startMode) == -1)76{77logln("Error: " + startMode + " not present in " + d);78}7980// Use a binary search, assuming that we have a Standard81// time at the midpoint.82long min = d.getTime();83long max = min + SIX_MONTHS;8485while ((max - min) > INTERVAL)86{87long mid = (min + max) >> 1;88String s = new Date(mid).toString();89// logln(s);90if (s.indexOf(startMode) != -1)91{92min = mid;93}94else95{96max = mid;97}98}99100logln("Date Before: " + showDate(min));101logln("Date After: " + showDate(max));102long mindelta = expectedBoundary - min;103long maxdelta = max - expectedBoundary;104if (mindelta >= 0 && mindelta <= INTERVAL &&105mindelta >= 0 && mindelta <= INTERVAL)106logln("PASS: Expected boundary at " + expectedBoundary);107else108errln("FAIL: Expected boundary at " + expectedBoundary);109}110111void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST, long expectedBoundary)112{113findDaylightBoundaryUsingTimeZone(d, startsInDST, expectedBoundary,114TimeZone.getDefault());115}116117void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST,118long expectedBoundary, TimeZone tz)119{120// Given a date with a year start, find the Daylight onset121// and end. The given date should be 1/1/xx in some year.122123// Use a binary search, assuming that we have a Standard124// time at the midpoint.125long min = d.getTime();126long max = min + SIX_MONTHS;127128if (tz.inDaylightTime(d) != startsInDST)129{130errln("FAIL: " + tz.getID() + " inDaylightTime(" +131d + ") != " + startsInDST);132startsInDST = !startsInDST; // Flip over; find the apparent value133}134135if (tz.inDaylightTime(new Date(max)) == startsInDST)136{137errln("FAIL: " + tz.getID() + " inDaylightTime(" +138(new Date(max)) + ") != " + (!startsInDST));139return;140}141142while ((max - min) > INTERVAL)143{144long mid = (min + max) >> 1;145boolean isIn = tz.inDaylightTime(new Date(mid));146if (isIn == startsInDST)147{148min = mid;149}150else151{152max = mid;153}154}155156logln(tz.getID() + " Before: " + showDate(min, tz));157logln(tz.getID() + " After: " + showDate(max, tz));158159long mindelta = expectedBoundary - min;160long maxdelta = max - expectedBoundary;161if (mindelta >= 0 && mindelta <= INTERVAL &&162mindelta >= 0 && mindelta <= INTERVAL)163logln("PASS: Expected boundary at " + expectedBoundary);164else165errln("FAIL: Expected boundary at " + expectedBoundary);166}167168private static String showDate(long l)169{170return showDate(new Date(l));171}172173@SuppressWarnings("deprecation")174private static String showDate(Date d)175{176return "" + d.getYear() + "/" + showNN(d.getMonth()+1) + "/" + showNN(d.getDate()) +177" " + showNN(d.getHours()) + ":" + showNN(d.getMinutes()) +178" \"" + d + "\" = " +179d.getTime();180}181182private static String showDate(long l, TimeZone z)183{184return showDate(new Date(l), z);185}186187@SuppressWarnings("deprecation")188private static String showDate(Date d, TimeZone zone)189{190DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);191fmt.setTimeZone(zone);192return "" + d.getYear() + "/" + showNN(d.getMonth()+1) + "/" + showNN(d.getDate()) +193" " + showNN(d.getHours()) + ":" + showNN(d.getMinutes()) +194" \"" + d + "\" = " +195fmt.format(d);196}197198private static String showNN(int n)199{200return ((n < 10) ? "0" : "") + n;201}202203/**204* Given a date, a TimeZone, and expected values for inDaylightTime,205* useDaylightTime, zone and DST offset, verify that this is the case.206*/207void verifyDST(Date d, TimeZone time_zone,208boolean expUseDaylightTime, boolean expInDaylightTime,209int expZoneOffset, int expDSTOffset)210{211logln("-- Verifying time " + d +212" in zone " + time_zone.getID());213214if (time_zone.inDaylightTime(d) == expInDaylightTime)215logln("PASS: inDaylightTime = " + time_zone.inDaylightTime(d));216else217errln("FAIL: inDaylightTime = " + time_zone.inDaylightTime(d));218219if (time_zone.useDaylightTime() == expUseDaylightTime)220logln("PASS: useDaylightTime = " + time_zone.useDaylightTime());221else222errln("FAIL: useDaylightTime = " + time_zone.useDaylightTime());223224if (time_zone.getRawOffset() == expZoneOffset)225logln("PASS: getRawOffset() = " + expZoneOffset/(double)ONE_HOUR);226else227errln("FAIL: getRawOffset() = " + time_zone.getRawOffset()/(double)ONE_HOUR +228"; expected " + expZoneOffset/(double)ONE_HOUR);229230GregorianCalendar gc = new GregorianCalendar(time_zone);231gc.setTime(d);232int offset = time_zone.getOffset(gc.get(gc.ERA), gc.get(gc.YEAR), gc.get(gc.MONTH),233gc.get(gc.DAY_OF_MONTH), gc.get(gc.DAY_OF_WEEK),234((gc.get(gc.HOUR_OF_DAY) * 60 +235gc.get(gc.MINUTE)) * 60 +236gc.get(gc.SECOND)) * 1000 +237gc.get(gc.MILLISECOND));238if (offset == expDSTOffset)239logln("PASS: getOffset() = " + offset/(double)ONE_HOUR);240else241errln("FAIL: getOffset() = " + offset/(double)ONE_HOUR +242"; expected " + expDSTOffset/(double)ONE_HOUR);243}244245@SuppressWarnings("deprecation")246public void TestBoundaries()247{248TimeZone pst = TimeZone.getTimeZone("PST");249TimeZone save = TimeZone.getDefault();250try {251TimeZone.setDefault(pst);252253// DST changeover for PST is 4/6/1997 at 2 hours past midnight254Date d = new Date(97,Calendar.APRIL,6);255256// i is minutes past midnight standard time257for (int i=60; i<=180; i+=15)258{259boolean inDST = (i >= 120);260Date e = new Date(d.getTime() + i*60*1000);261verifyDST(e, pst, true, inDST, -8*ONE_HOUR,262inDST ? -7*ONE_HOUR : -8*ONE_HOUR);263}264265logln("========================================");266findDaylightBoundaryUsingDate(new Date(97,0,1), "PST", PST_1997_BEG);267logln("========================================");268findDaylightBoundaryUsingDate(new Date(97,6,1), "PDT", PST_1997_END);269270// Southern hemisphere test271logln("========================================");272TimeZone z = TimeZone.getTimeZone(AUSTRALIA);273findDaylightBoundaryUsingTimeZone(new Date(97,0,1), true, AUSTRALIA_1997_END, z);274275logln("========================================");276findDaylightBoundaryUsingTimeZone(new Date(97,0,1), false, PST_1997_BEG);277logln("========================================");278findDaylightBoundaryUsingTimeZone(new Date(97,6,1), true, PST_1997_END);279} finally {280TimeZone.setDefault(save);281}282}283284void testUsingBinarySearch(SimpleTimeZone tz, Date d, long expectedBoundary)285{286// Given a date with a year start, find the Daylight onset287// and end. The given date should be 1/1/xx in some year.288289// Use a binary search, assuming that we have a Standard290// time at the midpoint.291long min = d.getTime();292long max = min + (long)(365.25 / 2 * ONE_DAY);293294// First check the boundaries295boolean startsInDST = tz.inDaylightTime(d);296297if (tz.inDaylightTime(new Date(max)) == startsInDST)298{299logln("Error: inDaylightTime(" + (new Date(max)) + ") != " + (!startsInDST));300}301302while ((max - min) > INTERVAL)303{304long mid = (min + max) >> 1;305if (tz.inDaylightTime(new Date(mid)) == startsInDST)306{307min = mid;308}309else310{311max = mid;312}313}314315logln("Binary Search Before: " + showDate(min));316logln("Binary Search After: " + showDate(max));317318long mindelta = expectedBoundary - min;319long maxdelta = max - expectedBoundary;320if (mindelta >= 0 && mindelta <= INTERVAL &&321mindelta >= 0 && mindelta <= INTERVAL)322logln("PASS: Expected boundary at " + expectedBoundary);323else324errln("FAIL: Expected boundary at " + expectedBoundary);325}326327/*328static void testUsingMillis(Date d, boolean startsInDST)329{330long millis = d.getTime();331long max = millis + (long)(370 * ONE_DAY); // A year plus extra332333boolean lastDST = startsInDST;334while (millis < max)335{336cal.setTime(new Date(millis));337boolean inDaylight = cal.inDaylightTime();338339if (inDaylight != lastDST)340{341logln("Switch " + (inDaylight ? "into" : "out of")342+ " DST at " + (new Date(millis)));343lastDST = inDaylight;344}345346millis += 15*ONE_MINUTE;347}348}349*/350351/**352* Test new rule formats.353*/354@SuppressWarnings("deprecation")355public void TestNewRules()356{357//logln(Locale.getDefault().getDisplayName());358//logln(TimeZone.getDefault().getID());359//logln(new Date(0));360361if (true)362{363// Doesn't matter what the default TimeZone is here, since we364// are creating our own TimeZone objects.365366SimpleTimeZone tz;367368logln("-----------------------------------------------------------------");369logln("Aug 2ndTues .. Mar 15");370tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_1",371Calendar.AUGUST, 2, Calendar.TUESDAY, 2*ONE_HOUR,372Calendar.MARCH, 15, 0, 2*ONE_HOUR);373//logln(tz.toString());374logln("========================================");375testUsingBinarySearch(tz, new Date(97,0,1), 858416400000L);376logln("========================================");377testUsingBinarySearch(tz, new Date(97,6,1), 871380000000L);378379logln("-----------------------------------------------------------------");380logln("Apr Wed>=14 .. Sep Sun<=20");381tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_2",382Calendar.APRIL, 14, -Calendar.WEDNESDAY, 2*ONE_HOUR,383Calendar.SEPTEMBER, -20, -Calendar.SUNDAY, 2*ONE_HOUR);384//logln(tz.toString());385logln("========================================");386testUsingBinarySearch(tz, new Date(97,0,1), 861184800000L);387logln("========================================");388testUsingBinarySearch(tz, new Date(97,6,1), 874227600000L);389}390391/*392if (true)393{394logln("========================================");395logln("Stepping using millis");396testUsingMillis(new Date(97,0,1), false);397}398399if (true)400{401logln("========================================");402logln("Stepping using fields");403testUsingFields(1997, false);404}405406if (false)407{408cal.clear();409cal.set(1997, 3, 5, 10, 0);410// cal.inDaylightTime();411logln("Date = " + cal.getTime());412logln("Millis = " + cal.getTime().getTime()/3600000);413}414*/415}416417//----------------------------------------------------------------------418//----------------------------------------------------------------------419//----------------------------------------------------------------------420// Long Bug421//----------------------------------------------------------------------422//----------------------------------------------------------------------423//----------------------------------------------------------------------424425//public void Test3()426//{427// findDaylightBoundaryUsingTimeZone(new Date(97,6,1), true);428//}429430/**431* Find boundaries by stepping.432*/433@SuppressWarnings("deprecation")434void findBoundariesStepwise(int year, long interval, TimeZone z, int expectedChanges)435{436Date d = new Date(year - 1900, Calendar.JANUARY, 1);437long time = d.getTime(); // ms438long limit = time + ONE_YEAR + ONE_DAY;439boolean lastState = z.inDaylightTime(d);440int changes = 0;441logln("-- Zone " + z.getID() + " starts in " + year + " with DST = " + lastState);442logln("useDaylightTime = " + z.useDaylightTime());443while (time < limit)444{445d.setTime(time);446boolean state = z.inDaylightTime(d);447if (state != lastState)448{449logln((state ? "Entry " : "Exit ") +450"at " + d);451lastState = state;452++changes;453}454time += interval;455}456if (changes == 0)457{458if (!lastState && !z.useDaylightTime()) logln("No DST");459else errln("FAIL: Timezone<" + z.getID() + "> DST all year, or no DST with true useDaylightTime");460}461else if (changes != 2)462{463errln("FAIL: Timezone<" + z.getID() + "> " + changes + " changes seen; should see 0 or 2");464}465else if (!z.useDaylightTime())466{467errln("FAIL: Timezone<" + z.getID() + "> useDaylightTime false but 2 changes seen");468}469if (changes != expectedChanges)470{471errln("FAIL: Timezone<" + z.getID() + "> " + changes + " changes seen; expected " + expectedChanges);472}473}474475public void TestStepwise()476{477findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("ACT"), 0);478// "EST" is disabled because its behavior depends on the mapping property. (6466476).479//findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("EST"), 2);480findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("HST"), 0);481findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("PST"), 2);482findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("PST8PDT"), 2);483findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("SystemV/PST"), 0);484findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("SystemV/PST8PDT"), 2);485findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("Japan"), 0);486findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("Europe/Paris"), 2);487findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("America/Los_Angeles"), 2);488findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone(AUSTRALIA), 2);489}490}491492493