| /* | |
| * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| /* | |
| * @test | |
| * @bug 4052967 4073209 4073215 4084933 4096952 4109314 4126678 4151406 4151429 | |
| * 4154525 4154537 4154542 4154650 4159922 4162593 4173604 4176686 4184229 4208960 | |
| * 4966229 6433179 6851214 8007520 8008577 8174269 8347841 | |
| * @library /java/text/testlib | |
| * @run junit TimeZoneRegression | |
| */ | |
| import java.util.*; | |
| import java.io.*; | |
| import java.text.*; | |
| import org.junit.jupiter.api.Test; | |
| import static org.junit.jupiter.api.Assertions.fail; | |
| public class TimeZoneRegression { | |
| @Test | |
| public void Test4073209() { | |
| TimeZone z1 = TimeZone.getTimeZone("America/Los_Angeles"); | |
| TimeZone z2 = TimeZone.getTimeZone("America/Los_Angeles"); | |
| if (z1 == z2) { | |
| fail("Fail: TimeZone should return clones"); | |
| } | |
| } | |
| @SuppressWarnings("deprecation") | |
| @Test | |
| public void Test4073215() { | |
| SimpleTimeZone z = new SimpleTimeZone(0, "GMT"); | |
| if (z.useDaylightTime()) { | |
| fail("Fail: Fix test to start with non-DST zone"); | |
| } | |
| z.setStartRule(Calendar.FEBRUARY, 1, Calendar.SUNDAY, 0); | |
| z.setEndRule(Calendar.MARCH, -1, Calendar.SUNDAY, 0); | |
| if (!z.useDaylightTime()) { | |
| fail("Fail: DST not active"); | |
| } | |
| if (z.inDaylightTime(new Date(97, Calendar.JANUARY, 31)) || | |
| !z.inDaylightTime(new Date(97, Calendar.MARCH, 1)) || | |
| z.inDaylightTime(new Date(97, Calendar.MARCH, 31))) { | |
| fail("Fail: DST not working as expected"); | |
| } | |
| } | |
| /** | |
| * The expected behavior of TimeZone around the boundaries is: | |
| * (Assume transition time of 2:00 AM) | |
| * day of onset 1:59 AM STD = display name 1:59 AM ST | |
| * 2:00 AM STD = display name 3:00 AM DT | |
| * day of end 0:59 AM STD = display name 1:59 AM DT | |
| * 1:00 AM STD = display name 1:00 AM ST | |
| */ | |
| @Test | |
| public void Test4084933() { | |
| // test both SimpleTimeZone and ZoneInfo objects. | |
| // @since 1.4 | |
| sub4084933(getPST()); | |
| sub4084933(TimeZone.getTimeZone("America/Los_Angeles")); | |
| } | |
| private void sub4084933(TimeZone tz) { | |
| long offset1 = tz.getOffset(1, | |
| 1997, Calendar.OCTOBER, 26, Calendar.SUNDAY, (2*60*60*1000)); | |
| long offset2 = tz.getOffset(1, | |
| 1997, Calendar.OCTOBER, 26, Calendar.SUNDAY, (2*60*60*1000)-1); | |
| long offset3 = tz.getOffset(1, | |
| 1997, Calendar.OCTOBER, 26, Calendar.SUNDAY, (1*60*60*1000)); | |
| long offset4 = tz.getOffset(1, | |
| 1997, Calendar.OCTOBER, 26, Calendar.SUNDAY, (1*60*60*1000)-1); | |
| /* | |
| * The following was added just for consistency. It shows that going *to* Daylight | |
| * Savings Time (PDT) does work at 2am. | |
| */ | |
| long offset5 = tz.getOffset(1, | |
| 1997, Calendar.APRIL, 6, Calendar.SUNDAY, (2*60*60*1000)); | |
| long offset6 = tz.getOffset(1, | |
| 1997, Calendar.APRIL, 6, Calendar.SUNDAY, (2*60*60*1000)-1); | |
| long offset7 = tz.getOffset(1, | |
| 1997, Calendar.APRIL, 6, Calendar.SUNDAY, (1*60*60*1000)); | |
| long offset8 = tz.getOffset(1, | |
| 1997, Calendar.APRIL, 6, Calendar.SUNDAY, (1*60*60*1000)-1); | |
| long SToffset = -8 * 60*60*1000L; | |
| long DToffset = -7 * 60*60*1000L; | |
| if (offset1 != SToffset || offset2 != SToffset || | |
| offset3 != SToffset || offset4 != DToffset || | |
| offset5 != DToffset || offset6 != SToffset || | |
| offset7 != SToffset || offset8 != SToffset) | |
| fail("Fail: TimeZone misbehaving"); { | |
| } | |
| } | |
| @Test | |
| public void Test4096952() { | |
| String[] ZONES = { "GMT", "MET", "Asia/Kolkata" }; | |
| boolean pass = true; | |
| try { | |
| for (int i=0; i<ZONES.length; ++i) { | |
| TimeZone zone = TimeZone.getTimeZone(ZONES[i]); | |
| if (!zone.getID().equals(ZONES[i])) | |
| fail("Fail: Test broken; zones not instantiating"); | |
| ByteArrayOutputStream baos; | |
| ObjectOutputStream ostream = | |
| new ObjectOutputStream(baos = new | |
| ByteArrayOutputStream()); | |
| ostream.writeObject(zone); | |
| ostream.close(); | |
| baos.close(); | |
| ObjectInputStream istream = | |
| new ObjectInputStream(new | |
| ByteArrayInputStream(baos.toByteArray())); | |
| TimeZone frankenZone = (TimeZone) istream.readObject(); | |
| //logln("Zone: " + zone); | |
| //logln("FrankenZone: " + frankenZone); | |
| if (!zone.equals(frankenZone)) { | |
| System.out.println("TimeZone " + zone.getID() + | |
| " not equal to serialized/deserialized one"); | |
| pass = false; | |
| } | |
| } | |
| if (!pass) fail("Fail: TimeZone serialization/equality bug"); | |
| } | |
| catch (IOException e) { | |
| fail("Fail: " + e); | |
| e.printStackTrace(); | |
| } | |
| catch (ClassNotFoundException e) { | |
| fail("Fail: " + e); | |
| e.printStackTrace(); | |
| } | |
| } | |
| @Test | |
| public void Test4109314() { | |
| Locale locale = Locale.getDefault(); | |
| if (!TestUtils.usesGregorianCalendar(locale)) { | |
| System.out.println("Skipping this test because locale is " + locale); | |
| return; | |
| } | |
| // test both SimpleTimeZone and ZoneInfo objects. | |
| // @since 1.4 | |
| sub4109314(getPST()); | |
| sub4109314(TimeZone.getTimeZone("America/Los_Angeles")); | |
| } | |
| @SuppressWarnings("deprecation") | |
| private void sub4109314(TimeZone PST) { | |
| GregorianCalendar testCal = (GregorianCalendar)Calendar.getInstance(); | |
| Object[] testData = { | |
| PST, new Date(98,Calendar.APRIL,4,22,0), new Date(98, Calendar.APRIL, 5,6,0), | |
| PST, new Date(98,Calendar.OCTOBER,24,22,0), new Date(98,Calendar.OCTOBER,25,6,0), | |
| }; | |
| boolean pass=true; | |
| for (int i=0; i<testData.length; i+=3) { | |
| testCal.setTimeZone((TimeZone) testData[i]); | |
| long t = ((Date)testData[i+1]).getTime(); | |
| Date end = (Date) testData[i+2]; | |
| while (t < end.getTime()) { | |
| testCal.setTime(new Date(t)); | |
| if (!checkCalendar314(testCal, (TimeZone) testData[i])) | |
| pass = false; | |
| t += 60*60*1000L; | |
| } | |
| } | |
| if (!pass) fail("Fail: TZ API inconsistent"); | |
| } | |
| boolean checkCalendar314(GregorianCalendar testCal, TimeZone testTZ) { | |
| // GregorianCalendar testCal = (GregorianCalendar)aCal.clone(); | |
| final int ONE_DAY = 24*60*60*1000; | |
| int tzOffset, tzRawOffset; | |
| Float tzOffsetFloat,tzRawOffsetFloat; | |
| // Here is where the user made an error. They were passing in the value of | |
| // the MILLSECOND field; you need to pass in the millis in the day in STANDARD | |
| // time. | |
| int millis = testCal.get(Calendar.MILLISECOND) + | |
| 1000 * (testCal.get(Calendar.SECOND) + | |
| 60 * (testCal.get(Calendar.MINUTE) + | |
| 60 * (testCal.get(Calendar.HOUR_OF_DAY)))) - | |
| testCal.get(Calendar.DST_OFFSET); | |
| /* Fix up millis to be in range. ASSUME THAT WE ARE NOT AT THE | |
| * BEGINNING OR END OF A MONTH. We must add this code because | |
| * getOffset() has been changed to be more strict about the parameters | |
| * it receives -- it turns out that this test was passing in illegal | |
| * values. */ | |
| int date = testCal.get(Calendar.DATE); | |
| int dow = testCal.get(Calendar.DAY_OF_WEEK); | |
| while (millis < 0) { | |
| millis += ONE_DAY; | |
| --date; | |
| dow = Calendar.SUNDAY + ((dow - Calendar.SUNDAY + 6) % 7); | |
| } | |
| while (millis >= ONE_DAY) { | |
| millis -= ONE_DAY; | |
| ++date; | |
| dow = Calendar.SUNDAY + ((dow - Calendar.SUNDAY + 1) % 7); | |
| } | |
| tzOffset = testTZ.getOffset(testCal.get(Calendar.ERA), | |
| testCal.get(Calendar.YEAR), | |
| testCal.get(Calendar.MONTH), | |
| date, | |
| dow, | |
| millis); | |
| tzRawOffset = testTZ.getRawOffset(); | |
| tzOffsetFloat = new Float((float)tzOffset/(float)3600000); | |
| tzRawOffsetFloat = new Float((float)tzRawOffset/(float)3600000); | |
| Date testDate = testCal.getTime(); | |
| boolean inDaylightTime = testTZ.inDaylightTime(testDate); | |
| SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm"); | |
| sdf.setCalendar(testCal); | |
| String inDaylightTimeString; | |
| boolean passed; | |
| if (inDaylightTime) | |
| { | |
| inDaylightTimeString = " DST "; | |
| passed = (tzOffset == (tzRawOffset + 3600000)); | |
| } | |
| else | |
| { | |
| inDaylightTimeString = " "; | |
| passed = (tzOffset == tzRawOffset); | |
| } | |
| String output = testTZ.getID() + " " + sdf.format(testDate) + | |
| " Offset(" + tzOffsetFloat + ")" + | |
| " RawOffset(" + tzRawOffsetFloat + ")" + | |
| " " + millis/(float)3600000 + " " + | |
| inDaylightTimeString; | |
| if (passed) | |
| output += " "; | |
| else | |
| output += "ERROR"; | |
| if (passed) System.out.println(output); else fail(output); | |
| return passed; | |
| } | |
| /** | |
| * CANNOT REPRODUDE | |
| * | |
| * Yet another _alleged_ bug in TimeZone.getOffset(), a method that never | |
| * should have been made public. It's simply too hard to use correctly. | |
| * | |
| * The original test code failed to do the following: | |
| * (1) Call Calendar.setTime() before getting the fields! | |
| * (2) Use the right millis (as usual) for getOffset(); they were passing | |
| * in the MILLIS field, instead of the STANDARD MILLIS IN DAY. | |
| * When you fix these two problems, the test passes, as expected. | |
| */ | |
| @Test | |
| public void Test4126678() { | |
| Locale locale = Locale.getDefault(); | |
| if (!TestUtils.usesGregorianCalendar(locale)) { | |
| System.out.println("Skipping this test because locale is " + locale); | |
| return; | |
| } | |
| // Note: this test depends on the PST time zone. | |
| TimeZone initialZone = TimeZone.getDefault(); | |
| // test both SimpleTimeZone and ZoneInfo objects. | |
| // @since 1.4 | |
| sub4126678(getPST()); | |
| sub4126678(TimeZone.getTimeZone("America/Los_Angeles")); | |
| // restore the initial time zone so that this test case | |
| // doesn't affect the others. | |
| TimeZone.setDefault(initialZone); | |
| } | |
| @SuppressWarnings("deprecation") | |
| private void sub4126678(TimeZone tz) { | |
| Calendar cal = Calendar.getInstance(); | |
| TimeZone.setDefault(tz); | |
| cal.setTimeZone(tz); | |
| Date dt = new Date(1998-1900, Calendar.APRIL, 5, 10, 0); | |
| // the dt value is local time in PST. | |
| if (!tz.inDaylightTime(dt)) | |
| fail("We're not in Daylight Savings Time and we should be.\n"); | |
| cal.setTime(dt); | |
| int era = cal.get(Calendar.ERA); | |
| int year = cal.get(Calendar.YEAR); | |
| int month = cal.get(Calendar.MONTH); | |
| int day = cal.get(Calendar.DATE); | |
| int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); | |
| int millis = cal.get(Calendar.MILLISECOND) + | |
| (cal.get(Calendar.SECOND) + | |
| (cal.get(Calendar.MINUTE) + | |
| (cal.get(Calendar.HOUR) * 60) * 60) * 1000) - | |
| cal.get(Calendar.DST_OFFSET); | |
| long offset = tz.getOffset(era, year, month, day, dayOfWeek, millis); | |
| long raw_offset = tz.getRawOffset(); | |
| if (offset == raw_offset) { | |
| fail("Offsets should not match when in DST"); | |
| } | |
| } | |
| /** | |
| * TimeZone.getAvailableIDs(int) throws exception for certain values, | |
| * due to a faulty constant in TimeZone.java. | |
| */ | |
| @Test | |
| public void Test4151406() { | |
| int max = 0; | |
| for (int h=-28; h<=30; ++h) { | |
| // h is in half-hours from GMT; rawoffset is in millis | |
| int rawoffset = h * 1800000; | |
| int hh = (h<0) ? -h : h; | |
| String hname = ((h<0) ? "GMT-" : "GMT+") + | |
| ((hh/2 < 10) ? "0" : "") + | |
| (hh/2) + ':' + | |
| ((hh%2==0) ? "00" : "30"); | |
| try { | |
| String[] ids = TimeZone.getAvailableIDs(rawoffset); | |
| if (ids.length > max) max = ids.length; | |
| System.out.println(hname + ' ' + ids.length + | |
| ((ids.length > 0) ? (" e.g. " + ids[0]) : "")); | |
| } catch (Exception e) { | |
| fail(hname + ' ' + "Fail: " + e); | |
| } | |
| } | |
| System.out.println("Maximum zones per offset = " + max); | |
| } | |
| @Test | |
| public void Test4151429() { | |
| try { | |
| TimeZone tz = TimeZone.getTimeZone("GMT"); | |
| String name = tz.getDisplayName(true, Integer.MAX_VALUE, | |
| Locale.getDefault()); | |
| fail("IllegalArgumentException not thrown by TimeZone.getDisplayName()"); | |
| } catch(IllegalArgumentException e) {} | |
| } | |
| /** | |
| * SimpleTimeZone accepts illegal DST savings values. These values | |
| * must be non-zero. There is no upper limit at this time. | |
| */ | |
| @Test | |
| public void Test4154525() { | |
| final int GOOD = 1, BAD = 0; | |
| int[] DATA = { | |
| 1, GOOD, | |
| 0, BAD, | |
| -1, BAD, | |
| 60*60*1000, GOOD, | |
| Integer.MIN_VALUE, BAD, | |
| // Integer.MAX_VALUE, ?, // no upper limit on DST savings at this time | |
| }; | |
| for (int i=0; i<DATA.length; i+=2) { | |
| int savings = DATA[i]; | |
| boolean valid = DATA[i+1] == GOOD; | |
| String method = null; | |
| for (int j=0; j<2; ++j) { | |
| try { | |
| switch (j) { | |
| case 0: | |
| method = "constructor"; | |
| SimpleTimeZone z = new SimpleTimeZone(0, "id", | |
| Calendar.JANUARY, 1, 0, 0, | |
| Calendar.MARCH, 1, 0, 0, | |
| savings); // <- what we're interested in | |
| break; | |
| case 1: | |
| method = "setDSTSavings()"; | |
| z = new SimpleTimeZone(0, "GMT"); | |
| z.setDSTSavings(savings); | |
| break; | |
| } | |
| if (valid) { | |
| System.out.println("Pass: DST savings of " + savings + " accepted by " + method); | |
| } else { | |
| fail("Fail: DST savings of " + savings + " accepted by " + method); | |
| } | |
| } catch (IllegalArgumentException e) { | |
| if (valid) { | |
| fail("Fail: DST savings of " + savings + " to " + method + " gave " + e); | |
| } else { | |
| System.out.println("Pass: DST savings of " + savings + " to " + method + " gave " + e); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| /** | |
| * SimpleTimeZone.hasSameRules() doesn't work for zones with no DST | |
| * and different DST parameters. | |
| */ | |
| @Test | |
| public void Test4154537() { | |
| // tz1 and tz2 have no DST and different rule parameters | |
| SimpleTimeZone tz1 = new SimpleTimeZone(0, "1", 0, 0, 0, 0, 2, 0, 0, 0); | |
| SimpleTimeZone tz2 = new SimpleTimeZone(0, "2", 1, 0, 0, 0, 3, 0, 0, 0); | |
| // tza and tzA have the same rule params | |
| SimpleTimeZone tza = new SimpleTimeZone(0, "a", 0, 1, 0, 0, 3, 2, 0, 0); | |
| SimpleTimeZone tzA = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 3, 2, 0, 0); | |
| // tzb differs from tza | |
| SimpleTimeZone tzb = new SimpleTimeZone(0, "b", 0, 1, 0, 0, 3, 1, 0, 0); | |
| if (tz1.useDaylightTime() || tz2.useDaylightTime() || | |
| !tza.useDaylightTime() || !tzA.useDaylightTime() || | |
| !tzb.useDaylightTime()) { | |
| fail("Test is broken -- rewrite it"); | |
| } | |
| if (!tza.hasSameRules(tzA) || tza.hasSameRules(tzb)) { | |
| fail("Fail: hasSameRules() broken for zones with rules"); | |
| } | |
| if (!tz1.hasSameRules(tz2)) { | |
| fail("Fail: hasSameRules() returns false for zones without rules"); | |
| fail("zone 1 = " + tz1); | |
| fail("zone 2 = " + tz2); | |
| } | |
| } | |
| /** | |
| * SimpleTimeZone constructors, setStartRule(), and setEndRule() don't | |
| * check for out-of-range arguments. | |
| */ | |
| @Test | |
| public void Test4154542() { | |
| final int GOOD = 1; | |
| final int BAD = 0; | |
| final int GOOD_MONTH = Calendar.JANUARY; | |
| final int GOOD_DAY = 1; | |
| final int GOOD_DAY_OF_WEEK = Calendar.SUNDAY; | |
| final int GOOD_TIME = 0; | |
| int[] DATA = { | |
| GOOD, Integer.MIN_VALUE, 0, Integer.MAX_VALUE, Integer.MIN_VALUE, | |
| GOOD, Calendar.JANUARY, -5, Calendar.SUNDAY, 0, | |
| GOOD, Calendar.DECEMBER, 5, Calendar.SATURDAY, 24*60*60*1000-1, | |
| GOOD, Calendar.DECEMBER, 5, Calendar.SATURDAY, 24*60*60*1000, | |
| BAD, Calendar.DECEMBER, 5, Calendar.SATURDAY, 24*60*60*1000+1, | |
| BAD, Calendar.DECEMBER, 5, Calendar.SATURDAY, -1, | |
| BAD, Calendar.JANUARY, -6, Calendar.SUNDAY, 0, | |
| BAD, Calendar.DECEMBER, 6, Calendar.SATURDAY, 24*60*60*1000, | |
| GOOD, Calendar.DECEMBER, 1, 0, 0, | |
| GOOD, Calendar.DECEMBER, 31, 0, 0, | |
| BAD, Calendar.APRIL, 31, 0, 0, | |
| BAD, Calendar.DECEMBER, 32, 0, 0, | |
| BAD, Calendar.JANUARY-1, 1, Calendar.SUNDAY, 0, | |
| BAD, Calendar.DECEMBER+1, 1, Calendar.SUNDAY, 0, | |
| GOOD, Calendar.DECEMBER, 31, -Calendar.SUNDAY, 0, | |
| GOOD, Calendar.DECEMBER, 31, -Calendar.SATURDAY, 0, | |
| BAD, Calendar.DECEMBER, 32, -Calendar.SATURDAY, 0, | |
| BAD, Calendar.DECEMBER, -32, -Calendar.SATURDAY, 0, | |
| BAD, Calendar.DECEMBER, 31, -Calendar.SATURDAY-1, 0, | |
| }; | |
| SimpleTimeZone zone = new SimpleTimeZone(0, "Z"); | |
| for (int i=0; i<DATA.length; i+=5) { | |
| boolean shouldBeGood = (DATA[i] == GOOD); | |
| int month = DATA[i+1]; | |
| int day = DATA[i+2]; | |
| int dayOfWeek = DATA[i+3]; | |
| int time = DATA[i+4]; | |
| Exception ex = null; | |
| try { | |
| zone.setStartRule(month, day, dayOfWeek, time); | |
| } catch (IllegalArgumentException e) { | |
| ex = e; | |
| } | |
| if ((ex == null) != shouldBeGood) { | |
| fail("setStartRule(month=" + month + ", day=" + day + | |
| ", dayOfWeek=" + dayOfWeek + ", time=" + time + | |
| (shouldBeGood ? (") should work but throws " + ex) | |
| : ") should fail but doesn't")); | |
| } | |
| ex = null; | |
| try { | |
| zone.setEndRule(month, day, dayOfWeek, time); | |
| } catch (IllegalArgumentException e) { | |
| ex = e; | |
| } | |
| if ((ex == null) != shouldBeGood) { | |
| fail("setEndRule(month=" + month + ", day=" + day + | |
| ", dayOfWeek=" + dayOfWeek + ", time=" + time + | |
| (shouldBeGood ? (") should work but throws " + ex) | |
| : ") should fail but doesn't")); | |
| } | |
| ex = null; | |
| try { | |
| SimpleTimeZone temp = new SimpleTimeZone(0, "Z", | |
| month, day, dayOfWeek, time, | |
| GOOD_MONTH, GOOD_DAY, GOOD_DAY_OF_WEEK, GOOD_TIME); | |
| } catch (IllegalArgumentException e) { | |
| ex = e; | |
| } | |
| if ((ex == null) != shouldBeGood) { | |
| fail("SimpleTimeZone(month=" + month + ", day=" + day + | |
| ", dayOfWeek=" + dayOfWeek + ", time=" + time + | |
| (shouldBeGood ? (", <end>) should work but throws " + ex) | |
| : ", <end>) should fail but doesn't")); | |
| } | |
| ex = null; | |
| try { | |
| SimpleTimeZone temp = new SimpleTimeZone(0, "Z", | |
| GOOD_MONTH, GOOD_DAY, GOOD_DAY_OF_WEEK, GOOD_TIME, | |
| month, day, dayOfWeek, time); | |
| } catch (IllegalArgumentException e) { | |
| ex = e; | |
| } | |
| if ((ex == null) != shouldBeGood) { | |
| fail("SimpleTimeZone(<start>, month=" + month + ", day=" + day + | |
| ", dayOfWeek=" + dayOfWeek + ", time=" + time + | |
| (shouldBeGood ? (") should work but throws " + ex) | |
| : ") should fail but doesn't")); | |
| } | |
| } | |
| } | |
| /** | |
| * SimpleTimeZone.getOffset accepts illegal arguments. | |
| */ | |
| @Test | |
| public void Test4154650() { | |
| final int GOOD=1, BAD=0; | |
| final int GOOD_ERA=GregorianCalendar.AD, GOOD_YEAR=1998, GOOD_MONTH=Calendar.AUGUST; | |
| final int GOOD_DAY=2, GOOD_DOW=Calendar.SUNDAY, GOOD_TIME=16*3600000; | |
| int[] DATA = { | |
| GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
| GOOD, GregorianCalendar.BC, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
| GOOD, GregorianCalendar.AD, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
| BAD, GregorianCalendar.BC-1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
| BAD, GregorianCalendar.AD+1, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
| GOOD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
| GOOD, GOOD_ERA, GOOD_YEAR, Calendar.DECEMBER, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
| BAD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY-1, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
| BAD, GOOD_ERA, GOOD_YEAR, Calendar.DECEMBER+1, GOOD_DAY, GOOD_DOW, GOOD_TIME, | |
| GOOD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, 1, GOOD_DOW, GOOD_TIME, | |
| GOOD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, 31, GOOD_DOW, GOOD_TIME, | |
| BAD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, 0, GOOD_DOW, GOOD_TIME, | |
| BAD, GOOD_ERA, GOOD_YEAR, Calendar.JANUARY, 32, GOOD_DOW, GOOD_TIME, | |
| GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, Calendar.SUNDAY, GOOD_TIME, | |
| GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, Calendar.SATURDAY, GOOD_TIME, | |
| BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, Calendar.SUNDAY-1, GOOD_TIME, | |
| BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, Calendar.SATURDAY+1, GOOD_TIME, | |
| GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 0, | |
| GOOD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000-1, | |
| BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, -1, | |
| BAD, GOOD_ERA, GOOD_YEAR, GOOD_MONTH, GOOD_DAY, GOOD_DOW, 24*3600000, | |
| }; | |
| TimeZone tz = TimeZone.getDefault(); | |
| for (int i=0; i<DATA.length; i+=7) { | |
| boolean good = DATA[i] == GOOD; | |
| IllegalArgumentException e = null; | |
| try { | |
| int offset = tz.getOffset(DATA[i+1], DATA[i+2], DATA[i+3], | |
| DATA[i+4], DATA[i+5], DATA[i+6]); | |
| } catch (IllegalArgumentException ex) { | |
| e = ex; | |
| } | |
| if (good != (e == null)) { | |
| fail("Fail: getOffset(" + | |
| DATA[i+1] + ", " + DATA[i+2] + ", " + DATA[i+3] + ", " + | |
| DATA[i+4] + ", " + DATA[i+5] + ", " + DATA[i+6] + | |
| (good ? (") threw " + e) : ") accepts invalid args")); | |
| } | |
| } | |
| } | |
| /** | |
| * TimeZone constructors allow null IDs. | |
| */ | |
| @Test | |
| public void Test4159922() { | |
| TimeZone z = null; | |
| // TimeZone API. Only hasSameRules() and setDefault() should | |
| // allow null. | |
| try { | |
| z = TimeZone.getTimeZone((String)null); | |
| fail("FAIL: Null allowed in getTimeZone"); | |
| } catch (NullPointerException e) {} | |
| z = TimeZone.getTimeZone("GMT"); | |
| try { | |
| z.getDisplayName(false, TimeZone.SHORT, null); | |
| fail("FAIL: Null allowed in getDisplayName(3)"); | |
| } catch (NullPointerException e) {} | |
| try { | |
| z.getDisplayName(null); | |
| fail("FAIL: Null allowed in getDisplayName(1)"); | |
| } catch (NullPointerException e) {} | |
| try { | |
| if (z.hasSameRules(null)) { | |
| fail("FAIL: hasSameRules returned true"); | |
| } | |
| } catch (NullPointerException e) { | |
| fail("FAIL: Null NOT allowed in hasSameRules"); | |
| } | |
| try { | |
| z.inDaylightTime(null); | |
| fail("FAIL: Null allowed in inDaylightTime"); | |
| } catch (NullPointerException e) {} | |
| try { | |
| z.setID(null); | |
| fail("FAIL: Null allowed in setID"); | |
| } catch (NullPointerException e) {} | |
| TimeZone save = TimeZone.getDefault(); | |
| try { | |
| TimeZone.setDefault(null); | |
| } catch (NullPointerException e) { | |
| fail("FAIL: Null NOT allowed in setDefault"); | |
| } finally { | |
| TimeZone.setDefault(save); | |
| } | |
| // SimpleTimeZone API | |
| SimpleTimeZone s = null; | |
| try { | |
| s = new SimpleTimeZone(0, null); | |
| fail("FAIL: Null allowed in SimpleTimeZone(2)"); | |
| } catch (NullPointerException e) {} | |
| try { | |
| s = new SimpleTimeZone(0, null, 0, 1, 0, 0, 0, 1, 0, 0); | |
| fail("FAIL: Null allowed in SimpleTimeZone(10)"); | |
| } catch (NullPointerException e) {} | |
| try { | |
| s = new SimpleTimeZone(0, null, 0, 1, 0, 0, 0, 1, 0, 0, 1000); | |
| fail("FAIL: Null allowed in SimpleTimeZone(11)"); | |
| } catch (NullPointerException e) {} | |
| } | |
| /** | |
| * TimeZone broken at midnight. The TimeZone code fails to handle | |
| * transitions at midnight correctly. | |
| */ | |
| @SuppressWarnings("deprecation") | |
| @Test | |
| public void Test4162593() { | |
| SimpleDateFormat fmt = new SimpleDateFormat("z", Locale.US); | |
| final int ONE_HOUR = 60*60*1000; | |
| TimeZone initialZone = TimeZone.getDefault(); | |
| SimpleTimeZone asuncion = new SimpleTimeZone(-4*ONE_HOUR, "America/Asuncion" /*PY%sT*/, | |
| Calendar.OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, | |
| Calendar.MARCH, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR); | |
| /* Zone | |
| * Starting time | |
| * Transition expected between start+1H and start+2H | |
| */ | |
| Object[] DATA = { | |
| new SimpleTimeZone(2*ONE_HOUR, "Asia/Damascus" /*EE%sT*/, | |
| Calendar.APRIL, 1, 0 /*DOM*/, 0*ONE_HOUR, | |
| Calendar.OCTOBER, 1, 0 /*DOM*/, 0*ONE_HOUR, 1*ONE_HOUR), | |
| new int[] {98, Calendar.SEPTEMBER, 30, 22, 0}, | |
| Boolean.TRUE, | |
| asuncion, | |
| new int[] {100, Calendar.FEBRUARY, 28, 22, 0}, | |
| Boolean.FALSE, | |
| asuncion, | |
| new int[] {100, Calendar.FEBRUARY, 29, 22, 0}, | |
| Boolean.TRUE, | |
| }; | |
| String[] zone = new String[4]; | |
| try { | |
| for (int j=0; j<DATA.length; j+=3) { | |
| TimeZone tz = (TimeZone)DATA[j]; | |
| TimeZone.setDefault(tz); | |
| fmt.setTimeZone(tz); | |
| // Must construct the Date object AFTER setting the default zone | |
| int[] p = (int[])DATA[j+1]; | |
| Date d = new Date(p[0], p[1], p[2], p[3], p[4]); | |
| boolean transitionExpected = ((Boolean)DATA[j+2]).booleanValue(); | |
| System.out.println(tz.getID() + ":"); | |
| for (int i=0; i<4; ++i) { | |
| zone[i] = fmt.format(d); | |
| System.out.println("" + i + ": " + d); | |
| d = new Date(d.getTime() + ONE_HOUR); | |
| } | |
| if (zone[0].equals(zone[1]) && | |
| (zone[1].equals(zone[2]) != transitionExpected) && | |
| zone[2].equals(zone[3])) { | |
| System.out.println("Ok: transition " + transitionExpected); | |
| } else { | |
| fail("Fail: boundary transition incorrect"); | |
| } | |
| } | |
| } | |
| finally { | |
| // restore the initial time zone so that this test case | |
| // doesn't affect the others. | |
| TimeZone.setDefault(initialZone); | |
| } | |
| } | |
| /** | |
| * TimeZone broken in last hour of year | |
| */ | |
| @Test | |
| public void Test4173604() { | |
| // test both SimpleTimeZone and ZoneInfo objects. | |
| // @since 1.4 | |
| sub4173604(getPST()); | |
| sub4173604(TimeZone.getTimeZone("America/Los_Angeles")); | |
| } | |
| private void sub4173604(TimeZone pst) { | |
| int o22 = pst.getOffset(1, 1998, 11, 31, Calendar.THURSDAY, 22*60*60*1000); | |
| int o23 = pst.getOffset(1, 1998, 11, 31, Calendar.THURSDAY, 23*60*60*1000); | |
| int o00 = pst.getOffset(1, 1999, 0, 1, Calendar.FRIDAY, 0); | |
| if (o22 != o23 || o22 != o00) { | |
| fail("Offsets should be the same (for PST), but got: " + | |
| "12/31 22:00 " + o22 + | |
| ", 12/31 23:00 " + o23 + | |
| ", 01/01 00:00 " + o00); | |
| } | |
| GregorianCalendar cal = new GregorianCalendar(); | |
| cal.setTimeZone(pst); | |
| cal.clear(); | |
| cal.set(1998, Calendar.JANUARY, 1); | |
| int lastDST = cal.get(Calendar.DST_OFFSET); | |
| int transitions = 0; | |
| int delta = 5; | |
| while (cal.get(Calendar.YEAR) < 2000) { | |
| cal.add(Calendar.MINUTE, delta); | |
| if (cal.get(Calendar.DST_OFFSET) != lastDST) { | |
| ++transitions; | |
| Calendar t = (Calendar)cal.clone(); | |
| t.add(Calendar.MINUTE, -delta); | |
| System.out.println(t.getTime() + " " + t.get(Calendar.DST_OFFSET)); | |
| System.out.println(cal.getTime() + " " + (lastDST=cal.get(Calendar.DST_OFFSET))); | |
| } | |
| } | |
| if (transitions != 4) { | |
| fail("Saw " + transitions + " transitions; should have seen 4"); | |
| } | |
| } | |
| /** | |
| * getDisplayName doesn't work with unusual savings/offsets. | |
| */ | |
| @SuppressWarnings("deprecation") | |
| @Test | |
| public void Test4176686() { | |
| // Construct a zone that does not observe DST but | |
| // that does have a DST savings (which should be ignored). | |
| int offset = 90 * 60000; // 1:30 | |
| SimpleTimeZone z1 = new SimpleTimeZone(offset, "_std_zone_"); | |
| z1.setDSTSavings(45 * 60000); // 0:45 | |
| // Construct a zone that observes DST for the first 6 months. | |
| SimpleTimeZone z2 = new SimpleTimeZone(offset, "_dst_zone_"); | |
| z2.setDSTSavings(45 * 60000); // 0:45 | |
| z2.setStartRule(Calendar.JANUARY, 1, 0); | |
| z2.setEndRule(Calendar.JULY, 1, 0); | |
| // Also check DateFormat | |
| DateFormat fmt1 = new SimpleDateFormat("z"); | |
| fmt1.setTimeZone(z1); // Format uses standard zone | |
| DateFormat fmt2 = new SimpleDateFormat("z"); | |
| fmt2.setTimeZone(z2); // Format uses DST zone | |
| Date dst = new Date(1970-1900, Calendar.FEBRUARY, 1); // Time in DST | |
| Date std = new Date(1970-1900, Calendar.AUGUST, 1); // Time in standard | |
| // Description, Result, Expected Result | |
| String[] DATA = { | |
| "getDisplayName(false, SHORT)/std zone", | |
| z1.getDisplayName(false, TimeZone.SHORT), "GMT+01:30", | |
| "getDisplayName(false, LONG)/std zone", | |
| z1.getDisplayName(false, TimeZone.LONG ), "GMT+01:30", | |
| "getDisplayName(true, SHORT)/std zone", | |
| z1.getDisplayName(true, TimeZone.SHORT), "GMT+01:30", | |
| "getDisplayName(true, LONG)/std zone", | |
| z1.getDisplayName(true, TimeZone.LONG ), "GMT+01:30", | |
| "getDisplayName(false, SHORT)/dst zone", | |
| z2.getDisplayName(false, TimeZone.SHORT), "GMT+01:30", | |
| "getDisplayName(false, LONG)/dst zone", | |
| z2.getDisplayName(false, TimeZone.LONG ), "GMT+01:30", | |
| "getDisplayName(true, SHORT)/dst zone", | |
| z2.getDisplayName(true, TimeZone.SHORT), "GMT+02:15", | |
| "getDisplayName(true, LONG)/dst zone", | |
| z2.getDisplayName(true, TimeZone.LONG ), "GMT+02:15", | |
| "DateFormat.format(std)/std zone", fmt1.format(std), "GMT+01:30", | |
| "DateFormat.format(dst)/std zone", fmt1.format(dst), "GMT+01:30", | |
| "DateFormat.format(std)/dst zone", fmt2.format(std), "GMT+01:30", | |
| "DateFormat.format(dst)/dst zone", fmt2.format(dst), "GMT+02:15", | |
| }; | |
| for (int i=0; i<DATA.length; i+=3) { | |
| if (!DATA[i+1].equals(DATA[i+2])) { | |
| fail("FAIL: " + DATA[i] + " -> " + DATA[i+1] + ", exp " + DATA[i+2]); | |
| } | |
| } | |
| } | |
| /** | |
| * SimpleTimeZone allows invalid DOM values. | |
| */ | |
| @Test | |
| public void Test4184229() { | |
| SimpleTimeZone zone = null; | |
| try { | |
| zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0); | |
| fail("Failed. No exception has been thrown for DOM -1 startDay"); | |
| } catch(IllegalArgumentException e) { | |
| System.out.println("(a) " + e.getMessage()); | |
| } | |
| try { | |
| zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0); | |
| fail("Failed. No exception has been thrown for DOM -1 endDay"); | |
| } catch(IllegalArgumentException e) { | |
| System.out.println("(b) " + e.getMessage()); | |
| } | |
| try { | |
| zone = new SimpleTimeZone(0, "A", 0, -1, 0, 0, 0, 0, 0, 0, 1000); | |
| fail("Failed. No exception has been thrown for DOM -1 startDay +savings"); | |
| } catch(IllegalArgumentException e) { | |
| System.out.println("(c) " + e.getMessage()); | |
| } | |
| try { | |
| zone = new SimpleTimeZone(0, "A", 0, 0, 0, 0, 0, -1, 0, 0, 1000); | |
| fail("Failed. No exception has been thrown for DOM -1 endDay +savings"); | |
| } catch(IllegalArgumentException e) { | |
| System.out.println("(d) " + e.getMessage()); | |
| } | |
| // Make a valid constructor call for subsequent tests. | |
| zone = new SimpleTimeZone(0, "A", 0, 1, 0, 0, 0, 1, 0, 0); | |
| try { | |
| zone.setStartRule(0, -1, 0, 0); | |
| fail("Failed. No exception has been thrown for DOM -1 setStartRule +savings"); | |
| } catch(IllegalArgumentException e) { | |
| System.out.println("(e) " + e.getMessage()); | |
| } | |
| try { | |
| zone.setStartRule(0, -1, 0); | |
| fail("Failed. No exception has been thrown for DOM -1 setStartRule"); | |
| } catch(IllegalArgumentException e) { | |
| System.out.println("(f) " + e.getMessage()); | |
| } | |
| try { | |
| zone.setEndRule(0, -1, 0, 0); | |
| fail("Failed. No exception has been thrown for DOM -1 setEndRule +savings"); | |
| } catch(IllegalArgumentException e) { | |
| System.out.println("(g) " + e.getMessage()); | |
| } | |
| try { | |
| zone.setEndRule(0, -1, 0); | |
| fail("Failed. No exception has been thrown for DOM -1 setEndRule"); | |
| } catch(IllegalArgumentException e) { | |
| System.out.println("(h) " + e.getMessage()); | |
| } | |
| } | |
| /** | |
| * SimpleTimeZone.getOffset() throws IllegalArgumentException when to get | |
| * of 2/29/1996 (leap day). | |
| */ | |
| @Test | |
| public void Test4208960 () { | |
| // test both SimpleTimeZone and ZoneInfo objects. | |
| // @since 1.4 | |
| sub4208960(getPST()); | |
| sub4208960(TimeZone.getTimeZone("America/Los_Angeles")); | |
| } | |
| private void sub4208960(TimeZone tz) { | |
| try { | |
| int offset = tz.getOffset(GregorianCalendar.AD, 1996, Calendar.FEBRUARY, 29, | |
| Calendar.THURSDAY, 0); | |
| } catch (IllegalArgumentException e) { | |
| fail("FAILED: to get TimeZone.getOffset(2/29/96)"); | |
| } | |
| try { | |
| int offset = tz.getOffset(GregorianCalendar.AD, 1997, Calendar.FEBRUARY, 29, | |
| Calendar.THURSDAY, 0); | |
| fail("FAILED: TimeZone.getOffset(2/29/97) expected to throw Exception."); | |
| } catch (IllegalArgumentException e) { | |
| System.out.println("got IllegalArgumentException"); | |
| } | |
| } | |
| /** | |
| * 4966229: java.util.Date methods may works incorrect. | |
| * sun.util.calendar.ZoneInfo doesn't clone properly. | |
| */ | |
| @SuppressWarnings("deprecation") | |
| @Test | |
| public void Test4966229() { | |
| TimeZone savedTZ = TimeZone.getDefault(); | |
| try { | |
| TimeZone.setDefault(TimeZone.getTimeZone("GMT")); | |
| Date d = new Date(2100-1900, 5, 1); // specify year >2037 | |
| TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles"); | |
| Calendar cal = new GregorianCalendar(tz); | |
| cal.setTime(d); | |
| // Change the raw offset in tz | |
| int offset = tz.getRawOffset(); | |
| tz.setRawOffset(0); | |
| TimeZone tz2 = (TimeZone) tz.clone(); | |
| Calendar cal2 = new GregorianCalendar(tz2); | |
| cal2.setTime(d); | |
| int expectedHourOfDay = cal2.get(cal.HOUR_OF_DAY); | |
| // Restore the GMT offset in tz which shouldn't affect tz2 | |
| tz.setRawOffset(offset); | |
| cal2.setTime(d); | |
| int hourOfDay = cal2.get(cal.HOUR_OF_DAY); | |
| if (hourOfDay != expectedHourOfDay) { | |
| fail("wrong hour of day: got: " + hourOfDay | |
| + ", expected: " + expectedHourOfDay); | |
| } | |
| } finally { | |
| TimeZone.setDefault(savedTZ); | |
| } | |
| } | |
| /** | |
| * 6433179: (tz) Incorrect DST end for America/Winnipeg and Canada/Central in 2038+ | |
| */ | |
| @Test | |
| public void Test6433179() { | |
| // Use the old America/Winnipeg rule for testing. Note that | |
| // startMode is WALL_TIME for testing. It's actually | |
| // STANDARD_TIME, though. | |
| //Rule Winn 1966 2005 - Oct lastSun 2:00s 0 S | |
| //Rule Winn 1987 2005 - Apr Sun>=1 2:00s 1:00 D | |
| TimeZone tz = new SimpleTimeZone(-6*ONE_HOUR, "America/Winnipeg", | |
| Calendar.APRIL, 1, -Calendar.SUNDAY, 2*ONE_HOUR, SimpleTimeZone.WALL_TIME, | |
| Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*ONE_HOUR, SimpleTimeZone.STANDARD_TIME, | |
| 1*ONE_HOUR); | |
| Calendar cal = Calendar.getInstance(tz, Locale.US); | |
| cal.clear(); | |
| cal.set(2039, Calendar.OCTOBER, 1); | |
| cal.getTime(); | |
| cal.set(cal.DAY_OF_WEEK, cal.SUNDAY); | |
| cal.set(cal.DAY_OF_WEEK_IN_MONTH, -1); | |
| cal.add(Calendar.HOUR_OF_DAY, 2); | |
| if (cal.get(cal.DST_OFFSET) == 0) { | |
| fail("Should still be in DST."); | |
| } | |
| } | |
| private static final int ONE_HOUR = 60 * 60 * 1000; | |
| /** | |
| * Returns an instance of SimpleTimeZone for | |
| * "PST". (TimeZone.getTimeZone() no longer returns a | |
| * SimpleTimeZone object.) | |
| * @since 1.4 | |
| */ | |
| private SimpleTimeZone getPST() { | |
| return new SimpleTimeZone(-8*ONE_HOUR, "PST", | |
| Calendar.APRIL, 1, -Calendar.SUNDAY, 2*ONE_HOUR, | |
| Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*ONE_HOUR, | |
| 1*ONE_HOUR); | |
| } | |
| } | |
| //eof |