undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2015, 2022, 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 8060126
* @summary Make sure that the tzdata version matches between the run-time and tests.
*/
import java.time.zone.ZoneRules;
import java.time.zone.ZoneRulesProvider;
import java.util.NavigableMap;
public class AssureTzdataVersion {
public static void main(String... args) throws Exception {
// get the tzdata version for the run-time
NavigableMap<String, ZoneRules> map;
map = ZoneRulesProvider.getVersions("America/Los_Angeles");
if (map.isEmpty()) {
throw new RuntimeException("Unknown runtime tzdata version");
}
String runtime = map.lastEntry().getKey();
// get the tzdata version for regression tests
String testdata = null;
try (TextFileReader textreader = new TextFileReader("VERSION")) {
testdata = textreader.getLine().substring("tzdata".length());
}
if (!testdata.equals(runtime)) {
throw new RuntimeException("tzdata versions don't match: run-time=" + runtime
+ ", tests=" + testdata);
}
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 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 8347955
* @summary Ensure underlying element equality of available tz ID methods
* @run junit AvailableIDsTest
*/
import org.junit.jupiter.api.Test;
import java.util.TimeZone;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
public class AvailableIDsTest {
// Validate the equality of the array and stream of available IDs
@Test
public void streamEqualsArrayTest() {
String[] tzs = TimeZone.getAvailableIDs();
assertArrayEquals(tzs, TimeZone.availableIDs().toArray(String[]::new),
"availableIDs() and getAvailableIDs() do not have the same elements");
}
// Validate the equality of the array and stream of available IDs
// when passed an offset. Tests various offsets.
@ParameterizedTest
@ValueSource(ints = {21600000, 25200000, 28800000}) // 6:00, 7:00, 8:00
public void streamEqualsArrayWithOffsetTest(int offset) {
String[] tzs = TimeZone.getAvailableIDs(offset);
assertArrayEquals(tzs, TimeZone.availableIDs(offset).toArray(String[]::new),
"availableIDs(int) and getAvailableIDs(int) do not have the same elements");
}
}

View file

@ -0,0 +1,230 @@
/*
* Copyright (c) 2001, 2024, 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 4322313
* @summary Make sure that new implementation of custom time zone
* support for TimeZone.getTimeZone() works correctly and the
* getDisplayName() methods are locale independent.
* @run junit Bug4322313
*/
import java.util.Locale;
import java.util.TimeZone;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class Bug4322313 {
private static final int MPM = 60 * 1000; /* Milliseconds per minute */
private static final Object[][] VALIDS = {
/* given ID rawOffset normalized ID */
{"GMT+00:00", 0, "GMT+00:00"},
{"GMT+3:04", 184 * MPM, "GMT+03:04"},
{"GMT+03:04", 184 * MPM, "GMT+03:04"},
{"GMT+13:42", 822 * MPM, "GMT+13:42"},
/* ISO-LATIN-1 digits */
{"GMT+\u0030\u0031:\u0032\u0033", 83 * MPM, "GMT+01:23"},
{"GMT+0", 0, "GMT+00:00"},
{"GMT+3", 180 * MPM, "GMT+03:00"},
{"GMT+13", 780 * MPM, "GMT+13:00"},
{"GMT+034", 34 * MPM, "GMT+00:34"},
{"GMT+1034", 634 * MPM, "GMT+10:34"},
{"GMT-00:00", 0, "GMT-00:00"},
{"GMT-3:04", -184 * MPM, "GMT-03:04"},
{"GMT-03:04", -184 * MPM, "GMT-03:04"},
{"GMT-13:42", -822 * MPM, "GMT-13:42"},
/* ISO-LATIN-1 digits */
{"GMT-\u0030\u0031:\u0032\u0033", -83 * MPM, "GMT-01:23"},
{"GMT-0", 0, "GMT-00:00"},
{"GMT-3", -180 * MPM, "GMT-03:00"},
{"GMT-13", -780 * MPM, "GMT-13:00"},
{"GMT-034", -34 * MPM, "GMT-00:34"},
{"GMT-1034", -634 * MPM, "GMT-10:34"},
};
private static final String[] INVALIDS = {
"GMT+5:8", "GMT+11:1", "GMT+23:60", "GMT+24:13",
"GMT+0a:0A", "GMT +13:42", "GMT+ 13:42", "GMT+13 :42",
"GMT+13: 42", "GMT+421:950", "GMT+-13:42", "GMT+!13:42",
"GMT+a", "GMT+24", "GMT+060", "GMT+3003",
"GMT+42195", "GMT+-1", "GMT+-15", " GMT",
"GMT-5:8", "GMT-11:1", "GMT-23:60", "GMT-24:13",
"GMT-0a:0A", "GMT -13:42", "GMT- 13:42", "GMT-13 :42",
"GMT-13: 42", "GMT-421:950", "GMT-+13:42", "GMT-#13:42",
"GMT-a", "GMT-24", "GMT-060", "GMT-2403",
"GMT-42195", "GMT-+1", "GMT-+15", "G M T",
"GMT+09:00 ",
};
@Test
void Test4322313() {
Locale savedLocale = Locale.getDefault();
TimeZone savedTimeZone = TimeZone.getDefault();
boolean err = false;
Locale[] locs = Locale.getAvailableLocales();
try {
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
for (int i = 0; i < locs.length; i++) {
Locale locale = locs[i];
Locale.setDefault(locale);
/* Okay case */
for (int k = 0; k < VALIDS.length; k++) {
TimeZone tz = TimeZone.getTimeZone((String)VALIDS[k][0]);
int offset;
if (!tz.getID().equals(VALIDS[k][2])) {
err = true;
System.err.println("\tFailed [Locale=" +
locale + ", \"" + VALIDS[k][0] +
"\"] Invalid TimeZone ID, expected:" +
VALIDS[k][2] + ", got:" + tz.getID() + ", " + tz);
} else {
System.out.println("\tPassed [Locale=" +
locale + ", \"" + VALIDS[k][0] +
"\"] Valid TimeZone ID, got:" + VALIDS[k][2]);
}
offset = tz.getRawOffset();
if (offset != (int)VALIDS[k][1]) {
err = true;
System.err.println("\tFailed [Locale=" +
locale + ", \"" + VALIDS[k][0] +
"\"] Invalid RawOffset, expected:" + VALIDS[k][1] +
", got:" + offset + ", " + tz);
} else {
System.out.println("\tPassed [Locale=" +
locale + ", \"" + VALIDS[k][0] +
"\"] Vaild RawOffset, got:" + offset);
}
offset = tz.getDSTSavings();
if (offset != 0) {
err = true;
System.err.println("\tFailed [Locale=" +
locale + ", \"" + VALIDS[k][0] +
"\"] DSTSavings should be zero, got:" + offset +
", " + tz);
} else {
System.out.println("\tPassed [Locale=" +
locale + ", \"" + VALIDS[k][0] +
"\"] DSTSavings is zero.");
}
}
/* Error case */
for (int k=0; k < INVALIDS.length; k++) {
TimeZone tz = TimeZone.getTimeZone(INVALIDS[k]);
int offset;
if (!tz.getID().equals("GMT")) {
err = true;
System.err.println("\tFailed [Locale=" +
locale + ", \"" + INVALIDS[k] +
"\"] Invalid TimeZone ID, expected:GMT, got:" +
tz.getID() + ", " + tz);
} else {
System.out.println("\tPassed [Locale=" +
locale + ", \"" + INVALIDS[k] +
"\"] Valid TimeZone ID, got:" + tz.getID());
}
offset = tz.getRawOffset();
if (offset != 0) {
err = true;
System.err.println("\tFailed [Locale=" +
locale + ", \"" + INVALIDS[k] +
"\"] RawOffset should be zero, got:" + offset +
", " + tz);
} else {
System.out.println("\tPassed [Locale=" +
locale + ", \"" + INVALIDS[k] +
"\"] RawOffset is zero.");
}
offset = tz.getDSTSavings();
if (offset != 0) {
err = true;
System.err.println("\tFailed [Locale=" +
locale + ", \"" + INVALIDS[k] +
"\"] DSTSavings should be zero, got:" + offset +
", " + tz);
} else {
System.out.println("\tPassed [Locale=" +
locale + ", \"" + INVALIDS[k] +
"\"] DSTSavings is zero.");
}
}
// getDisplayName() tests
{
String normalizedID = "GMT-08:00";
TimeZone tz = TimeZone.getTimeZone("GMT-8");
String s;
s = tz.getDisplayName(true, tz.LONG);
if (!normalizedID.equals(s)) {
err = true;
System.err.println("getDisplayName returned unexpected name: " + s +
" in " + locale);
}
s = tz.getDisplayName(true, tz.SHORT);
if (!normalizedID.equals(s)) {
err = true;
System.err.println("getDisplayName returned unexpected name: " + s +
" in " + locale);
}
s = tz.getDisplayName(false, tz.LONG);
if (!normalizedID.equals(s)) {
err = true;
System.err.println("getDisplayName returned unexpected name: " + s +
" in " + locale);
}
s = tz.getDisplayName(false, tz.SHORT);
if (!normalizedID.equals(s)) {
err = true;
System.err.println("getDisplayName returned unexpected name: " + s +
" in " + locale);
}
}
}
} finally {
Locale.setDefault(savedLocale);
TimeZone.setDefault(savedTimeZone);
}
if (err) {
fail("TimeZone.getTimeZone() test failed");
} else {
System.out.println("TimeZone.getTimeZone() test passed");
}
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2004, 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 5097350 8347841 8347955
* @summary Make sure that TimeZone.getTimeZone returns a clone of a cached TimeZone instance.
*/
import java.time.ZoneId;
import java.util.*;
import java.util.function.Predicate;
public class Bug5097350 {
public static void main(String[] args) {
String[] tzids = TimeZone.availableIDs()
.filter(Predicate.not(ZoneId.SHORT_IDS::containsKey))
.toArray(String[]::new);
List<String> ids = new ArrayList<>(tzids.length + 10);
ids.addAll(Arrays.asList(tzids));
// add some custom ids
ids.add("GMT+1");
ids.add("GMT-7:00");
ids.add("GMT+10:20");
ids.add("GMT-00:00");
ids.add("GMT+00:00");
for (String id : ids) {
test(id);
}
}
private static void test(String id) {
TimeZone tz1 = TimeZone.getTimeZone(id);
int offset1 = tz1.getRawOffset();
tz1.setRawOffset(offset1 + 13 * 60 * 60 * 1000);
TimeZone tz2 = TimeZone.getTimeZone(id);
if (tz1 == tz2) {
throw new RuntimeException("TimeZones are identical: " + id);
}
if (offset1 != tz2.getRawOffset()) {
throw new RuntimeException("Offset changed through aliasing: " + id);
}
}
}

View file

@ -0,0 +1,256 @@
/*
* Copyright (c) 2005, 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 6329116 6756569 6757131 6758988 6764308 6796489 6834474 6609737 6507067
* 7039469 7090843 7103108 7103405 7158483 8008577 8059206 8064560 8072042
* 8077685 8151876 8166875 8169191 8170316 8176044 8174269 8347841 8347955
* @summary Make sure that timezone short display names are identical to Olson's data.
* @run junit Bug6329116
*/
import java.io.*;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Predicate;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class Bug6329116 {
// Do not test all locales, as some locales have localized
// short names in CLDR. Test only for the US locale
// static Locale[] locales = Locale.getAvailableLocales();
static Locale[] locales = {Locale.US};
static String[] timezones = TimeZone.availableIDs()
.filter(Predicate.not(ZoneId.SHORT_IDS::containsKey))
.toArray(String[]::new);
@Test
public void bug6329116() throws IOException {
boolean err = false;
HashMap<String, String> aliasTable = new HashMap<>();
HashSet<String> timezoneTable = new HashSet<>();
for (String t : timezones) {
timezoneTable.add(t);
}
String line, key, value;
StringTokenizer st;
try (TextFileReader in = new TextFileReader("aliases.txt")) {
while ((line = in.readLine()) != null) {
st = new StringTokenizer(line);
st.nextToken();
key = st.nextToken();
value = st.nextToken();
if (!value.equals("ROC")) {
if (aliasTable.containsKey(key)) {
aliasTable.put(key, aliasTable.get(key) + " " + value);
} else {
aliasTable.put(key, value);
}
}
}
}
try (TextFileReader in = new TextFileReader("displaynames.txt")) {
String timezoneID, expected, expected_DST, got;
String[] aliases, tzs;
TimeZone tz;
while ((line = in.readLine()) != null) {
st = new StringTokenizer(line);
timezoneID = st.nextToken();
expected = st.nextToken();
if (st.hasMoreTokens()) {
expected_DST = st.nextToken();
} else {
expected_DST = null;
}
if (aliasTable.containsKey(timezoneID)) {
aliases = aliasTable.get(timezoneID).split(" ");
tzs = new String[1 + aliases.length];
System.arraycopy(aliases, 0, tzs, 1, aliases.length);
aliasTable.remove(timezoneID);
} else {
tzs = new String[1];
}
tzs[0] = timezoneID;
for (int j = 0; j < tzs.length; j++) {
if (ZoneId.SHORT_IDS.containsKey(tzs[j])) {
continue;
}
tz = TimeZone.getTimeZone(tzs[j]);
if (!tzs[j].equals(tz.getID())) {
System.err.println(tzs[j] + " may not be a valid Timezone ID and \"" + tz.getID() + "\" was returned. Please check it.");
err = true;
}
timezoneTable.remove(tzs[j]);
for (int i = 0; i < locales.length; i++) {
got = tz.getDisplayName(false, TimeZone.SHORT, locales[i]);
if (!expected.equals(got) &&
!expected.startsWith(got + "/") &&
!expected.endsWith("/" + got)) {
if (useLocalizedShortDisplayName(tz, locales[i], got, false)) {
/*
System.out.println(tzs[j] +
((j > 0) ? "(Alias of \"" + tzs[0] + "\")" : "") +
" seems to use a localized short display name" +
": original: " + expected +
": got: " + got + " for non-DST in " +
locales[i] + " locale.");
*/
} else {
System.err.println(tzs[j] +
((j > 0) ? "(Alias of \"" + tzs[0] + "\")" : "") +
": expected: " + expected +
": got: " + got + " for non-DST in " +
locales[i] + " locale.");
err = true;
}
}
got = tz.getDisplayName(true, TimeZone.SHORT, locales[i]);
if (expected_DST != null) {
if (!expected_DST.equals(got) &&
!expected_DST.startsWith(got + "/") &&
!expected_DST.endsWith("/" + got)) {
if (tzs[j].equals("Europe/London") &&
locales[i].equals(new Locale("en", "IE"))) {
continue;
} else if (useLocalizedShortDisplayName(tz, locales[i], got, true)) {
/*
System.out.println(tzs[j] +
((j > 0) ? "(Alias of \"" + tzs[0] + "\")" : "") +
" seems to use a localized short display name" +
": original: " + expected_DST +
": got: " + got + " for DST in " +
locales[i] + " locale.");
*/
continue;
}
System.err.println(tzs[j] +
((j > 0) ? "(Alias of \"" + tzs[0] + "\")" : "") +
": expected: " + expected_DST +
": got: " + got + " for DST in " +
locales[i] + " locale.");
err = true;
}
} else {
// Some timezones don't have DST display names in Olson's data,
// and we created them ourselves based on non-DST display names
// to prepare potential use in the future.
// Because there's no expected name, we don't judge if these
// DST display names are correct but just compare them with
// non-DST diplay names for checking with our eyes .
if (!expected.equals(got) &&
!expected.startsWith(got + "/") &&
!expected.endsWith("/" + got)) {
/*
System.out.println("## " + tzs[j] +
((j > 0) ? "(Alias of \"" + tzs[0] + "\")" : "") +
": expected: " + expected +
": got: " + got + " for DST in " +
locales[i] + " locale.");
*/
}
}
}
}
}
}
if (!timezoneTable.isEmpty()) {
System.out.println("# Timezone(s) valid in JRE but untested in this test program:");
Iterator<String> it = timezoneTable.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println();
}
if (!aliasTable.isEmpty()) {
System.out.println("# Timezone(s) exists in Olson's data as Link but unused in JRE:");
for (Map.Entry<String, String> entry : aliasTable.entrySet()) {
System.out.println(entry);
}
}
if (err) {
fail("At least one timezone display name is incorrect.");
}
}
static boolean useLocalizedShortDisplayName(TimeZone tz,
Locale locale,
String got,
boolean inDST) {
// if (locale.getLanguage().equals("de")) {
// String name = tz.getDisplayName(inDST, TimeZone.LONG, locale);
// if (inDST) {
// if (("Mitteleurop\u00e4ische Sommerzeit".equals(name) && "MESZ".equals(got)) ||
// ("Osteurop\u00e4ische Sommerzeit".equals(name) && "OESZ".equals(got)) ||
// ("Westeurop\u00e4ische Sommerzeit".equals(name) && "WESZ".equals(got))) {
// return true;
// }
// } else {
// if (("Mitteleurop\u00e4ische Zeit".equals(name) && "MEZ".equals(got)) ||
// ("Osteurop\u00e4ische Zeit".equals(name) && "OEZ".equals(got)) ||
// ("Westeurop\u00e4ische Zeit".equals(name) && "WEZ".equals(got))) {
// return true;
// }
// }
// } else if (locale.getLanguage().equals("zh") &&
// (locale.getCountry().equals("TW") || locale.getCountry().equals("HK"))) {
// String name = tz.getDisplayName(inDST, TimeZone.LONG, locale);
// if (inDST) {
// if (("\u53f0\u7063\u590f\u4ee4\u6642\u9593".equals(name) && "TDT".equals(got))) {
// return true;
// }
// } else {
// if (("\u53f0\u7063\u6a19\u6e96\u6642\u9593".equals(name) && "TST".equals(got))) {
// return true;
// }
// }
// }
// If we get a TimeZone with GMT+hh:mm format, we can ignore the offset value
if (tz.getDisplayName(Locale.ENGLISH).startsWith("GMT+") || tz.getDisplayName(Locale.ENGLISH).startsWith("GMT-")) {
return tz.getDisplayName().substring(0, 3).equals(got.substring(0, 3));
}
return false;
}
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2011, 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 6772689 8347841 8347955
* @summary Test for standard-to-daylight transitions at midnight:
* date stays on the given day.
*/
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.function.Predicate;
import static java.util.GregorianCalendar.*;
public class Bug6772689 {
private static final int BEGIN_YEAR = 2035;
private static final int END_YEAR = BEGIN_YEAR + 28;
public static void main(String[] args) {
TimeZone defaultTimeZone = TimeZone.getDefault();
int errors = 0;
Calendar cal = new GregorianCalendar(BEGIN_YEAR, MARCH, 1);
String[] tzids = TimeZone.availableIDs()
.filter(Predicate.not(ZoneId.SHORT_IDS::containsKey))
.toArray(String[]::new);
try {
for (String id : tzids) {
TimeZone tz = TimeZone.getTimeZone(id);
if (!tz.useDaylightTime()) {
continue;
}
TimeZone.setDefault(tz);
dateloop:
// Use future dates because sun.util.calendar.ZoneInfo
// delegates offset transition calculations to a SimpleTimeZone
// (after 2038 as of JDK7).
for (int year = BEGIN_YEAR; year < END_YEAR; year++) {
for (int month = MARCH; month <= NOVEMBER; month++) {
cal.set(year, month, 1, 15, 0, 0);
int maxDom = cal.getActualMaximum(DAY_OF_MONTH);
for (int dom = 1; dom <= maxDom; dom++) {
Date date = new Date(year - 1900, month, dom);
if (date.getYear()+1900 != year
|| date.getMonth() != month
|| date.getDate() != dom) {
System.err.printf("%s: got %04d-%02d-%02d, expected %04d-%02d-%02d%n",
id,
date.getYear() + 1900,
date.getMonth() + 1,
date.getDate(),
year,
month + 1,
dom);
errors++;
break dateloop;
}
}
}
}
}
} finally {
// Restore the default TimeZone.
TimeZone.setDefault(defaultTimeZone);
}
if (errors > 0) {
throw new RuntimeException("Transition test failed");
}
}
}

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2016, 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.
*/
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Bug8066652 {
public static void main(String args[]) {
ExecutorService executor = Executors.newFixedThreadPool(10);
Callable<TimeZone> calTimeZone = () -> TimeZone.getDefault();
List<Callable<TimeZone>> tasks = new ArrayList<>();
for (int j = 1; j < 10; j++) {
tasks.add(calTimeZone);
}
try {
List<Future<TimeZone>> results = executor.invokeAll(tasks);
for (Future<TimeZone> f : results) {
TimeZone tz = f.get();
if (! tz.getID().equals("GMT")) {
throw new RuntimeException("wrong Time zone ID: " + tz.getID()
+ ", It should be GMT");
}
}
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException("Execution interrupted or Execution Exception occurred", e);
} finally {
executor.shutdown();
}
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2016, 2019, 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 8066652
* @requires os.family == "mac"
* @summary tests thread safe native function localtime_r is accessed by multiple
* threads at same time and zone id should not be "GMT+00:00"
* if default timezone is "GMT" and user specifies a fake timezone.
* @library /test/lib
* @build Bug8066652
* @run main Bug8066652Run
*/
import java.util.Map;
import jdk.test.lib.JDKToolLauncher;
import jdk.test.lib.Utils;
import jdk.test.lib.process.ProcessTools;
public class Bug8066652Run {
private static String cp = Utils.TEST_CLASSES;
private static ProcessBuilder pb = new ProcessBuilder();
public static void main(String[] args) throws Throwable {
//set system TimeZone to GMT using environment variable TZ
Map<String, String> env = pb.environment();
env.put("TZ", "GMT");
System.out.println("Current TimeZone:" + pb.environment().get("TZ"));
JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("java");
//Setting invalid TimeZone using VM option
launcher.addToolArg("-Duser.timezone=Foo/Bar")
.addToolArg("-ea")
.addToolArg("-esa")
.addToolArg("-cp")
.addToolArg(cp)
.addToolArg("Bug8066652");
pb.command(launcher.getCommand());
int exitCode = ProcessTools.executeCommand(pb)
.getExitValue();
if (exitCode != 0) {
throw new RuntimeException("Unexpected exit code: " + exitCode);
}
}
}

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2016, 2018, 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 8149452 8151876 8181157 8206965
* @modules java.base/sun.util.calendar
* @run main/othervm -Duser.language=de -Duser.country=DE Bug8149452
* @run main/othervm -Duser.language=ja -Duser.country=JP Bug8149452
* @run main/othervm -Duser.language=en -Duser.country=US Bug8149452
* @summary Check the missing time zone names for English, German and Japanese locales.
*/
import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.TimeZone;
import java.util.Arrays;
import java.util.List;
public class Bug8149452 {
public static void main(String[] args) {
List<String> listNotFound = new ArrayList<>();
String[][] zoneStrings = DateFormatSymbols.getInstance()
.getZoneStrings();
for (String tzID : TimeZone.getAvailableIDs()) {
if (!Arrays.stream(zoneStrings)
.anyMatch(zone -> tzID.equalsIgnoreCase(zone[0]))) {
// to ignore names for Etc/GMT[+-][0-9]+ which are not supported
if (!tzID.startsWith("Etc/GMT")
&& !tzID.startsWith("GMT")) {
listNotFound.add(tzID);
}
}
}
if (!listNotFound.isEmpty()) {
throw new RuntimeException("Test Failed: Time Zone Strings for "
+ listNotFound + " not found");
}
}
}

View file

@ -0,0 +1,257 @@
/*
* Copyright (c) 2016, 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 8167143 8174269 8358170
* @summary Test
* Timezone parsing works for all locales for default providers preference
* CLDR implicit locales are correctly reflected,
* th_TH bundle is not wrongly cached in DateFormatSymbols,
* correct candidate locale list is retrieved for
* zh_Hant and zh_Hans and
* Implicit FALLBACK Locales nn-NO, nb-NO are reflected in available locales
* @modules java.base/sun.util.locale.provider
* java.base/sun.util.spi
* jdk.localedata
* @run main Bug8167143 testTimeZone
* @run main Bug8167143 testCldr
* @run main Bug8167143 testCache
* @run main Bug8167143 testCandidateLocales
* @run main Bug8167143 testFallback
*/
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TimeZone;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleProviderAdapter.Type;
public class Bug8167143 {
private static final TimeZone REYKJAVIK = TimeZone.getTimeZone("Atlantic/Reykjavik");
private static final TimeZone NEW_YORK = TimeZone.getTimeZone("America/New_York");
private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
private static final List<Locale> CLDR_IMPLICIT_LOCS = List.of(Locale.forLanguageTag("zh-Hans-CN"),
Locale.forLanguageTag("zh-Hans-SG"),
Locale.forLanguageTag("zh-Hant-HK"),
Locale.forLanguageTag("zh-Hant-TW"),
Locale.forLanguageTag("zh-Hant-MO"));
private static final List<Locale> FALLBACK_IMPLICIT_LOCS = List.of(Locale.forLanguageTag("nn-NO"),
Locale.forLanguageTag("nb-NO"));
/**
* List of candidate locales for zh_Hant
*/
private static final List<Locale> ZH_HANT_CANDLOCS = List.of(
Locale.forLanguageTag("zh-Hant"),
Locale.forLanguageTag("zh-TW"),
Locale.forLanguageTag("zh"),
Locale.ROOT);
/**
* List of candidate locales for zh_Hans
*/
private static final List<Locale> ZH_HANS_CANDLOCS = List.of(
Locale.forLanguageTag("zh-Hans"),
Locale.forLanguageTag("zh-CN"),
Locale.forLanguageTag("zh"),
Locale.ROOT);
public static void main(String[] args) {
switch (args[0]) {
case "testTimeZone":
testTimeZoneParsing();
break;
case "testCldr":
testImplicitCldrLocales();
break;
case "testCache":
testDateFormatSymbolsCache();
break;
case "testCandidateLocales":
testCandidateLocales();
break;
case "testFallback":
testImplicitFallbackLocales();
break;
default:
throw new RuntimeException("no test was specified.");
}
}
/**
* Check that if Locale Provider Preference list is Default, or if Locale
* Provider Preference List is COMPAT,CLDR SimplDateFormat parsing works for
* all Available Locales.
*/
private static void testTimeZoneParsing() {
Set<Locale> locales = Set.of(Locale.forLanguageTag("zh-hant"), Locale.of("no", "NO", "NY"));
// Set<Locale> locales = Set.of(Locale.getAvailableLocales());
locales.forEach((locale) -> {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd z", locale);
for (final TimeZone tz : new TimeZone[]{REYKJAVIK, GMT, NEW_YORK}) {
try {
sdf.parse("2000/02/10 " + tz.getDisplayName(locale));
} catch (ParseException e) {
throw new RuntimeException("TimeZone Parsing failed with Locale "
+ locale + " for TimeZone " + tz.getDisplayName(), e);
}
}
});
}
/**
* Check that locales implicitly supported from CLDR are reflected in output
* from getAvailbleLocales() for each bundle.
*
*/
private static void testImplicitCldrLocales() {
LocaleProviderAdapter cldr = LocaleProviderAdapter.forType(Type.CLDR);
checkPresenceCldr("CurrencyNameProvider",
cldr.getCurrencyNameProvider().getAvailableLocales());
checkPresenceCldr("LocaleNameProvider",
cldr.getLocaleNameProvider().getAvailableLocales());
checkPresenceCldr("TimeZoneNameProvider",
cldr.getTimeZoneNameProvider().getAvailableLocales());
checkPresenceCldr("CalendarDataProvider",
cldr.getCalendarDataProvider().getAvailableLocales());
checkPresenceCldr("CalendarNameProvider",
cldr.getCalendarProvider().getAvailableLocales());
}
private static void checkPresenceCldr(String testName, Locale[] got) {
List<Locale> gotLocalesList = Arrays.asList(got);
List<Locale> gotList = new ArrayList<>(gotLocalesList);
if (!testName.equals("TimeZoneNameProvider")) {
if (!gotList.removeAll(CLDR_IMPLICIT_LOCS)) {
// check which locale are not present in retrievedLocales List.
List<Locale> expectedLocales = new ArrayList<>(CLDR_IMPLICIT_LOCS);
expectedLocales.removeAll(gotList);
throw new RuntimeException("Locales those not correctly reflected are "
+ expectedLocales + " for test " + testName);
}
} else {
// check one extra locale zh_HK for TimeZoneNameProvider
Locale zh_HK = Locale.forLanguageTag("zh-HK");
if (!gotList.removeAll(CLDR_IMPLICIT_LOCS) && gotList.remove(zh_HK)) {
//check which locale are not present in retrievedLocales List
List<Locale> expectedLocales = new ArrayList<>(CLDR_IMPLICIT_LOCS);
expectedLocales.add(zh_HK);
expectedLocales.removeAll(gotList);
throw new RuntimeException("Locales those not correctly reflected are "
+ expectedLocales + " for test " + testName);
}
}
}
/**
* Check that if Locale Provider Preference list is default and if
* SimpleDateFormat instance for th-TH-TH is created first, then JRE bundle
* for th-TH should not be cached in cache of DateFormatSymbols class.
*/
private static void testDateFormatSymbolsCache() {
Locale th_TH_TH = Locale.of("th", "TH", "TH");
Locale th_TH = Locale.of("th", "TH");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd z", th_TH_TH);
String[][] thTHTHZoneStrings = sdf.getDateFormatSymbols().getZoneStrings();
String[][] thTHZoneStrings = sdf.getDateFormatSymbols().getZoneStrings();
if (Arrays.equals(thTHTHZoneStrings, thTHZoneStrings)) {
throw new RuntimeException("th_TH bundle still cached with DateFormatSymbols"
+ "cache for locale " + th_TH
);
}
}
/**
* Check that candidate locales list retrieved for zh__Hant and for zh__Hans
* do not have first candidate locale as zh_TW_Hant and zh_CN_Hans
* respectively.
*/
private static void testCandidateLocales() {
ResourceBundle.Control Control = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);
Locale zh_Hant = Locale.forLanguageTag("zh-Hant");
Locale zh_Hans = Locale.forLanguageTag("zh-Hans");
List<Locale> zhHantCandidateLocs = Control.getCandidateLocales("", zh_Hant);
List<Locale> zhHansCandidateLocs = Control.getCandidateLocales("", zh_Hans);
if (!zhHantCandidateLocs.equals(ZH_HANT_CANDLOCS)) {
reportDifference(zhHantCandidateLocs, ZH_HANT_CANDLOCS, "zh_Hant");
}
if (!zhHansCandidateLocs.equals(ZH_HANS_CANDLOCS)) {
reportDifference(zhHansCandidateLocs, ZH_HANS_CANDLOCS, "zh_Hans");
}
}
private static void reportDifference(List<Locale> got, List<Locale> expected, String locale) {
List<Locale> retrievedList = new ArrayList<>(got);
List<Locale> expectedList = new ArrayList<>(expected);
retrievedList.removeAll(expectedList);
expectedList.removeAll(retrievedList);
if ((retrievedList.size() > 0) && (expectedList.size() > 0)) {
throw new RuntimeException(" retrievedList contain extra candidate locales " + retrievedList
+ " and missing candidate locales " + expectedList
+ "for locale " + locale);
}
if ((retrievedList.size() > 0)) {
throw new RuntimeException(" retrievedList contain extra candidate locales " + retrievedList
+ "for locale " + locale);
}
if ((expectedList.size() > 0)) {
throw new RuntimeException(" retrievedList contain extra candidate locales " + expectedList
+ "for locale " + locale);
}
}
/**
* Checks that locales (nn-NO and nb-NO) implicitly supported in FALLBACK
* provider should be present in output of getAvailableLocales() for
* BreakIteratorProvider and CollatorProvider.
*/
private static void testImplicitFallbackLocales() {
LocaleProviderAdapter fallback = LocaleProviderAdapter.forType(Type.FALLBACK);
checkPresenceFallback("BreakIteratorProvider",
fallback.getBreakIteratorProvider().getAvailableLocales());
checkPresenceFallback("CollatorProvider",
fallback.getCollatorProvider().getAvailableLocales());
}
private static void checkPresenceFallback(String testName, Locale[] got) {
List<Locale> gotLocalesList = Arrays.asList(got);
List<Locale> gotList = new ArrayList<>(gotLocalesList);
if (!gotList.removeAll(FALLBACK_IMPLICIT_LOCS)) {
// check which Implicit locale are not present in retrievedLocales List.
List<Locale> implicitLocales = new ArrayList<>(FALLBACK_IMPLICIT_LOCS);
implicitLocales.removeAll(gotList);
throw new RuntimeException("Locale(s) not correctly reflected are "
+ implicitLocales + " for test " + testName);
}
}
}

View file

@ -0,0 +1,170 @@
/*
* Copyright (c) 2012, 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 8005471 8008577 8129881 8130845 8136518 8181157 8210490 8220037
* 8234347 8236548 8317979 8354548
* @modules jdk.localedata
* @run main CLDRDisplayNamesTest
* @summary Make sure that localized time zone names of CLDR are used
* if specified.
*/
import java.text.*;
import java.util.*;
import static java.util.TimeZone.*;
public class CLDRDisplayNamesTest {
/*
* The first element is a language tag. The rest are localized
* display names of America/Los_Angeles copied from the CLDR
* resources data. If data change in CLDR, test data below will
* need to be changed accordingly.
*
* Generic names are NOT tested (until they are supported by API).
*/
static final String[][] CLDR_DATA = {
{
"ja-JP",
"米国太平洋標準時",
"PST",
"米国太平洋夏時間",
"PDT",
},
{
"zh-CN",
"北美太平洋标准时间",
"PST",
"北美太平洋夏令时间",
"PDT",
},
{
"de-DE",
"Nordamerikanische Westküsten-Normalzeit",
"PST",
"Nordamerikanische Westküsten-Sommerzeit",
"PDT",
},
};
private static final String NO_INHERITANCE_MARKER = "∅∅∅";
public static void main(String[] args) {
// Make sure that localized time zone names of CLDR are used
// if specified.
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
int errors = 0;
for (String[] data : CLDR_DATA) {
Locale locale = Locale.forLanguageTag(data[0]);
for (int i = 1; i < data.length; i++) {
int style = ((i % 2) == 1) ? LONG : SHORT;
boolean daylight = (i == 3 || i == 4);
String name = tz.getDisplayName(daylight, style, locale);
if (!data[i].equals(name)) {
System.err.printf("error: got '%s' expected '%s' (style=%d, daylight=%s, locale=%s)%n",
name, data[i], style, daylight, locale);
errors++;
}
}
}
// for 8129881
/* 8234347: CLDR Converter will not pre-fill short display names from COMPAT anymore.
tz = TimeZone.getTimeZone("Europe/Vienna");
String name = tz.getDisplayName(false, SHORT, Locale.ENGLISH);
if (!"CET".equals(name)) {
System.err.printf("error: got '%s' expected 'CET' %n", name);
errors++;
}
*/
// for 8130845
SimpleDateFormat fmtROOT = new SimpleDateFormat("EEE MMM d hh:mm:ss z yyyy", Locale.ROOT);
SimpleDateFormat fmtUS = new SimpleDateFormat("EEE MMM d hh:mm:ss z yyyy", Locale.US);
SimpleDateFormat fmtUK = new SimpleDateFormat("EEE MMM d hh:mm:ss z yyyy", Locale.UK);
Locale originalLocale = Locale.getDefault();
try {
Locale.setDefault(Locale.ROOT);
fmtROOT.parse("Thu Nov 13 04:35:51 GMT-09:00 2008");
fmtUS.parse("Thu Nov 13 04:35:51 AKST 2008");
fmtUK.parse("Thu Nov 13 04:35:51 GMT-09:00 2008");
} catch (ParseException pe) {
System.err.println(pe);
errors++;
} finally {
Locale.setDefault(originalLocale);
}
// for 8210490
// Check that TimeZone.getDisplayName should honor passed locale parameter,
// even if default locale is set to some other locale.
Locale.setDefault(Locale.forLanguageTag("ar-PK"));
TimeZone zi = TimeZone.getTimeZone("Etc/GMT-5");
String displayName = zi.getDisplayName(false, TimeZone.SHORT, Locale.US);
Locale.setDefault(originalLocale);
if (!displayName.equals("GMT+05:00")) {
System.err.println("Wrong display name for timezone Etc/GMT-5 : expected GMT+05:00, Actual " + displayName);
errors++;
}
// 8217366: No "no inheritance marker" should be left in the returned array
// from DateFormatSymbols.getZoneStrings()
errors += List.of(Locale.ROOT,
Locale.CHINA,
Locale.GERMANY,
Locale.JAPAN,
Locale.UK,
Locale.US,
Locale.forLanguageTag("hi-IN"),
Locale.forLanguageTag("es-419")).stream()
.peek(System.out::println)
.map(l -> DateFormatSymbols.getInstance(l).getZoneStrings())
.flatMap(zoneStrings -> Arrays.stream(zoneStrings))
.filter(namesArray -> Arrays.stream(namesArray)
.anyMatch(aName -> aName.equals(NO_INHERITANCE_MARKER)))
.peek(marker -> {
System.err.println("No-inheritance-marker is detected with tzid: "
+ marker[0]);
})
.count();
// 8220037: Make sure CLDRConverter uniquely produces bundles, regardless of the
// source file enumeration order.
/* 8234347: CLDR Converter will not pre-fill short display names from COMPAT anymore.
tz = TimeZone.getTimeZone("America/Argentina/La_Rioja");
if (!"ARST".equals(tz.getDisplayName(true, TimeZone.SHORT,
new Locale.Builder()
.setLanguage("en")
.setRegion("CA")
.build()))) {
System.err.println("Short display name of \"" + tz.getID() + "\" was not \"ARST\"");
errors++;
}
*/
if (errors > 0) {
throw new RuntimeException("test failed");
}
}
}

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2022, 2023, 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 8285838
* @library /test/lib
* @summary This test will ensure that daylight savings rules are followed
* appropriately when setting a custom timezone ID via the TZ env variable.
* @requires os.family != "windows"
* @run main/othervm CustomTzIDCheckDST
*/
import java.util.Calendar;
import java.util.Date;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.time.DayOfWeek;
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAdjusters;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
public class CustomTzIDCheckDST {
// Northern Hemisphere
private static String CUSTOM_TZ = "MEZ-1MESZ,M3.5.0,M10.5.0/3";
// Simulate Southern Hemisphere
private static String CUSTOM_TZ2 = "MEZ-1MESZ,M10.5.0,M3.5.0/3";
public static void main(String args[]) throws Throwable {
if (args.length == 0) {
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("CustomTzIDCheckDST", "runTZTest");
pb.environment().put("TZ", CUSTOM_TZ);
OutputAnalyzer output = ProcessTools.executeProcess(pb);
output.shouldHaveExitValue(0);
pb.environment().put("TZ", CUSTOM_TZ2);
output = ProcessTools.executeProcess(pb);
output.shouldHaveExitValue(0);
} else {
runTZTest();
}
}
/* TZ is set to "MEZ-1MESZ,M3.5.0,M10.5.0/3", it will be the northern hemisphere.
* This ensures the transition periods for Daylights Savings should be at March's last
* Sunday and October's last Sunday.
*/
private static void runTZTest() {
Date time = new Date();
String tzStr = System.getenv("TZ");
if (tzStr == null)
throw new RuntimeException("Got unexpected timezone information: TZ is null");
boolean nor = CUSTOM_TZ.equals(tzStr);
TimeZone tz = new SimpleTimeZone(3600000, tzStr,
nor ? Calendar.MARCH : Calendar.OCTOBER, -1,
Calendar.SUNDAY, 3600000, SimpleTimeZone.UTC_TIME,
nor ? Calendar.OCTOBER : Calendar.MARCH, -1,
Calendar.SUNDAY, 3600000, SimpleTimeZone.UTC_TIME,
3600000);
if (tz.inDaylightTime(time)) {
// We are in Daylight savings period.
if (time.toString().endsWith("GMT+02:00 " + Integer.toString(time.getYear() + 1900)))
return;
} else {
if (time.toString().endsWith("GMT+01:00 " + Integer.toString(time.getYear() + 1900)))
return;
}
// Reaching here means time zone did not match up as expected.
throw new RuntimeException("Got unexpected timezone information: " + tzStr + " " + time);
}
private static ZonedDateTime getLastSundayOfMonth(ZonedDateTime date) {
return date.with(TemporalAdjusters.lastInMonth(DayOfWeek.SUNDAY));
}
}

View file

@ -0,0 +1,107 @@
/*
* Copyright (c) 2011, 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 6936350 8347841 8347955
* @summary Test case for TimeZone.observesDaylightTime()
*/
import java.time.ZoneId;
import java.util.*;
import java.util.function.Predicate;
import static java.util.GregorianCalendar.*;
public class DaylightTimeTest {
private static final int ONE_HOUR = 60 * 60 * 1000; // one hour
private static final int INTERVAL = 24 * ONE_HOUR; // one day
private static final String[] ZONES = TimeZone.availableIDs()
.filter(Predicate.not(ZoneId.SHORT_IDS::containsKey))
.toArray(String[]::new);
private static int errors = 0;
public static void main(String[] args) {
// Test default TimeZone
for (String id : ZONES) {
TimeZone tz = TimeZone.getTimeZone(id);
long now = System.currentTimeMillis();
boolean observes = tz.observesDaylightTime();
boolean found = findDSTTransition(tz, now);
if (observes != found) {
// There's a critical section. If DST ends after the
// System.currentTimeMills() call, there should be
// inconsistency in the determination. Try the same
// thing again to see the inconsistency was due to the
// critical section.
now = System.currentTimeMillis();
observes = tz.observesDaylightTime();
found = findDSTTransition(tz, now);
if (observes != found) {
System.err.printf("%s: observesDaylightTime() should return %s at %d%n",
tz.getID(), found, now);
errors++;
}
}
}
// Test SimpleTimeZone in which observesDaylightTime() is
// equivalent to useDaylightTime().
testSimpleTimeZone(new SimpleTimeZone(-8*ONE_HOUR, "X",
APRIL, 1, -SUNDAY, 2*ONE_HOUR,
OCTOBER, -1, SUNDAY, 2*ONE_HOUR,
1*ONE_HOUR));
testSimpleTimeZone(new SimpleTimeZone(-8*ONE_HOUR, "Y"));
if (errors > 0) {
throw new RuntimeException("DaylightTimeTest: failed");
}
}
/**
* Returns true if it's `now' in DST or there's any
* standard-to-daylight transition within 50 years after `now'.
*/
private static boolean findDSTTransition(TimeZone tz, long now) {
GregorianCalendar cal = new GregorianCalendar(tz, Locale.US);
cal.setTimeInMillis(now);
cal.add(YEAR, 50);
long end = cal.getTimeInMillis();
for (long t = now; t < end; t += INTERVAL) {
cal.setTimeInMillis(t);
if (cal.get(DST_OFFSET) > 0) {
return true;
}
}
return false;
}
private static void testSimpleTimeZone(SimpleTimeZone stz) {
if (stz.useDaylightTime() != stz.observesDaylightTime()) {
System.err.printf("Failed: useDaylightTime=%b, observesDaylightTime()=%b%n\t%s%n",
stz.useDaylightTime(),stz.observesDaylightTime(), stz);
errors++;
}
}
}

View file

@ -0,0 +1,141 @@
/*
* Copyright (c) 2005, 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 4296930 5033603 7092679
* @summary Ensure that Java detects the platform time zone correctly, even
* if changed during runtime. Also ensure that the system time zone detection code
* detects the "Automatically adjust clock for daylight saving changes" setting
* correctly on Windows. This is a manual test dependent on making changes to
* the platform setting of the machine and thus cannot be automated.
* @library /java/awt/regtesthelpers
* @build PassFailJFrame
* @run main/manual DefaultTimeZoneTest
*/
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.BoxLayout;
import javax.swing.Box;
import java.awt.Dimension;
import java.awt.Component;
import java.awt.BorderLayout;
import java.awt.Window;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class DefaultTimeZoneTest {
private static final SimpleDateFormat SDF =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzzz (XXX)");
private static final String INSTRUCTIONS =
"""
Tests the platform time zone detection on all platforms.
(Part I) and on/off of DST adjustment on Windows (Part II).
Part I:
Observe the displayed Time zone ID and the local time.
Change the platform time zone setting, then click the
"Update Time Zone" button. If the ID and local time
update correctly, part I passes, otherwise press fail. Note that
some time zone IDs have their aliases that may be displayed.
For example, "US/Pacific" is an alias of "America/Los_Angeles".
If this platform is Windows, proceed to Part II. Otherwise, press
the Pass button to complete this test.
Part II:
Note that Part II may require the Administrator privilege to change
Windows setting.
1. Open the Settings app and navigate to Time & Language > Date & Time
2. Select any time zone where daylight saving time is *currently*
in effect, such as "(GMT-08:00) Pacific Time (US & Canada);
Tijuana", "(GMT+10:00) Canberra, Melbourne, Sydney", and Apply.
3. After pressing "Update Time Zone" button, observe that the local
time on the Settings app and the test local time are the same (daylight time).
4. Turn off "Adjust for daylight saving time automatically"
5. Observe the two local times should be the same (standard time).
6. Turn on "Adjust for daylight saving time automatically"
If the local time in the Settings app and test window are always the same,
then this test passes. Press the Pass or Fail button based on the Part II
result and complete the test.
""";
public static void main(String[] args)
throws InterruptedException, InvocationTargetException {
// Force platform time zone as default time zone
TimeZone.setDefault(null);
System.setProperty("user.timezone", "");
// Construct test window
PassFailJFrame.builder()
.title("DefaultTimeZoneTest Instructions")
.testUI(createTest())
.instructions(INSTRUCTIONS)
.build().awaitAndCheck();
}
private static Window createTest() {
var contents = new JFrame("DefaultTimeZoneTest");
contents.setSize(350, 250);
// Panel with vertical layout
var panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
// Time zone ID label
var timeZoneID = new JLabel("Time zone ID: " + SDF.getTimeZone().getID(), SwingConstants.CENTER);
timeZoneID.setAlignmentX(Component.CENTER_ALIGNMENT);
// Time label
var label = new JLabel(SDF.format(new Date()), SwingConstants.CENTER);
label.setAlignmentX(Component.CENTER_ALIGNMENT);
// Update button
var button = new JButton("Update Time Zone");
button.setAlignmentX(Component.CENTER_ALIGNMENT);
// Add components with spacing
panel.add(Box.createRigidArea(new Dimension(0, 10)));
panel.add(timeZoneID);
panel.add(Box.createRigidArea(new Dimension(0, 5)));
panel.add(label);
panel.add(Box.createRigidArea(new Dimension(0, 10)));
panel.add(button);
contents.add(panel);
// Update default time zone on button click
button.addActionListener(e -> {
// Clear JVM cached timezone and force reload from OS
TimeZone.setDefault(null);
System.setProperty("user.timezone", "");
TimeZone tz = TimeZone.getDefault();
SDF.setTimeZone(tz);
timeZoneID.setText("Time zone ID: " + tz.getID());
label.setText(SDF.format(new Date()));
contents.repaint();
});
return contents;
}
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2001, 2024, 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 4487276 8008577 8174269
* @modules jdk.localedata
* @summary Verify that Hong Kong locale uses traditional Chinese names.
* @run main/othervm HongKong
*/
import java.util.Locale;
import java.util.TimeZone;
public class HongKong {
public static void main(String[] args) {
Locale reservedLocale = Locale.getDefault();
try {
Locale.setDefault(Locale.of("zh", "HK"));
checkCountry(Locale.GERMANY, "\u5fb7\u570b");
checkCountry(Locale.FRANCE, "\u6cd5\u570b");
checkCountry(Locale.ITALY, "\u610f\u5927\u5229");
checkTimeZone("Asia/Shanghai",
"\u4e2d\u570b\u6a19\u6e96\u6642\u9593");
} finally {
// restore the reserved locale
Locale.setDefault(reservedLocale);
}
}
private static void checkCountry(Locale country, String expected) {
String actual = country.getDisplayCountry();
if (!expected.equals(actual)) {
throw new RuntimeException("Failed. actual: %s, expected: %s"
.formatted(actual, expected));
}
}
private static void checkTimeZone(String timeZoneID, String expected) {
TimeZone timeZone = TimeZone.getTimeZone(timeZoneID);
String actual = timeZone.getDisplayName();
if (!expected.equals(actual)) {
throw new RuntimeException("Failed. actual: %s, expected: %s"
.formatted(actual, expected));
}
}
}

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 2002, 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 4509255 5055567 6176318 7090844 8347841 8347955
* @summary Tests consistencies of time zone IDs.
*/
import java.time.ZoneId;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.function.Predicate;
public class IDTest {
public static void main(String[] args) {
Set<String> ids = new HashSet<>();
Map<Integer, Set<String>> tree = new TreeMap<>();
String[] tzs = TimeZone.availableIDs()
.filter(Predicate.not(ZoneId.SHORT_IDS::containsKey))
.toArray(String[]::new);
String[] tzs2 = TimeZone.availableIDs()
.filter(Predicate.not(ZoneId.SHORT_IDS::containsKey))
.toArray(String[]::new);
if (tzs.length != tzs2.length) {
throw new RuntimeException("tzs.length(" + tzs.length
+ ") != tzs2.length(" + tzs2.length + ")");
}
for (int i = 0; i < tzs.length; i++) {
if (tzs[i] != tzs2[i]) {
throw new RuntimeException(i + ": " + tzs[i] + " != " + tzs2[i]);
}
}
System.out.println("Total: " + tzs.length + " time zone IDs");
for (String id : tzs) {
ids.add(id);
TimeZone tz = TimeZone.getTimeZone(id);
Integer offset = tz.getRawOffset();
Set<String> s = tree.get(offset);
if (s == null) {
s = new HashSet<>();
tree.put(offset, s);
}
s.add(id);
}
for (Integer key : tree.keySet()) {
Set<String> s1 = tree.get(key);
// Make sure no duplicates in the other sets
for (Integer k : tree.keySet()) {
if (k.equals(key)) {
continue;
}
Set<String> s2 = new HashSet<>(tree.get(k));
s2.retainAll(s1);
if (!s2.isEmpty()) {
throw new RuntimeException("s1 included in the subset for " + (k.intValue()/60000) +
" (" + s2 + " shouldn't be in s1)");
}
}
// Check the getAvailableIDs(int) call to return the same
// set of IDs
int offset = key.intValue();
tzs = TimeZone.availableIDs(offset)
.filter(Predicate.not(ZoneId.SHORT_IDS::containsKey))
.toArray(String[]::new);
tzs2 = TimeZone.availableIDs(offset)
.filter(Predicate.not(ZoneId.SHORT_IDS::containsKey))
.toArray(String[]::new);
if (!Arrays.equals(tzs, tzs2)) {
throw new RuntimeException("inconsistent tzs from getAvailableIDs("+offset+")");
}
Set<String> s2 = new HashSet<>();
s2.addAll(Arrays.asList(tzs));
if (!s1.equals(s2)) {
throw new RuntimeException("s1 != s2 for " + offset/60000 +
" (diff=" + getDiff(s1, s2) + ")");
}
if (!ids.containsAll(s2)) {
throw new RuntimeException("s2 isn't a subset of ids (" + getDiff(s2, ids) +
" not in ids)");
}
}
for (Integer key : tree.keySet()) {
Set<String> s1 = tree.get(key);
ids.removeAll(s1);
}
if (!ids.isEmpty()) {
throw new RuntimeException("ids didn't become empty. (" + ids + ")");
}
}
private static String getDiff(Set<String> set1, Set<String> set2) {
Set<String> s1 = new HashSet<>(set1);
s1.removeAll(set2);
Set<String> s2 = new HashSet<>(set2);
s2.removeAll(set1);
s2.addAll(s1);
return s2.toString();
}
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2009, 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 6851214 8347841 8347955
* @summary Allow 24:00 as a valid end/start DST time stamp
* @run main ListTimeZones
*/
import java.time.ZoneId;
import java.util.*;
import java.util.function.Predicate;
public class ListTimeZones{
public static void main(String[] args){
Date date = new Date();
String[] TimeZoneIds = TimeZone.availableIDs()
.filter(Predicate.not(ZoneId.SHORT_IDS::containsKey))
.toArray(String[]::new);
for(int i = 0; i < TimeZoneIds.length; i++){
TimeZone tz = TimeZone.getTimeZone(TimeZoneIds[i]);
Calendar calendar = new GregorianCalendar(tz);
String calString = calendar.toString();
}
}
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2019, 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.
*/
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.TimeZone;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
/**
* @test
* @bug 8212970 8324065
* @summary Test whether the savings are positive in time zones that have
* negative savings in the source TZ files.
* @run junit NegativeDSTTest
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class NegativeDSTTest {
private static final TimeZone DUBLIN = TimeZone.getTimeZone("Europe/Dublin");
private static final TimeZone PRAGUE = TimeZone.getTimeZone("Europe/Prague");
private static final TimeZone WINDHOEK = TimeZone.getTimeZone("Africa/Windhoek");
private static final TimeZone CASABLANCA = TimeZone.getTimeZone("Africa/Casablanca");
private static final int ONE_HOUR = 3600_000;
private Object[][] negativeDST () {
return new Object[][] {
// TimeZone, localDate, offset, isDaylightSavings
// Europe/Dublin for the Rule "Eire"
{DUBLIN, LocalDate.of(1970, 6, 23), ONE_HOUR, true},
{DUBLIN, LocalDate.of(1971, 6, 23), ONE_HOUR, true},
{DUBLIN, LocalDate.of(1971, 11, 1), 0, false},
{DUBLIN, LocalDate.of(2019, 6, 23), ONE_HOUR, true},
{DUBLIN, LocalDate.of(2019, 12, 23), 0, false},
// Europe/Prague which contains fixed negative savings (not a named Rule)
{PRAGUE, LocalDate.of(1946, 9, 30), 2 * ONE_HOUR, true},
{PRAGUE, LocalDate.of(1946, 10, 10), ONE_HOUR, false},
{PRAGUE, LocalDate.of(1946, 12, 3), 0, false},
{PRAGUE, LocalDate.of(1947, 2, 25), ONE_HOUR, false},
{PRAGUE, LocalDate.of(1947, 4, 30), 2 * ONE_HOUR, true},
// Africa/Windhoek for the Rule "Namibia"
{WINDHOEK, LocalDate.of(1994, 3, 23), ONE_HOUR, false},
{WINDHOEK, LocalDate.of(2016, 9, 23), 2 * ONE_HOUR, true},
// Africa/Casablanca for the Rule "Morocco" Defines negative DST till 2037 as of 2019a.
{CASABLANCA, LocalDate.of(1939, 9, 13), ONE_HOUR, true},
{CASABLANCA, LocalDate.of(1939, 11, 20), 0, false},
{CASABLANCA, LocalDate.of(2018, 6, 18), ONE_HOUR, true},
{CASABLANCA, LocalDate.of(2019, 1, 1), ONE_HOUR, true},
{CASABLANCA, LocalDate.of(2019, 5, 6), 0, false},
{CASABLANCA, LocalDate.of(2037, 10, 5), 0, false},
{CASABLANCA, LocalDate.of(2037, 11, 16), ONE_HOUR, true},
{CASABLANCA, LocalDate.of(2038, 9, 27), 0, false},
{CASABLANCA, LocalDate.of(2038, 11, 1), ONE_HOUR, true},
{CASABLANCA, LocalDate.of(2087, 3, 31), 0, false},
{CASABLANCA, LocalDate.of(2087, 5, 12), ONE_HOUR, true},
};
}
@ParameterizedTest
@MethodSource("negativeDST")
public void test_NegativeDST(TimeZone tz, LocalDate ld, int offset, boolean isDST) {
Date d = Date.from(Instant.from(ZonedDateTime.of(ld, LocalTime.MIN, tz.toZoneId())));
assertEquals(offset, tz.getOffset(d.getTime()));
assertEquals(isDST, tz.inDaylightTime(d));
}
}

View file

@ -0,0 +1,137 @@
/*
* Copyright (c) 2017, 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.
*/
import java.util.Calendar;
import java.util.Locale;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import java.util.function.Supplier;
/*
* @test
* @bug 8191216
* @summary test that provokes race between cloning and lazily initializing
* SimpleTimeZone cache fields
*/
public class SimpleTimeZoneCloneRaceTest {
public static void main(String[] args) throws InterruptedException {
// shared TZ user repeatedly samples sharedTZ and calculates offset
// using the shared instance
TimeZoneUser sharedTZuser = new TimeZoneUser(() -> sharedTZ);
// cloned TZ user repeatedly samples sharedTZ then clones it and
// calculates offset using the clone...
TimeZoneUser clonedTZuser = new TimeZoneUser(() -> {
// sample shared TZ
TimeZone tz = sharedTZ;
// do some computation that takes roughly the same time as it takes
// sharedTZUser to start changing cache fields in shared TZ
cpuHogTZ.getOffset(time);
// now clone the sampled TZ and return it, hoping the clone is done
// at about the right time....
return (TimeZone) tz.clone();
});
// start threads
Thread t1 = new Thread(sharedTZuser);
Thread t2 = new Thread(clonedTZuser);
t1.start();
t2.start();
// plant new SimpleTimeZone instances for 2 seconds
long t0 = System.currentTimeMillis();
do {
TimeZone tz1 = createSTZ();
TimeZone tz2 = createSTZ();
cpuHogTZ = tz1;
sharedTZ = tz2;
} while (System.currentTimeMillis() - t0 < 2000L);
sharedTZuser.stop = true;
clonedTZuser.stop = true;
t1.join();
t2.join();
System.out.println(
String.format("shared TZ: %d correct, %d incorrect calculations",
sharedTZuser.correctCount, sharedTZuser.incorrectCount)
);
System.out.println(
String.format("cloned TZ: %d correct, %d incorrect calculations",
clonedTZuser.correctCount, clonedTZuser.incorrectCount)
);
if (clonedTZuser.incorrectCount > 0) {
throw new RuntimeException(clonedTZuser.incorrectCount +
" fatal data races detected");
}
}
static SimpleTimeZone createSTZ() {
return new SimpleTimeZone(-28800000,
"America/Los_Angeles",
Calendar.APRIL, 1, -Calendar.SUNDAY,
7200000,
Calendar.OCTOBER, -1, Calendar.SUNDAY,
7200000,
3600000);
}
static volatile TimeZone cpuHogTZ = createSTZ();
static volatile TimeZone sharedTZ = createSTZ();
static final long time;
static final long correctOffset;
static {
TimeZone tz = createSTZ();
Calendar cal = Calendar.getInstance(tz, Locale.ROOT);
cal.set(2000, Calendar.MAY, 1, 0, 0, 0);
time = cal.getTimeInMillis();
correctOffset = tz.getOffset(time);
}
static class TimeZoneUser implements Runnable {
private final Supplier<? extends TimeZone> tzSupplier;
TimeZoneUser(Supplier<? extends TimeZone> tzSupplier) {
this.tzSupplier = tzSupplier;
}
volatile boolean stop;
int correctCount, incorrectCount;
@Override
public void run() {
while (!stop) {
TimeZone tz = tzSupplier.get();
int offset = tz.getOffset(time);
if (offset == correctOffset) {
correctCount++;
} else {
incorrectCount++;
}
}
}
}
}

View file

@ -0,0 +1,83 @@
/*
* Copyright (c) 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 8369184
* @summary Checks if equals()/hashCode() of SimpleTimeZone works correctly
* @run junit SimpleTimeZoneEqualsHashCodeTest
*/
import java.util.SimpleTimeZone;
import static java.util.Calendar.MARCH;
import static java.util.Calendar.NOVEMBER;
import static java.util.Calendar.SUNDAY;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class SimpleTimeZoneEqualsHashCodeTest {
private static final SimpleTimeZone STZ_WITH_DST =
new SimpleTimeZone(-288_000_000, "America/Los_Angeles",
MARCH, 8, -SUNDAY, 7_200_000,
NOVEMBER, 1, -SUNDAY, 7_200_000);
private static final SimpleTimeZone STZ_WITHOUT_DST =
new SimpleTimeZone(0, "foo");
@Test
void withDSTTest() {
var stz = (SimpleTimeZone)STZ_WITH_DST.clone();
assertEquals(STZ_WITH_DST, stz);
assertEquals(STZ_WITH_DST.hashCode(), stz.hashCode());
stz.setEndRule(NOVEMBER, 8, -SUNDAY, 7_200_000);
assertNotEquals(STZ_WITH_DST, stz);
// From the contract point, hash codes may be the same.
// This tests the implementation which considers DST
// related fields for calculating the hash code.
assertNotEquals(STZ_WITH_DST.hashCode(), stz.hashCode());
}
@Test
void withoutDSTTest() {
var stz = (SimpleTimeZone)STZ_WITHOUT_DST.clone();
// Only setting start rule. Still considered non-DST zone
stz.setStartRule(MARCH, 8, -SUNDAY, 7_200_000);
assertTrue(!stz.useDaylightTime());
assertEquals(STZ_WITHOUT_DST, stz);
assertEquals(STZ_WITHOUT_DST.hashCode(), stz.hashCode());
// Setting end rule as well. Now it is considered DST zone
stz.setEndRule(NOVEMBER, 8, -SUNDAY, 7_200_000);
assertTrue(stz.useDaylightTime());
assertNotEquals(STZ_WITHOUT_DST, stz);
// From the contract point, hash codes may be the same.
// This tests the implementation which considers DST
// related fields for calculating the hash code.
assertNotEquals(STZ_WITHOUT_DST.hashCode(), stz.hashCode());
}
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2008, 2022, 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.
*/
import java.io.*;
// This class is public so that tools can invoke.
public class TextFileReader implements AutoCloseable {
private BufferedReader reader;
private int lineNo;
public TextFileReader(String filename) throws IOException {
this(new File(new File(System.getProperty("test.src", "."),
"TimeZoneData"),
filename));
}
public TextFileReader(File file) throws IOException {
InputStream is = new FileInputStream(file);
reader = new BufferedReader(new InputStreamReader(is, "utf-8"));
}
public String readLine() throws IOException {
return getLine();
}
public String getLine() throws IOException {
checkReader();
String line;
while ((line = reader.readLine()) != null) {
lineNo++;
line = line.trim();
// Skip blank and comment lines.
if (line.length() == 0) {
continue;
}
int x = line.indexOf('#');
if (x == 0) {
continue;
}
if (x > 0) {
line = line.substring(0, x).trim();
}
break;
}
return line;
}
public String getRawLine() throws IOException {
checkReader();
String line = reader.readLine();
if (line != null) {
lineNo++;
}
return line;
}
private void checkReader() throws IOException {
if (reader == null) {
throw new IOException("This TextFileReader has been closed.");
}
}
@Override
public void close() throws IOException {
reader.close();
reader = null;
}
int getLineNo() {
return lineNo;
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 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 8342550 8349873
* @summary Three-letter time zone IDs should output a deprecated warning
* message.
* @library /test/lib
* @build jdk.test.lib.process.ProcessTools
* @run junit ThreeLetterZoneID
*/
import java.util.TimeZone;
import jdk.test.lib.process.ProcessTools;
import org.junit.jupiter.api.Test;
public class ThreeLetterZoneID {
private static final String WARNING =
"WARNING: Use of the three-letter time zone ID \"PST\" is deprecated and it will be removed in a future release";
public static void main(String... args) {
if (args.length > 0) {
TimeZone.getTimeZone("PST");
} else {
TimeZone.getDefault();
}
}
@Test
public void testExplicitGetTimeZone() throws Exception {
ProcessTools.executeTestJava("ThreeLetterZoneID", "dummy").stderrShouldMatch(WARNING);
}
@Test
public void testSysProp() throws Exception {
ProcessTools.executeTestJava("-Duser.timezone=PST", "ThreeLetterZoneID").stderrShouldMatch(WARNING);
}
}

View file

@ -0,0 +1,424 @@
/*
* Copyright (c) 1997, 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 8347841
* @summary test Time Zone Boundary
* @run junit TimeZoneBoundaryTest
*/
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.SimpleTimeZone;
import java.util.TimeZone;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
/**
* A test which discovers the boundaries of DST programmatically and verifies
* that they are correct.
*/
public class TimeZoneBoundaryTest
{
static final int ONE_SECOND = 1000;
static final int ONE_MINUTE = 60*ONE_SECOND;
static final int ONE_HOUR = 60*ONE_MINUTE;
static final long ONE_DAY = 24*ONE_HOUR;
static final long ONE_YEAR = (long)(365.25 * ONE_DAY);
static final long SIX_MONTHS = ONE_YEAR / 2;
static final int MONTH_LENGTH[] = {31,29,31,30,31,30,31,31,30,31,30,31};
// These values are empirically determined to be correct
static final long PST_1997_BEG = 860320800000L;
static final long PST_1997_END = 877856400000L;
// Minimum interval for binary searches in ms; should be no larger
// than 1000.
static final long INTERVAL = 10; // Milliseconds
static final String AUSTRALIA = "Australia/Adelaide";
static final long AUSTRALIA_1997_BEG = 877797000000L;
static final long AUSTRALIA_1997_END = 859653000000L;
/**
* Date.toString().substring() Boundary Test
* Look for a DST changeover to occur within 6 months of the given Date.
* The initial Date.toString() should yield a string containing the
* startMode as a SUBSTRING. The boundary will be tested to be
* at the expectedBoundary value.
*/
void findDaylightBoundaryUsingDate(Date d, String startMode, long expectedBoundary)
{
// Given a date with a year start, find the Daylight onset
// and end. The given date should be 1/1/xx in some year.
if (d.toString().indexOf(startMode) == -1)
{
System.out.println("Error: " + startMode + " not present in " + d);
}
// Use a binary search, assuming that we have a Standard
// time at the midpoint.
long min = d.getTime();
long max = min + SIX_MONTHS;
while ((max - min) > INTERVAL)
{
long mid = (min + max) >> 1;
String s = new Date(mid).toString();
// logln(s);
if (s.indexOf(startMode) != -1)
{
min = mid;
}
else
{
max = mid;
}
}
System.out.println("Date Before: " + showDate(min));
System.out.println("Date After: " + showDate(max));
long mindelta = expectedBoundary - min;
long maxdelta = max - expectedBoundary;
if (mindelta >= 0 && mindelta <= INTERVAL &&
mindelta >= 0 && mindelta <= INTERVAL)
System.out.println("PASS: Expected boundary at " + expectedBoundary);
else
fail("FAIL: Expected boundary at " + expectedBoundary);
}
void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST, long expectedBoundary)
{
findDaylightBoundaryUsingTimeZone(d, startsInDST, expectedBoundary,
TimeZone.getDefault());
}
void findDaylightBoundaryUsingTimeZone(Date d, boolean startsInDST,
long expectedBoundary, TimeZone tz)
{
// Given a date with a year start, find the Daylight onset
// and end. The given date should be 1/1/xx in some year.
// Use a binary search, assuming that we have a Standard
// time at the midpoint.
long min = d.getTime();
long max = min + SIX_MONTHS;
if (tz.inDaylightTime(d) != startsInDST)
{
fail("FAIL: " + tz.getID() + " inDaylightTime(" +
d + ") != " + startsInDST);
startsInDST = !startsInDST; // Flip over; find the apparent value
}
if (tz.inDaylightTime(new Date(max)) == startsInDST)
{
fail("FAIL: " + tz.getID() + " inDaylightTime(" +
(new Date(max)) + ") != " + (!startsInDST));
return;
}
while ((max - min) > INTERVAL)
{
long mid = (min + max) >> 1;
boolean isIn = tz.inDaylightTime(new Date(mid));
if (isIn == startsInDST)
{
min = mid;
}
else
{
max = mid;
}
}
System.out.println(tz.getID() + " Before: " + showDate(min, tz));
System.out.println(tz.getID() + " After: " + showDate(max, tz));
long mindelta = expectedBoundary - min;
long maxdelta = max - expectedBoundary;
if (mindelta >= 0 && mindelta <= INTERVAL &&
mindelta >= 0 && mindelta <= INTERVAL)
System.out.println("PASS: Expected boundary at " + expectedBoundary);
else
fail("FAIL: Expected boundary at " + expectedBoundary);
}
private static String showDate(long l)
{
return showDate(new Date(l));
}
@SuppressWarnings("deprecation")
private static String showDate(Date d)
{
return "" + d.getYear() + "/" + showNN(d.getMonth()+1) + "/" + showNN(d.getDate()) +
" " + showNN(d.getHours()) + ":" + showNN(d.getMinutes()) +
" \"" + d + "\" = " +
d.getTime();
}
private static String showDate(long l, TimeZone z)
{
return showDate(new Date(l), z);
}
@SuppressWarnings("deprecation")
private static String showDate(Date d, TimeZone zone)
{
DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
fmt.setTimeZone(zone);
return "" + d.getYear() + "/" + showNN(d.getMonth()+1) + "/" + showNN(d.getDate()) +
" " + showNN(d.getHours()) + ":" + showNN(d.getMinutes()) +
" \"" + d + "\" = " +
fmt.format(d);
}
private static String showNN(int n)
{
return ((n < 10) ? "0" : "") + n;
}
/**
* Given a date, a TimeZone, and expected values for inDaylightTime,
* useDaylightTime, zone and DST offset, verify that this is the case.
*/
void verifyDST(Date d, TimeZone time_zone,
boolean expUseDaylightTime, boolean expInDaylightTime,
int expZoneOffset, int expDSTOffset)
{
System.out.println("-- Verifying time " + d +
" in zone " + time_zone.getID());
if (time_zone.inDaylightTime(d) == expInDaylightTime)
System.out.println("PASS: inDaylightTime = " + time_zone.inDaylightTime(d));
else
fail("FAIL: inDaylightTime = " + time_zone.inDaylightTime(d));
if (time_zone.useDaylightTime() == expUseDaylightTime)
System.out.println("PASS: useDaylightTime = " + time_zone.useDaylightTime());
else
fail("FAIL: useDaylightTime = " + time_zone.useDaylightTime());
if (time_zone.getRawOffset() == expZoneOffset)
System.out.println("PASS: getRawOffset() = " + expZoneOffset/(double)ONE_HOUR);
else
fail("FAIL: getRawOffset() = " + time_zone.getRawOffset()/(double)ONE_HOUR +
"; expected " + expZoneOffset/(double)ONE_HOUR);
GregorianCalendar gc = new GregorianCalendar(time_zone);
gc.setTime(d);
int offset = time_zone.getOffset(gc.get(gc.ERA), gc.get(gc.YEAR), gc.get(gc.MONTH),
gc.get(gc.DAY_OF_MONTH), gc.get(gc.DAY_OF_WEEK),
((gc.get(gc.HOUR_OF_DAY) * 60 +
gc.get(gc.MINUTE)) * 60 +
gc.get(gc.SECOND)) * 1000 +
gc.get(gc.MILLISECOND));
if (offset == expDSTOffset)
System.out.println("PASS: getOffset() = " + offset/(double)ONE_HOUR);
else
fail("FAIL: getOffset() = " + offset/(double)ONE_HOUR +
"; expected " + expDSTOffset/(double)ONE_HOUR);
}
@SuppressWarnings("deprecation")
@Test
public void TestBoundaries()
{
TimeZone pst = TimeZone.getTimeZone("America/Los_Angeles");
TimeZone save = TimeZone.getDefault();
try {
TimeZone.setDefault(pst);
// DST changeover for PST is 4/6/1997 at 2 hours past midnight
Date d = new Date(97,Calendar.APRIL,6);
// i is minutes past midnight standard time
for (int i=60; i<=180; i+=15)
{
boolean inDST = (i >= 120);
Date e = new Date(d.getTime() + i*60*1000);
verifyDST(e, pst, true, inDST, -8*ONE_HOUR,
inDST ? -7*ONE_HOUR : -8*ONE_HOUR);
}
System.out.println("========================================");
findDaylightBoundaryUsingDate(new Date(97,0,1), "PST", PST_1997_BEG);
System.out.println("========================================");
findDaylightBoundaryUsingDate(new Date(97,6,1), "PDT", PST_1997_END);
// Southern hemisphere test
System.out.println("========================================");
TimeZone z = TimeZone.getTimeZone(AUSTRALIA);
findDaylightBoundaryUsingTimeZone(new Date(97,0,1), true, AUSTRALIA_1997_END, z);
System.out.println("========================================");
findDaylightBoundaryUsingTimeZone(new Date(97,0,1), false, PST_1997_BEG);
System.out.println("========================================");
findDaylightBoundaryUsingTimeZone(new Date(97,6,1), true, PST_1997_END);
} finally {
TimeZone.setDefault(save);
}
}
void testUsingBinarySearch(SimpleTimeZone tz, Date d, long expectedBoundary)
{
// Given a date with a year start, find the Daylight onset
// and end. The given date should be 1/1/xx in some year.
// Use a binary search, assuming that we have a Standard
// time at the midpoint.
long min = d.getTime();
long max = min + (long)(365.25 / 2 * ONE_DAY);
// First check the boundaries
boolean startsInDST = tz.inDaylightTime(d);
if (tz.inDaylightTime(new Date(max)) == startsInDST)
{
System.out.println("Error: inDaylightTime(" + (new Date(max)) + ") != " + (!startsInDST));
}
while ((max - min) > INTERVAL)
{
long mid = (min + max) >> 1;
if (tz.inDaylightTime(new Date(mid)) == startsInDST)
{
min = mid;
}
else
{
max = mid;
}
}
System.out.println("Binary Search Before: " + showDate(min));
System.out.println("Binary Search After: " + showDate(max));
long mindelta = expectedBoundary - min;
long maxdelta = max - expectedBoundary;
if (mindelta >= 0 && mindelta <= INTERVAL &&
mindelta >= 0 && mindelta <= INTERVAL)
System.out.println("PASS: Expected boundary at " + expectedBoundary);
else
fail("FAIL: Expected boundary at " + expectedBoundary);
}
/**
* Test new rule formats.
*/
@SuppressWarnings("deprecation")
@Test
public void TestNewRules() {
// Doesn't matter what the default TimeZone is here, since we
// are creating our own TimeZone objects.
SimpleTimeZone tz;
System.out.println("-----------------------------------------------------------------");
System.out.println("Aug 2ndTues .. Mar 15");
tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_1",
Calendar.AUGUST, 2, Calendar.TUESDAY, 2*ONE_HOUR,
Calendar.MARCH, 15, 0, 2*ONE_HOUR);
System.out.println("========================================");
testUsingBinarySearch(tz, new Date(97,0,1), 858416400000L);
System.out.println("========================================");
testUsingBinarySearch(tz, new Date(97,6,1), 871380000000L);
System.out.println("-----------------------------------------------------------------");
System.out.println("Apr Wed>=14 .. Sep Sun<=20");
tz = new SimpleTimeZone(-8*ONE_HOUR, "Test_2",
Calendar.APRIL, 14, -Calendar.WEDNESDAY, 2*ONE_HOUR,
Calendar.SEPTEMBER, -20, -Calendar.SUNDAY, 2*ONE_HOUR);
System.out.println("========================================");
testUsingBinarySearch(tz, new Date(97,0,1), 861184800000L);
System.out.println("========================================");
testUsingBinarySearch(tz, new Date(97,6,1), 874227600000L);
}
/**
* Find boundaries by stepping.
*/
@SuppressWarnings("deprecation")
void findBoundariesStepwise(int year, long interval, TimeZone z, int expectedChanges)
{
Date d = new Date(year - 1900, Calendar.JANUARY, 1);
long time = d.getTime(); // ms
long limit = time + ONE_YEAR + ONE_DAY;
boolean lastState = z.inDaylightTime(d);
int changes = 0;
System.out.println("-- Zone " + z.getID() + " starts in " + year + " with DST = " + lastState);
System.out.println("useDaylightTime = " + z.useDaylightTime());
while (time < limit)
{
d.setTime(time);
boolean state = z.inDaylightTime(d);
if (state != lastState)
{
System.out.println((state ? "Entry " : "Exit ") +
"at " + d);
lastState = state;
++changes;
}
time += interval;
}
if (changes == 0)
{
if (!lastState && !z.useDaylightTime()) System.out.println("No DST");
else fail("FAIL: Timezone<" + z.getID() + "> DST all year, or no DST with true useDaylightTime");
}
else if (changes != 2)
{
fail("FAIL: Timezone<" + z.getID() + "> " + changes + " changes seen; should see 0 or 2");
}
else if (!z.useDaylightTime())
{
fail("FAIL: Timezone<" + z.getID() + "> useDaylightTime false but 2 changes seen");
}
if (changes != expectedChanges)
{
fail("FAIL: Timezone<" + z.getID() + "> " + changes + " changes seen; expected " + expectedChanges);
}
}
@Test
public void TestStepwise()
{
findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("Australia/Darwin"), 0);
findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("Pacific/Honolulu"), 0);
findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("PST8PDT"), 2);
findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("SystemV/PST"), 0);
findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("SystemV/PST8PDT"), 2);
findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("Japan"), 0);
findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("Europe/Paris"), 2);
findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone("America/Los_Angeles"), 2);
findBoundariesStepwise(1997, ONE_DAY, TimeZone.getTimeZone(AUSTRALIA), 2);
}
}

View file

@ -0,0 +1 @@
tzdata2026a

View file

@ -0,0 +1,256 @@
Link Australia/Sydney Australia/ACT #= Australia/Canberra
Link Australia/Lord_Howe Australia/LHI
Link Australia/Sydney Australia/NSW
Link Australia/Darwin Australia/North
Link Australia/Brisbane Australia/Queensland
Link Australia/Adelaide Australia/South
Link Australia/Hobart Australia/Tasmania
Link Australia/Melbourne Australia/Victoria
Link Australia/Perth Australia/West
Link Australia/Broken_Hill Australia/Yancowinna
Link America/Rio_Branco Brazil/Acre #= America/Porto_Acre
Link America/Noronha Brazil/DeNoronha
Link America/Sao_Paulo Brazil/East
Link America/Manaus Brazil/West
Link Europe/Brussels CET
Link America/Chicago CST6CDT
Link America/Halifax Canada/Atlantic
Link America/Winnipeg Canada/Central
Link America/Toronto Canada/Eastern
Link America/Edmonton Canada/Mountain
Link America/St_Johns Canada/Newfoundland
Link America/Vancouver Canada/Pacific
Link America/Regina Canada/Saskatchewan
Link America/Whitehorse Canada/Yukon
Link America/Santiago Chile/Continental
Link Pacific/Easter Chile/EasterIsland
Link America/Havana Cuba
Link Europe/Athens EET
Link America/Panama EST
Link America/New_York EST5EDT
Link Africa/Cairo Egypt
Link Europe/Dublin Eire
Link Etc/GMT Etc/GMT+0
Link Etc/GMT Etc/GMT-0
Link Etc/GMT Etc/GMT0
Link Etc/GMT Etc/Greenwich
Link Etc/UTC Etc/UCT
Link Etc/UTC Etc/Universal
Link Etc/UTC Etc/Zulu
Link Europe/London GB
Link Europe/London GB-Eire
Link Etc/GMT GMT+0
Link Etc/GMT GMT-0
Link Etc/GMT GMT0
Link Etc/GMT Greenwich
Link Asia/Hong_Kong Hongkong
Link Africa/Abidjan Iceland #= Atlantic/Reykjavik
Link Asia/Tehran Iran
Link Asia/Jerusalem Israel
Link America/Jamaica Jamaica
Link Asia/Tokyo Japan
Link Pacific/Kwajalein Kwajalein
Link Africa/Tripoli Libya
Link Europe/Brussels MET
Link America/Phoenix MST
Link America/Denver MST7MDT
Link America/Tijuana Mexico/BajaNorte
Link America/Mazatlan Mexico/BajaSur
Link America/Mexico_City Mexico/General
Link Pacific/Auckland NZ
Link Pacific/Chatham NZ-CHAT
Link America/Denver Navajo #= America/Shiprock
Link Asia/Shanghai PRC
Link Europe/Warsaw Poland
Link Europe/Lisbon Portugal
Link Asia/Taipei ROC
Link Asia/Seoul ROK
Link Asia/Singapore Singapore
Link Europe/Istanbul Turkey
Link Etc/UTC UCT
Link America/Anchorage US/Alaska
Link America/Adak US/Aleutian
Link America/Phoenix US/Arizona
Link America/Chicago US/Central
Link America/Indiana/Indianapolis US/East-Indiana
Link America/New_York US/Eastern
Link Pacific/Honolulu US/Hawaii
Link America/Indiana/Knox US/Indiana-Starke
Link America/Detroit US/Michigan
Link America/Denver US/Mountain
Link America/Los_Angeles US/Pacific
Link Pacific/Pago_Pago US/Samoa
Link Etc/UTC UTC
Link Etc/UTC Universal
Link Europe/Moscow W-SU
Link Etc/UTC Zulu
Link America/Argentina/Buenos_Aires America/Buenos_Aires
Link America/Argentina/Catamarca America/Catamarca
Link America/Argentina/Cordoba America/Cordoba
Link America/Indiana/Indianapolis America/Indianapolis
Link America/Argentina/Jujuy America/Jujuy
Link America/Indiana/Knox America/Knox_IN
Link America/Kentucky/Louisville America/Louisville
Link America/Argentina/Mendoza America/Mendoza
Link America/Puerto_Rico America/Virgin #= America/St_Thomas
Link Pacific/Pago_Pago Pacific/Samoa
Link Africa/Abidjan Africa/Accra
Link Africa/Nairobi Africa/Addis_Ababa
Link Africa/Nairobi Africa/Asmara
Link Africa/Abidjan Africa/Bamako
Link Africa/Lagos Africa/Bangui
Link Africa/Abidjan Africa/Banjul
Link Africa/Maputo Africa/Blantyre
Link Africa/Lagos Africa/Brazzaville
Link Africa/Maputo Africa/Bujumbura
Link Africa/Abidjan Africa/Conakry
Link Africa/Abidjan Africa/Dakar
Link Africa/Nairobi Africa/Dar_es_Salaam
Link Africa/Nairobi Africa/Djibouti
Link Africa/Lagos Africa/Douala
Link Africa/Abidjan Africa/Freetown
Link Africa/Maputo Africa/Gaborone
Link Africa/Maputo Africa/Harare
Link Africa/Nairobi Africa/Kampala
Link Africa/Maputo Africa/Kigali
Link Africa/Lagos Africa/Kinshasa
Link Africa/Lagos Africa/Libreville
Link Africa/Abidjan Africa/Lome
Link Africa/Lagos Africa/Luanda
Link Africa/Maputo Africa/Lubumbashi
Link Africa/Maputo Africa/Lusaka
Link Africa/Lagos Africa/Malabo
Link Africa/Johannesburg Africa/Maseru
Link Africa/Johannesburg Africa/Mbabane
Link Africa/Nairobi Africa/Mogadishu
Link Africa/Lagos Africa/Niamey
Link Africa/Abidjan Africa/Nouakchott
Link Africa/Abidjan Africa/Ouagadougou
Link Africa/Lagos Africa/Porto-Novo
Link America/Puerto_Rico America/Anguilla
Link America/Puerto_Rico America/Antigua
Link America/Puerto_Rico America/Aruba
Link America/Panama America/Atikokan
Link America/Puerto_Rico America/Blanc-Sablon
Link America/Panama America/Cayman
Link America/Phoenix America/Creston
Link America/Puerto_Rico America/Curacao
Link America/Puerto_Rico America/Dominica
Link America/Puerto_Rico America/Grenada
Link America/Puerto_Rico America/Guadeloupe
Link America/Puerto_Rico America/Kralendijk
Link America/Puerto_Rico America/Lower_Princes
Link America/Puerto_Rico America/Marigot
Link America/Puerto_Rico America/Montserrat
Link America/Toronto America/Nassau
Link America/Puerto_Rico America/Port_of_Spain
Link America/Puerto_Rico America/St_Barthelemy
Link America/Puerto_Rico America/St_Kitts
Link America/Puerto_Rico America/St_Lucia
Link America/Puerto_Rico America/St_Thomas
Link America/Puerto_Rico America/St_Vincent
Link America/Puerto_Rico America/Tortola
Link Pacific/Port_Moresby Antarctica/DumontDUrville
Link Pacific/Auckland Antarctica/McMurdo
Link Asia/Riyadh Antarctica/Syowa
Link Europe/Berlin Arctic/Longyearbyen
Link Asia/Riyadh Asia/Aden
Link Asia/Qatar Asia/Bahrain
Link Asia/Kuching Asia/Brunei
Link Asia/Singapore Asia/Kuala_Lumpur
Link Asia/Riyadh Asia/Kuwait
Link Asia/Dubai Asia/Muscat
Link Asia/Bangkok Asia/Phnom_Penh
Link Asia/Bangkok Asia/Vientiane
Link Africa/Abidjan Atlantic/Reykjavik
Link Africa/Abidjan Atlantic/St_Helena
Link Europe/Brussels Europe/Amsterdam
Link Europe/Prague Europe/Bratislava
Link Europe/Zurich Europe/Busingen
Link Europe/Berlin Europe/Copenhagen
Link Europe/London Europe/Guernsey
Link Europe/London Europe/Isle_of_Man
Link Europe/London Europe/Jersey
Link Europe/Belgrade Europe/Ljubljana
Link Europe/Brussels Europe/Luxembourg
Link Europe/Helsinki Europe/Mariehamn
Link Europe/Paris Europe/Monaco
Link Europe/Berlin Europe/Oslo
Link Europe/Belgrade Europe/Podgorica
Link Europe/Rome Europe/San_Marino
Link Europe/Belgrade Europe/Sarajevo
Link Europe/Belgrade Europe/Skopje
Link Europe/Berlin Europe/Stockholm
Link Europe/Zurich Europe/Vaduz
Link Europe/Rome Europe/Vatican
Link Europe/Belgrade Europe/Zagreb
Link Africa/Nairobi Indian/Antananarivo
Link Asia/Bangkok Indian/Christmas
Link Asia/Yangon Indian/Cocos
Link Africa/Nairobi Indian/Comoro
Link Indian/Maldives Indian/Kerguelen
Link Asia/Dubai Indian/Mahe
Link Africa/Nairobi Indian/Mayotte
Link Asia/Dubai Indian/Reunion
Link Pacific/Port_Moresby Pacific/Chuuk
Link Pacific/Tarawa Pacific/Funafuti
Link Pacific/Tarawa Pacific/Majuro
Link Pacific/Pago_Pago Pacific/Midway
Link Pacific/Guadalcanal Pacific/Pohnpei
Link Pacific/Guam Pacific/Saipan
Link Pacific/Tarawa Pacific/Wake
Link Pacific/Tarawa Pacific/Wallis
Link Africa/Abidjan Africa/Timbuktu
Link America/Argentina/Catamarca America/Argentina/ComodRivadavia
Link America/Adak America/Atka
Link America/Panama America/Coral_Harbour
Link America/Tijuana America/Ensenada
Link America/Indiana/Indianapolis America/Fort_Wayne
Link America/Toronto America/Montreal
Link America/Toronto America/Nipigon
Link America/Iqaluit America/Pangnirtung
Link America/Rio_Branco America/Porto_Acre
Link America/Winnipeg America/Rainy_River
Link America/Argentina/Cordoba America/Rosario
Link America/Tijuana America/Santa_Isabel
Link America/Denver America/Shiprock
Link America/Toronto America/Thunder_Bay
Link America/Edmonton America/Yellowknife
Link Pacific/Auckland Antarctica/South_Pole
Link Asia/Ulaanbaatar Asia/Choibalsan
Link Asia/Shanghai Asia/Chongqing
Link Asia/Shanghai Asia/Harbin
Link Asia/Urumqi Asia/Kashgar
Link Asia/Jerusalem Asia/Tel_Aviv
Link Europe/Berlin Atlantic/Jan_Mayen
Link Australia/Sydney Australia/Canberra
Link Australia/Hobart Australia/Currie
Link Europe/London Europe/Belfast
Link Europe/Chisinau Europe/Tiraspol
Link Europe/Kyiv Europe/Uzhgorod
Link Europe/Kyiv Europe/Zaporozhye
Link Pacific/Kanton Pacific/Enderbury
Link Pacific/Honolulu Pacific/Johnston
Link Pacific/Port_Moresby Pacific/Yap
Link Europe/Lisbon WET
Link Africa/Nairobi Africa/Asmera #= Africa/Asmara
Link America/Nuuk America/Godthab
Link Asia/Ashgabat Asia/Ashkhabad
Link Asia/Kolkata Asia/Calcutta
Link Asia/Shanghai Asia/Chungking #= Asia/Chongqing
Link Asia/Dhaka Asia/Dacca
Link Europe/Istanbul Asia/Istanbul
Link Asia/Kathmandu Asia/Katmandu
Link Asia/Macau Asia/Macao
Link Asia/Yangon Asia/Rangoon
Link Asia/Ho_Chi_Minh Asia/Saigon
Link Asia/Thimphu Asia/Thimbu
Link Asia/Makassar Asia/Ujung_Pandang
Link Asia/Ulaanbaatar Asia/Ulan_Bator
Link Atlantic/Faroe Atlantic/Faeroe
Link Europe/Kyiv Europe/Kiev
Link Asia/Nicosia Europe/Nicosia
Link Pacific/Honolulu HST
Link America/Los_Angeles PST8PDT
Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei
Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk

View file

@ -0,0 +1,160 @@
Africa/Abidjan GMT
Africa/Algiers CET
Africa/Bissau GMT
Africa/Cairo EET EEST
Africa/Ceuta CET CEST
Africa/Johannesburg SAST
Africa/Juba CAT
Africa/Khartoum CAT
Africa/Lagos WAT
Africa/Maputo CAT
Africa/Monrovia GMT
Africa/Nairobi EAT
Africa/Ndjamena WAT
Africa/Sao_Tome GMT
Africa/Tripoli EET
Africa/Tunis CET CEST
America/Anchorage AKST AKDT
America/Bahia_Banderas CST CDT
America/Barbados AST ADT
America/Belize CST CDT
America/Boise MST MDT
America/Cambridge_Bay MST MDT
America/Cancun EST
America/Chicago CST CDT
America/Chihuahua CST
America/Ciudad_Juarez MST MDT
America/Costa_Rica CST CDT
America/Danmarkshavn GMT
America/Dawson MST
America/Dawson_Creek MST
America/Denver MST MDT
America/Detroit EST EDT
America/Edmonton MST MDT
America/El_Salvador CST CDT
America/Fort_Nelson MST
America/Glace_Bay AST ADT
America/Goose_Bay AST ADT
America/Grand_Turk EST EDT
America/Guatemala CST CDT
America/Halifax AST ADT
America/Havana CST CDT
America/Hermosillo MST
America/Indiana/Indianapolis EST EDT
America/Indiana/Knox CST CDT
America/Indiana/Marengo EST EDT
America/Indiana/Petersburg EST EDT
America/Indiana/Tell_City CST CDT
America/Indiana/Vevay EST EDT
America/Indiana/Vincennes EST EDT
America/Indiana/Winamac EST EDT
America/Inuvik MST MDT
America/Iqaluit EST EDT
America/Jamaica EST
America/Juneau AKST AKDT
America/Kentucky/Louisville EST EDT
America/Kentucky/Monticello EST EDT
America/Los_Angeles PST PDT
America/Managua CST CDT
America/Martinique AST
America/Matamoros CST CDT
America/Mazatlan MST MDT
America/Menominee CST CDT
America/Merida CST CDT
America/Metlakatla AKST AKDT
America/Mexico_City CST CDT
America/Moncton AST ADT
America/Monterrey CST CDT
America/New_York EST EDT
America/Nome AKST AKDT
America/North_Dakota/Beulah CST CDT
America/North_Dakota/Center CST CDT
America/North_Dakota/New_Salem CST CDT
America/Ojinaga CST CDT
America/Panama EST
America/Phoenix MST
America/Port-au-Prince EST EDT
America/Puerto_Rico AST
America/Rankin_Inlet CST CDT
America/Regina CST
America/Resolute CST CDT
America/Santo_Domingo AST
America/Sitka AKST AKDT
America/St_Johns NST NDT
America/Swift_Current CST
America/Tegucigalpa CST CDT
America/Thule AST ADT
America/Tijuana PST PDT
America/Toronto EST EDT
America/Vancouver PST PDT
America/Whitehorse MST
America/Winnipeg CST CDT
America/Yakutat AKST AKDT
Antarctica/Macquarie AEST AEDT
Asia/Beirut EET EEST
Asia/Famagusta EET EEST
Asia/Gaza EET EEST
Asia/Hebron EET EEST
Asia/Hong_Kong HKT HKST
Asia/Jakarta WIB
Asia/Jayapura WIT
Asia/Jerusalem IST IDT
Asia/Karachi PKT PKST
Asia/Kolkata IST
Asia/Macau CST CDT
Asia/Makassar WITA
Asia/Manila PST PDT
Asia/Nicosia EET EEST
Asia/Pontianak WIB
Asia/Shanghai CST CDT
Asia/Taipei CST CDT
Asia/Tokyo JST JDT
Atlantic/Bermuda AST ADT
Atlantic/Canary WET WEST
Atlantic/Faroe WET WEST
Atlantic/Madeira WET WEST
Australia/Adelaide ACST ACDT
Australia/Brisbane AEST AEDT
Australia/Broken_Hill ACST ACDT
Australia/Darwin ACST ACDT
Australia/Hobart AEST AEDT
Australia/Lindeman AEST AEDT
Australia/Melbourne AEST AEDT
Australia/Perth AWST AWDT
Australia/Sydney AEST AEDT
Europe/Andorra CET CEST
Europe/Athens EET EEST
Europe/Belgrade CET CEST
Europe/Berlin CET CEST
Europe/Brussels CET CEST
Europe/Bucharest EET EEST
Europe/Budapest CET CEST
Europe/Chisinau EET EEST
Europe/Dublin IST/GMT IST/GMT
Europe/Gibraltar CET CEST
Europe/Helsinki EET EEST
Europe/Kaliningrad EET
Europe/Kirov MSK
Europe/Kyiv EET EEST
Europe/Lisbon WET WEST
Europe/London GMT/BST GMT/BST
Europe/Madrid CET CEST
Europe/Malta CET CEST
Europe/Moscow MSK
Europe/Paris CET CEST
Europe/Prague CET CEST
Europe/Riga EET EEST
Europe/Rome CET CEST
Europe/Simferopol MSK
Europe/Sofia EET EEST
Europe/Tallinn EET EEST
Europe/Tirane CET CEST
Europe/Vienna CET CEST
Europe/Vilnius EET EEST
Europe/Volgograd MSK
Europe/Warsaw CET CEST
Europe/Zurich CET CEST
Pacific/Auckland NZST NZDT
Pacific/Guam ChST
Pacific/Honolulu HST
Pacific/Pago_Pago SST

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,758 @@
/*
* Copyright (c) 1997, 2024, 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 4028006 4044013 4096694 4107276 4107570 4112869 4130885 7039469 7126465 7158483
* 8008577 8077685 8098547 8133321 8138716 8148446 8151876 8159684 8166875 8181157
* 8228469 8274407 8285844 8305113 8174269
* @modules java.base/sun.util.resources
* @summary test TimeZone
* @run junit TimeZoneTest
*/
import java.io.*;
import java.text.*;
import java.util.*;
import sun.util.resources.LocaleData;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class TimeZoneTest
{
static final int millisPerHour = 3600000;
/**
* Bug 4130885
* Certain short zone IDs, used since 1.1.x, are incorrect.
*
* The worst of these is:
*
* "CAT" (Central African Time) should be GMT+2:00, but instead returns a
* zone at GMT-1:00. The zone at GMT-1:00 should be called EGT, CVT, EGST,
* or AZOST, depending on which zone is meant, but in no case is it CAT.
*
* Other wrong zone IDs:
*
* ECT (European Central Time) GMT+1:00: ECT is Ecuador Time,
* GMT-5:00. European Central time is abbreviated CEST.
*
* SST (Solomon Island Time) GMT+11:00. SST is actually Samoa Standard Time,
* GMT-11:00. Solomon Island time is SBT.
*
* NST (New Zealand Time) GMT+12:00. NST is the abbreviation for
* Newfoundland Standard Time, GMT-3:30. New Zealanders use NZST.
*
* AST (Alaska Standard Time) GMT-9:00. [This has already been noted in
* another bug.] It should be "AKST". AST is Atlantic Standard Time,
* GMT-4:00.
*
* PNT (Phoenix Time) GMT-7:00. PNT usually means Pitcairn Time,
* GMT-8:30. There is no standard abbreviation for Phoenix time, as distinct
* from MST with daylight savings.
*
* In addition to these problems, a number of zones are FAKE. That is, they
* don't match what people use in the real world.
*
* FAKE zones:
*
* EET (should be EEST)
* ART (should be EET)
* MET (should be IRST)
* NET (should be AMST)
* PLT (should be PKT)
* BST (should be BDT)
* VST (should be ICT)
* CTT (should be CST) +
* ACT (should be CST) +
* AET (should be EST) +
* MIT (should be WST) +
* IET (should be EST) +
* PRT (should be AST) +
* CNT (should be NST)
* AGT (should be ARST)
* BET (should be EST) +
*
* + A zone with the correct name already exists and means something
* else. E.g., EST usually indicates the US Eastern zone, so it cannot be
* used for Brazil (BET).
*/
@Test
public void TestShortZoneIDs() throws Exception {
ZoneDescriptor[] JDK_116_REFERENCE_LIST = {
new ZoneDescriptor("MIT", 780, false), // Samoa no longer observes DST starting 2021b
new ZoneDescriptor("HST", -600, false),
new ZoneDescriptor("AST", -540, true),
new ZoneDescriptor("PST", -480, true),
new ZoneDescriptor("PNT", -420, false),
new ZoneDescriptor("MST", -420, false),
new ZoneDescriptor("CST", -360, true),
new ZoneDescriptor("IET", -300, true),
new ZoneDescriptor("EST", -300, false),
new ZoneDescriptor("PRT", -240, false),
new ZoneDescriptor("CNT", -210, true),
new ZoneDescriptor("AGT", -180, false),
new ZoneDescriptor("BET", -180, false),
// new ZoneDescriptor("CAT", -60, false), // Wrong:
// As of bug 4130885, fix CAT (Central Africa)
new ZoneDescriptor("CAT", 120, false), // Africa/Harare
new ZoneDescriptor("GMT", 0, false),
new ZoneDescriptor("UTC", 0, false),
new ZoneDescriptor("ECT", 60, true),
new ZoneDescriptor("ART", 120, true),
new ZoneDescriptor("EET", 120, true),
new ZoneDescriptor("EAT", 180, false),
new ZoneDescriptor("MET", 60, true),
new ZoneDescriptor("NET", 240, false),
new ZoneDescriptor("PLT", 300, false),
new ZoneDescriptor("IST", 330, false),
new ZoneDescriptor("BST", 360, false),
new ZoneDescriptor("VST", 420, false),
new ZoneDescriptor("CTT", 480, false),
new ZoneDescriptor("JST", 540, false),
new ZoneDescriptor("ACT", 570, false),
new ZoneDescriptor("AET", 600, true),
new ZoneDescriptor("SST", 660, false),
// new ZoneDescriptor("NST", 720, false),
// As of bug 4130885, fix NST (New Zealand)
new ZoneDescriptor("NST", 720, true), // Pacific/Auckland
};
Map<String, ZoneDescriptor> hash = new HashMap<>();
String[] ids = TimeZone.getAvailableIDs();
for (String id : ids) {
if (id.length() == 3) {
hash.put(id, new ZoneDescriptor(TimeZone.getTimeZone(id)));
}
}
for (int i = 0; i < JDK_116_REFERENCE_LIST.length; ++i) {
ZoneDescriptor referenceZone = JDK_116_REFERENCE_LIST[i];
ZoneDescriptor currentZone = hash.get(referenceZone.getID());
if (referenceZone.equals(currentZone)) {
System.out.println("ok " + referenceZone);
}
else {
fail("Fail: Expected " + referenceZone +
"; got " + currentZone);
}
}
}
/**
* A descriptor for a zone; used to regress the short zone IDs.
*/
static class ZoneDescriptor {
String id;
int offset; // In minutes
boolean daylight;
ZoneDescriptor(TimeZone zone) {
this.id = zone.getID();
this.offset = zone.getRawOffset() / 60000;
this.daylight = zone.useDaylightTime();
}
ZoneDescriptor(String id, int offset, boolean daylight) {
this.id = id;
this.offset = offset;
this.daylight = daylight;
}
public String getID() { return id; }
@Override
public boolean equals(Object o) {
ZoneDescriptor that = (ZoneDescriptor)o;
return that != null &&
id.equals(that.id) &&
offset == that.offset &&
daylight == that.daylight;
}
@Override
public int hashCode() {
return id.hashCode() ^ offset | (daylight ? 1 : 0);
}
@Override
public String toString() {
int min = offset;
char sign = '+';
if (min < 0) { sign = '-'; min = -min; }
return "Zone[\"" + id + "\", GMT" + sign + (min/60) + ':' +
(min%60<10?"0":"") + (min%60) + ", " +
(daylight ? "Daylight" : "Standard") + "]";
}
public static int compare(Object o1, Object o2) {
ZoneDescriptor i1 = (ZoneDescriptor)o1;
ZoneDescriptor i2 = (ZoneDescriptor)o2;
if (i1.offset > i2.offset) return 1;
if (i1.offset < i2.offset) return -1;
if (i1.daylight && !i2.daylight) return 1;
if (!i1.daylight && i2.daylight) return -1;
return i1.id.compareTo(i2.id);
}
}
static final String formatSeconds(int sec) {
char sign = '+';
if (sec < 0) { sign = '-'; sec = -sec; }
int h = sec / 3_600;
int m = sec % 3_600 / 60;
sec = sec % 60;
return "" + sign + h + ":" + ((m<10) ? "0" : "") + m +
(sec > 0 ? ":" + ((sec < 10) ? "0" : "") + sec : "");
}
/**
* As part of the VM fix (see CCC approved RFE 4028006, bug
* 4044013), TimeZone.getTimeZone() has been modified to recognize
* generic IDs of the form GMT[+-]hh:mm, GMT[+-]hhmm, and
* GMT[+-]hh. Test this behavior here.
*
* Bug 4044013
*
* ID "Custom" is no longer used for TimeZone objects created with
* a custom time zone ID, such as "GMT-8". See 4322313.
*/
@Test
public void TestCustomParse() throws Exception {
Object[] DATA = {
// ID Expected offset in seconds
"GMT", null,
"GMT+0", 0,
"GMT+1", 60 * 60,
"GMT-0030", -30 * 60,
"GMT+15:99", null,
"GMT+", null,
"GMT-", null,
"GMT+0:", null,
"GMT-:", null,
"GMT+0010", 10 * 60, // Interpret this as 00:10
"GMT-10", -10 * 60 * 60,
"GMT+30", null,
"GMT-3:30", -(3 * 60 + 30) * 60,
"GMT-230", -(2 * 60 + 30) * 60,
"GMT+00:00:01", 1,
"GMT-00:00:01", -1,
"GMT+00000", null,
"GMT+00:00:01:", null,
"GMT+00:00:012", null,
"GMT+00:00:0", null,
"GMT+00:00:", null,
};
for (int i=0; i<DATA.length; i+=2) {
String id = (String)DATA[i];
Integer exp = (Integer)DATA[i+1];
TimeZone zone = TimeZone.getTimeZone(id);
if (zone.getID().equals("GMT")) {
System.out.println(id + " -> generic GMT");
// When TimeZone.getTimeZone() can't parse the id, it
// returns GMT -- a dubious practice, but required for
// backward compatibility.
if (exp != null) {
throw new Exception("Expected offset of " + formatSeconds(exp.intValue()) +
" for " + id + ", got parse failure");
}
}
else {
int ioffset = zone.getRawOffset() / 1_000;
String offset = formatSeconds(ioffset);
System.out.println(id + " -> " + zone.getID() + " GMT" + offset);
if (exp == null) {
throw new Exception("Expected parse failure for " + id +
", got offset of " + offset +
", id " + zone.getID());
}
else if (ioffset != exp.intValue()) {
throw new Exception("Expected offset of " + formatSeconds(exp.intValue()) +
", id Custom, for " + id +
", got offset of " + offset +
", id " + zone.getID());
}
}
}
}
/**
* Test the basic functionality of the getDisplayName() API.
*
* Bug 4112869
* Bug 4028006
*
* See also API change request A41.
*
* 4/21/98 - make smarter, so the test works if the ext resources
* are present or not.
*/
@Test
public void TestDisplayName() {
TimeZone zone = TimeZone.getTimeZone("PST");
String name = zone.getDisplayName(Locale.ENGLISH);
System.out.println("PST->" + name);
if (!name.equals("Pacific Standard Time"))
fail("Fail: Expected \"Pacific Standard Time\"");
//*****************************************************************
// THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
// THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
// THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
//*****************************************************************
Object[] DATA = {
new Boolean(false), new Integer(TimeZone.SHORT), "PST",
new Boolean(true), new Integer(TimeZone.SHORT), "PDT",
new Boolean(false), new Integer(TimeZone.LONG), "Pacific Standard Time",
new Boolean(true), new Integer(TimeZone.LONG), "Pacific Daylight Time",
};
for (int i=0; i<DATA.length; i+=3) {
name = zone.getDisplayName(((Boolean)DATA[i]).booleanValue(),
((Integer)DATA[i+1]).intValue(),
Locale.ENGLISH);
if (!name.equals(DATA[i+2]))
fail("Fail: Expected " + DATA[i+2] + "; got " + name);
}
// Make sure that we don't display the DST name by constructing a fake
// PST zone that has DST all year long.
SimpleTimeZone zone2 = new SimpleTimeZone(0, "PST");
zone2.setStartRule(Calendar.JANUARY, 1, 0);
zone2.setEndRule(Calendar.DECEMBER, 31, 0);
System.out.println("Modified PST inDaylightTime->" + zone2.inDaylightTime(new Date()));
name = zone2.getDisplayName(Locale.ENGLISH);
System.out.println("Modified PST->" + name);
if (!name.equals("Pacific Standard Time"))
fail("Fail: Expected \"Pacific Standard Time\"");
// Make sure we get the default display format for Locales
// with no display name data.
Locale zh_CN = Locale.SIMPLIFIED_CHINESE;
name = zone.getDisplayName(zh_CN);
//*****************************************************************
// THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
// THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
// THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
//*****************************************************************
System.out.println("PST(zh_CN)->" + name);
// Now be smart -- check to see if zh resource is even present.
// If not, we expect the en fallback behavior.
ResourceBundle enRB = LocaleData.getBundle("sun.util.resources.cldr.TimeZoneNames",
Locale.ENGLISH);
ResourceBundle zhRB = LocaleData.getBundle("sun.util.resources.cldr.TimeZoneNames",
zh_CN);
boolean noZH = enRB == zhRB;
if (noZH) {
System.out.println("Warning: Not testing the zh_CN behavior because resource is absent");
if (!name.equals("Pacific Standard Time"))
fail("Fail: Expected Pacific Standard Time");
}
else if (!name.equals("Pacific Standard Time") &&
!name.equals("\u592a\u5e73\u6d0b\u6807\u51c6\u65f6\u95f4") &&
!name.equals("\u5317\u7f8e\u592a\u5e73\u6d0b\u6807\u51c6\u65f6\u95f4") &&
!name.equals("GMT-08:00") &&
!name.equals("GMT-8:00") &&
!name.equals("GMT-0800") &&
!name.equals("GMT-800")) {
fail("Fail: Expected GMT-08:00 or something similar\n"
+ "************************************************************\n"
+ "THE ABOVE FAILURE MAY JUST MEAN THE LOCALE DATA HAS CHANGED\n"
+ "************************************************************\n");
}
// Now try a non-existent zone
zone2 = new SimpleTimeZone(90*60*1000, "xyzzy");
name = zone2.getDisplayName(Locale.ENGLISH);
System.out.println("GMT+90min->" + name);
if (!name.equals("GMT+01:30") &&
!name.equals("GMT+1:30") &&
!name.equals("GMT+0130") &&
!name.equals("GMT+130"))
fail("Fail: Expected GMT+01:30 or something similar");
}
@Test
public void TestGenericAPI() {
String id = "NewGMT";
int offset = 12345;
SimpleTimeZone zone = new SimpleTimeZone(offset, id);
if (zone.useDaylightTime()) {
fail("FAIL: useDaylightTime should return false");
}
TimeZone zoneclone = (TimeZone)zone.clone();
if (!zoneclone.equals(zone)) {
fail("FAIL: clone or operator== failed");
}
zoneclone.setID("abc");
if (zoneclone.equals(zone)) {
fail("FAIL: clone or operator!= failed");
}
zoneclone = (TimeZone)zone.clone();
if (!zoneclone.equals(zone)) {
fail("FAIL: clone or operator== failed");
}
zoneclone.setRawOffset(45678);
if (zoneclone.equals(zone)) {
fail("FAIL: clone or operator!= failed");
}
TimeZone saveDefault = TimeZone.getDefault();
try {
TimeZone.setDefault(zone);
TimeZone defaultzone = TimeZone.getDefault();
if (defaultzone == zone) {
fail("FAIL: Default object is identical, not clone");
}
if (!defaultzone.equals(zone)) {
fail("FAIL: Default object is not equal");
}
}
finally {
TimeZone.setDefault(saveDefault);
}
}
@SuppressWarnings("deprecation")
@Test
public void TestRuleAPI()
{
// ErrorCode status = ZERO_ERROR;
int offset = (int)(60*60*1000*1.75); // Pick a weird offset
SimpleTimeZone zone = new SimpleTimeZone(offset, "TestZone");
if (zone.useDaylightTime()) fail("FAIL: useDaylightTime should return false");
// Establish our expected transition times. Do this with a non-DST
// calendar with the (above) declared local offset.
GregorianCalendar gc = new GregorianCalendar(zone);
gc.clear();
gc.set(1990, Calendar.MARCH, 1);
long marchOneStd = gc.getTime().getTime(); // Local Std time midnight
gc.clear();
gc.set(1990, Calendar.JULY, 1);
long julyOneStd = gc.getTime().getTime(); // Local Std time midnight
// Starting and ending hours, WALL TIME
int startHour = (int)(2.25 * 3600000);
int endHour = (int)(3.5 * 3600000);
zone.setStartRule(Calendar.MARCH, 1, 0, startHour);
zone.setEndRule (Calendar.JULY, 1, 0, endHour);
gc = new GregorianCalendar(zone);
// if (failure(status, "new GregorianCalendar")) return;
long marchOne = marchOneStd + startHour;
long julyOne = julyOneStd + endHour - 3600000; // Adjust from wall to Std time
long expMarchOne = 636251400000L;
if (marchOne != expMarchOne)
{
fail("FAIL: Expected start computed as " + marchOne +
" = " + new Date(marchOne));
System.out.println(" Should be " + expMarchOne +
" = " + new Date(expMarchOne));
}
long expJulyOne = 646793100000L;
if (julyOne != expJulyOne)
{
fail("FAIL: Expected start computed as " + julyOne +
" = " + new Date(julyOne));
System.out.println(" Should be " + expJulyOne +
" = " + new Date(expJulyOne));
}
testUsingBinarySearch(zone, new Date(90, Calendar.JANUARY, 1).getTime(),
new Date(90, Calendar.JUNE, 15).getTime(), marchOne);
testUsingBinarySearch(zone, new Date(90, Calendar.JUNE, 1).getTime(),
new Date(90, Calendar.DECEMBER, 31).getTime(), julyOne);
if (zone.inDaylightTime(new Date(marchOne - 1000)) ||
!zone.inDaylightTime(new Date(marchOne)))
fail("FAIL: Start rule broken");
if (!zone.inDaylightTime(new Date(julyOne - 1000)) ||
zone.inDaylightTime(new Date(julyOne)))
fail("FAIL: End rule broken");
zone.setStartYear(1991);
if (zone.inDaylightTime(new Date(marchOne)) ||
zone.inDaylightTime(new Date(julyOne - 1000)))
fail("FAIL: Start year broken");
// failure(status, "TestRuleAPI");
// delete gc;
// delete zone;
}
void testUsingBinarySearch(SimpleTimeZone tz, long min, long max, long expectedBoundary)
{
// ErrorCode status = ZERO_ERROR;
boolean startsInDST = tz.inDaylightTime(new Date(min));
// if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
if (tz.inDaylightTime(new Date(max)) == startsInDST) {
System.out.println("Error: inDaylightTime(" + new Date(max) + ") != " + (!startsInDST));
return;
}
// if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
while ((max - min) > INTERVAL) {
long mid = (min + max) / 2;
if (tz.inDaylightTime(new Date(mid)) == startsInDST) {
min = mid;
}
else {
max = mid;
}
// if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
}
System.out.println("Binary Search Before: " + min + " = " + new Date(min));
System.out.println("Binary Search After: " + max + " = " + new Date(max));
long mindelta = expectedBoundary - min;
long maxdelta = max - expectedBoundary;
if (mindelta >= 0 &&
mindelta <= INTERVAL &&
mindelta >= 0 &&
mindelta <= INTERVAL)
System.out.println("PASS: Expected bdry: " + expectedBoundary + " = " + new Date(expectedBoundary));
else
fail("FAIL: Expected bdry: " + expectedBoundary + " = " + new Date(expectedBoundary));
}
static final int INTERVAL = 100;
// Bug 006; verify the offset for a specific zone.
@Test
public void TestPRTOffset()
{
TimeZone tz = TimeZone.getTimeZone( "PRT" );
if( tz == null ) {
fail( "FAIL: TimeZone(PRT) is null" );
}
else{
if (tz.getRawOffset() != (-4*millisPerHour))
fail("FAIL: Offset for PRT should be -4");
}
}
// Test various calls
@SuppressWarnings("deprecation")
@Test
public void TestVariousAPI518()
{
TimeZone time_zone = TimeZone.getTimeZone("PST");
Date d = new Date(97, Calendar.APRIL, 30);
System.out.println("The timezone is " + time_zone.getID());
if (time_zone.inDaylightTime(d) != true)
fail("FAIL: inDaylightTime returned false");
if (time_zone.useDaylightTime() != true)
fail("FAIL: useDaylightTime returned false");
if (time_zone.getRawOffset() != -8*millisPerHour)
fail( "FAIL: getRawOffset returned wrong value");
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(d);
if (time_zone.getOffset(gc.AD, gc.get(gc.YEAR), gc.get(gc.MONTH),
gc.get(gc.DAY_OF_MONTH),
gc.get(gc.DAY_OF_WEEK), 0)
!= -7*millisPerHour)
fail("FAIL: getOffset returned wrong value");
}
// Test getAvailableID API
@Test
public void TestGetAvailableIDs913()
{
StringBuffer buf = new StringBuffer("TimeZone.getAvailableIDs() = { ");
String[] s = TimeZone.getAvailableIDs();
for (int i=0; i<s.length; ++i)
{
if (i > 0) buf.append(", ");
buf.append(s[i]);
}
buf.append(" };");
System.out.println(buf.toString());
buf.setLength(0);
buf.append("TimeZone.getAvailableIDs(GMT+02:00) = { ");
s = TimeZone.getAvailableIDs(+2 * 60 * 60 * 1000);
for (int i=0; i<s.length; ++i)
{
if (i > 0) buf.append(", ");
buf.append(s[i]);
}
buf.append(" };");
System.out.println(buf.toString());
TimeZone tz = TimeZone.getTimeZone("PST");
if (tz != null)
System.out.println("getTimeZone(PST) = " + tz.getID());
else
fail("FAIL: getTimeZone(PST) = null");
tz = TimeZone.getTimeZone("America/Los_Angeles");
if (tz != null)
System.out.println("getTimeZone(America/Los_Angeles) = " + tz.getID());
else
fail("FAIL: getTimeZone(PST) = null");
// Bug 4096694
tz = TimeZone.getTimeZone("NON_EXISTENT");
if (tz == null)
fail("FAIL: getTimeZone(NON_EXISTENT) = null");
else if (!tz.getID().equals("GMT"))
fail("FAIL: getTimeZone(NON_EXISTENT) = " + tz.getID());
}
/**
* Bug 4107276
*/
@Test
public void TestDSTSavings() {
// It might be better to find a way to integrate this test into the main TimeZone
// tests above, but I don't have time to figure out how to do this (or if it's
// even really a good idea). Let's consider that a future. --rtg 1/27/98
SimpleTimeZone tz = new SimpleTimeZone(-5 * millisPerHour, "dstSavingsTest",
Calendar.MARCH, 1, 0, 0, Calendar.SEPTEMBER, 1, 0, 0,
(int)(0.5 * millisPerHour));
if (tz.getRawOffset() != -5 * millisPerHour)
fail("Got back a raw offset of " + (tz.getRawOffset() / millisPerHour) +
" hours instead of -5 hours.");
if (!tz.useDaylightTime())
fail("Test time zone should use DST but claims it doesn't.");
if (tz.getDSTSavings() != 0.5 * millisPerHour)
fail("Set DST offset to 0.5 hour, but got back " + (tz.getDSTSavings() /
millisPerHour) + " hours instead.");
int offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JANUARY, 1,
Calendar.THURSDAY, 10 * millisPerHour);
if (offset != -5 * millisPerHour)
fail("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JUNE, 1, Calendar.MONDAY,
10 * millisPerHour);
if (offset != -4.5 * millisPerHour)
fail("The offset for 10 AM, 6/1/98 should have been -4.5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
tz.setDSTSavings(millisPerHour);
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JANUARY, 1,
Calendar.THURSDAY, 10 * millisPerHour);
if (offset != -5 * millisPerHour)
fail("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JUNE, 1, Calendar.MONDAY,
10 * millisPerHour);
if (offset != -4 * millisPerHour)
fail("The offset for 10 AM, 6/1/98 (with a 1-hour DST offset) should have been -4 hours, but we got "
+ (offset / millisPerHour) + " hours.");
}
/**
* Bug 4107570
*/
@Test
public void TestAlternateRules() {
// Like TestDSTSavings, this test should probably be integrated somehow with the main
// test at the top of this class, but I didn't have time to figure out how to do that.
// --rtg 1/28/98
SimpleTimeZone tz = new SimpleTimeZone(-5 * millisPerHour, "alternateRuleTest");
// test the day-of-month API
tz.setStartRule(Calendar.MARCH, 10, 12 * millisPerHour);
tz.setEndRule(Calendar.OCTOBER, 20, 12 * millisPerHour);
int offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 5,
Calendar.THURSDAY, 10 * millisPerHour);
if (offset != -5 * millisPerHour)
fail("The offset for 10AM, 3/5/98 should have been -5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 15,
Calendar.SUNDAY, 10 * millisPerHour);
if (offset != -4 * millisPerHour)
fail("The offset for 10AM, 3/15/98 should have been -4 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 15,
Calendar.THURSDAY, 10 * millisPerHour);
if (offset != -4 * millisPerHour)
fail("The offset for 10AM, 10/15/98 should have been -4 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 25,
Calendar.SUNDAY, 10 * millisPerHour);
if (offset != -5 * millisPerHour)
fail("The offset for 10AM, 10/25/98 should have been -5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
// test the day-of-week-after-day-in-month API
tz.setStartRule(Calendar.MARCH, 10, Calendar.FRIDAY, 12 * millisPerHour, true);
tz.setEndRule(Calendar.OCTOBER, 20, Calendar.FRIDAY, 12 * millisPerHour, false);
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 11,
Calendar.WEDNESDAY, 10 * millisPerHour);
if (offset != -5 * millisPerHour)
fail("The offset for 10AM, 3/11/98 should have been -5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 14,
Calendar.SATURDAY, 10 * millisPerHour);
if (offset != -4 * millisPerHour)
fail("The offset for 10AM, 3/14/98 should have been -4 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 15,
Calendar.THURSDAY, 10 * millisPerHour);
if (offset != -4 * millisPerHour)
fail("The offset for 10AM, 10/15/98 should have been -4 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 17,
Calendar.SATURDAY, 10 * millisPerHour);
if (offset != -5 * millisPerHour)
fail("The offset for 10AM, 10/17/98 should have been -5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
}
}
//eof

View file

@ -0,0 +1,289 @@
/*
* Copyright (c) 2002, 2023, 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 4278609 4761696
* @summary Make sure to handle DST transition ending at 0:00 January 1.
* @run junit TransitionTest
*/
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 org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.fail;
public class TransitionTest {
@Test
public void Test4278609() {
SimpleTimeZone tz = new SimpleTimeZone(0, "MyTimeZone",
/* DST start day: August, 1, 0:00 */
Calendar.AUGUST, 1, 0, 0,
/* DST end day: January, 1, 0:00 (wall-clock)*/
Calendar.JANUARY, 1, 0, 0,
60 * 60 * 1000);
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
// setting a date using GMT zone just after the end rule of tz zone
cal.clear();
cal.set(Calendar.ERA, GregorianCalendar.AD);
cal.set(1998, Calendar.DECEMBER, 31, 23, 01, 00);
Date date = cal.getTime();
int millis = cal.get(Calendar.HOUR_OF_DAY) * 3600000
+ cal.get(Calendar.MINUTE) * 60000
+ cal.get(Calendar.SECOND) * 1000
+ cal.get(Calendar.MILLISECOND);
/* we must use standard local time */
millis += tz.getRawOffset();
int offset = tz.getOffset(cal.get(Calendar.ERA),
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH),
cal.get(Calendar.DATE),
cal.get(Calendar.DAY_OF_WEEK),
millis);
if (offset != 0) {
SimpleDateFormat format = new SimpleDateFormat("dd MMM HH:mm:ss zzz",
Locale.US);
format.setTimeZone(tz);
fail("Wrong DST transition: " + tz
+ "\na date just after DST = " + format.format(date)
+ "\ngetOffset = " + offset);
}
}
/*
* 4761696: Rewrite SimpleTimeZone to support correct DST transitions
*
* Derived from JCK test cases some of which specify wrong day of week values.
*/
@Test
public void Test4761696() {
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
// test#1
int rawOffset = -43200000;
int saving = 1800000;
int timeOfDay = 84600001;
SimpleTimeZone tz = new SimpleTimeZone(rawOffset, "stz",
Calendar.JULY, 1, 0, 0,
Calendar.JANUARY, 1, 0, 0,
saving);
int year = Integer.MIN_VALUE;
tz.setStartYear(year);
int offset = tz.getOffset(GregorianCalendar.AD,
year,
Calendar.DECEMBER,
31,
1, // should be SATURDAY
timeOfDay);
int y = (int) mod((long)year, 28L); // 28-year cycle
cal.clear();
cal.set(cal.ERA, cal.AD);
cal.set(y, Calendar.DECEMBER, 31);
cal.set(cal.MILLISECOND, timeOfDay);
long localtime = cal.getTimeInMillis() + rawOffset; // local standard time
cal.clear();
cal.set(cal.ERA, cal.AD);
cal.set(y + 1, Calendar.JANUARY, 1);
cal.set(cal.MILLISECOND, -saving);
long endTime = cal.getTimeInMillis() + rawOffset;
long expectedOffset = (localtime < endTime) ? rawOffset + saving : rawOffset;
if (offset != expectedOffset) {
fail("test#1: wrong offset: got "+offset+", expected="+expectedOffset);
}
// test#2
saving = 1;
timeOfDay = 0;
tz = new SimpleTimeZone(rawOffset, "stz",
Calendar.JULY, 1, 0, 0,
Calendar.JANUARY, 1, 0, 0,
saving);
tz.setStartYear(year);
offset = tz.getOffset(GregorianCalendar.AD,
year,
Calendar.AUGUST,
15,
1, // should be MONDAY
timeOfDay);
y = (int) mod((long)year, 28L); // 28-year cycle
cal.clear();
cal.set(y, Calendar.AUGUST, 15);
cal.set(cal.MILLISECOND, timeOfDay);
localtime = cal.getTimeInMillis() + rawOffset; // local standard time
cal.clear();
cal.set(y + 1, Calendar.JANUARY, 1);
cal.set(cal.MILLISECOND, -saving);
endTime = cal.getTimeInMillis() + rawOffset;
expectedOffset = (localtime < endTime) ? rawOffset + saving : rawOffset;
if (offset != expectedOffset) {
fail("Wrong offset: got "+offset+", expected="+expectedOffset);
}
rawOffset = 43200000;
saving = 1;
timeOfDay = 3599998;
tz = new SimpleTimeZone(rawOffset, "stz",
Calendar.JULY, 1, 0, 3600000,
Calendar.JANUARY, 1, 0, 3600000,
saving);
tz.setStartYear(year);
offset = tz.getOffset(GregorianCalendar.AD,
year,
Calendar.JANUARY,
1,
1,
timeOfDay);
y = (int) mod((long)year, 28L); // 28-year cycle
cal.clear();
cal.set(y, Calendar.JANUARY, 1);
cal.set(cal.MILLISECOND, timeOfDay);
localtime = cal.getTimeInMillis() + rawOffset; // local standard time
cal.clear();
cal.set(y + 1, Calendar.JANUARY, 1);
cal.set(cal.MILLISECOND, 3600000-saving);
endTime = cal.getTimeInMillis() + rawOffset;
expectedOffset = (localtime < endTime) ? rawOffset + saving : rawOffset;
if (offset != expectedOffset) {
fail("test#2: wrong offset: got "+offset+", expected="+expectedOffset);
}
// test#3
rawOffset = -43200000;
saving = 1800000;
timeOfDay = 84600001;
tz = new SimpleTimeZone(rawOffset, "stz",
Calendar.SEPTEMBER, 1, 0, 0,
Calendar.MARCH, 1, 0, 0,
saving);
tz.setStartYear(year);
offset = tz.getOffset(GregorianCalendar.AD,
year,
Calendar.FEBRUARY,
28,
1,
timeOfDay);
y = (int) mod((long)year, 28L); // 28-year cycle
cal.clear();
cal.set(y, Calendar.FEBRUARY, 28);
cal.set(cal.MILLISECOND, timeOfDay);
localtime = cal.getTimeInMillis() + rawOffset; // local standard time
cal.clear();
cal.set(y, Calendar.MARCH, 1);
cal.set(cal.MILLISECOND, -saving);
endTime = cal.getTimeInMillis() + rawOffset;
expectedOffset = (localtime < endTime) ? rawOffset + saving : rawOffset;
if (offset != expectedOffset) {
fail("test#3: wrong offset: got "+offset+", expected="+expectedOffset);
}
// test#4
rawOffset = -43200000;
saving = 1;
timeOfDay = 0;
tz = new SimpleTimeZone(rawOffset, "stz",
Calendar.JANUARY, -4, 1, 3600000,
Calendar.JULY, -4, 1, 3600000,
saving);
tz.setStartYear(year);
offset = tz.getOffset(GregorianCalendar.AD,
year,
Calendar.JANUARY,
10,
2, // should be 1 (SUNDAY)
timeOfDay);
y = (int) mod((long)year, 28L); // 28-year cycle
cal.clear();
cal.set(y, Calendar.JANUARY, 10);
cal.set(cal.MILLISECOND, timeOfDay);
localtime = cal.getTimeInMillis() + rawOffset; // local standard time
cal.clear();
cal.set(cal.YEAR, y);
cal.set(cal.MONTH, Calendar.JANUARY);
cal.set(cal.DAY_OF_MONTH, 8);
cal.set(cal.WEEK_OF_MONTH, cal.getActualMaximum(cal.WEEK_OF_MONTH)-4+1);
cal.set(cal.DAY_OF_WEEK, 1);
cal.set(cal.MILLISECOND, 3600000-saving);
long startTime = cal.getTimeInMillis() + rawOffset;
expectedOffset = (localtime >= startTime) ? rawOffset + saving : rawOffset;
if (offset != expectedOffset) {
fail("test#4: wrong offset: got "+offset+", expected="+expectedOffset);
}
// test#5
rawOffset = 0;
saving = 3600000;
timeOfDay = 7200000;
year = 1982;
tz = new SimpleTimeZone(rawOffset, "stz",
Calendar.APRIL, 1, 0, 7200000,
Calendar.OCTOBER, 10, 0, 7200000,
saving);
offset = tz.getOffset(GregorianCalendar.AD,
year,
Calendar.OCTOBER,
10,
1,
timeOfDay);
cal.clear();
cal.set(year, Calendar.OCTOBER, 10);
cal.set(cal.MILLISECOND, timeOfDay);
localtime = cal.getTimeInMillis() + rawOffset; // local standard time
cal.clear();
cal.set(year, Calendar.OCTOBER, 10);
cal.set(cal.MILLISECOND, 7200000-saving);
endTime = cal.getTimeInMillis() + rawOffset;
expectedOffset = (localtime < endTime) ? rawOffset + saving : rawOffset;
if (offset != expectedOffset) {
fail("test#5: wrong offset: got "+offset+", expected="+expectedOffset);
}
}
public static final long floorDivide(long n, long d) {
return ((n >= 0) ?
(n / d) : (((n + 1L) / d) - 1L));
}
public static final long mod(long x, long y) {
return (x - y * floorDivide(x, y));
}
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2005, 2017, 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 6282072
* @summary Make sure that "UTC" is an alias of "Etc/UTC" as defined in the tzdata backward.
* @modules java.base/sun.util.calendar
* @compile -XDignore.symbol.file UTCAliasTest.java
* @run main UTCAliasTest
*/
import java.util.*;
import sun.util.calendar.ZoneInfo;
public class UTCAliasTest {
public static void main(String[] args) {
Map<String,String> map = ZoneInfo.getAliasTable();
String alias = map.get("UTC");
if (!alias.equals("Etc/UTC")) {
throw new RuntimeException("got " + alias + ", expected Etc/UTC");
}
TimeZone GMT = TimeZone.getTimeZone("GMT");
TimeZone UTC = TimeZone.getTimeZone("UTC");
if (!GMT.hasSameRules(UTC)) {
throw new RuntimeException("GMT and UTC have different rules");
}
TimeZone EtcUTC = TimeZone.getTimeZone("Etc/UTC");
if (!UTC.hasSameRules(EtcUTC)) {
throw new RuntimeException("UTC and Etc/UTC have different rules");
}
}
}

View file

@ -0,0 +1,71 @@
/*
* Copyright (c) 2022, 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.
*/
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.TimeZone;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
/**
* @test
* @bug 8285844
* @summary Checks round-trips between TimeZone and ZoneId are consistent
* @run junit ZoneIdRoundTripTest
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class ZoneIdRoundTripTest {
private Object[][] testZoneIds() {
return new Object[][] {
{ZoneId.of("Z"), 0},
{ZoneId.of("UT"), 0},
{ZoneId.of("UTC"), 0},
{ZoneId.of("GMT"), 0},
{ZoneId.of("+00:01"), 60_000},
{ZoneId.of("-00:01"), -60_000},
{ZoneId.of("+00:00:01"), 1_000},
{ZoneId.of("-00:00:01"), -1_000},
{ZoneId.of("UT+00:00:01"), 1_000},
{ZoneId.of("UT-00:00:01"), -1_000},
{ZoneId.of("UTC+00:00:01"), 1_000},
{ZoneId.of("UTC-00:00:01"), -1_000},
{ZoneId.of("GMT+00:00:01"), 1_000},
{ZoneId.of("GMT-00:00:01"), -1_000},
{ZoneOffset.of("+00:00:01"), 1_000},
{ZoneOffset.of("-00:00:01"), -1_000},
};
}
@ParameterizedTest
@MethodSource("testZoneIds")
public void test_ZoneIdRoundTrip(ZoneId zid, int offset) {
var tz = TimeZone.getTimeZone(zid);
assertEquals(offset, tz.getRawOffset());
assertEquals(zid.normalized(), tz.toZoneId().normalized());
}
}

View file

@ -0,0 +1,67 @@
/*
* 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 4096952 8347841
* @summary simple serialization/deserialization test
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.TimeZone;
public class bug4096952 {
public static void main(String[] args) {
int errors = 0;
String[] ZONES = { "GMT", "MET", "Asia/Kolkata" };
for (String id : ZONES) {
TimeZone zone = TimeZone.getTimeZone(id);
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream ostream = new ObjectOutputStream(baos)) {
ostream.writeObject(zone);
}
try (ObjectInputStream istream
= new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) {
if (!zone.equals(istream.readObject())) {
errors++;
System.out.println("Time zone " + id + " are not equal to serialized/deserialized one.");
} else {
System.out.println("Time zone " + id + " ok.");
}
}
} catch (IOException | ClassNotFoundException e) {
errors++;
System.out.println(e);
}
}
if (errors > 0) {
throw new RuntimeException("test failed");
}
}
}

View file

@ -0,0 +1,84 @@
#
# Copyright (c) 2008, 2022, 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.
#
#
# Compares two year* test data files
# Typical usage:
# perl CompareYearData.pl ../../TimeZoneData/year2008 year2008
#
%oldData = &readData($ARGV[0]);
%newData = &readData($ARGV[1]);
foreach $key (sort(keys(%oldData))) {
if (defined($newData{$key})) {
if ($oldData{$key} ne $newData{$key}) {
print "Changed:\n";
print "$oldData{$key}";
print "---\n";
print "$newData{$key}";
}
delete $newData{$key};
} else {
print "Deleted:\n";
print "$oldData{$key}";
}
}
foreach $key (sort(keys(%newData))) {
print "Added:\n";
print "$newData{$key}";
}
sub readData {
local($file) = @_;
open(F, $file) || die "Can't open $file\n";
my %data = ();
my $line = 0;
my $id = "";
while (<F>) {
$line++;
s/^\s*\d+ //;
if (/tzdata\d+/) {
$data{" version"} = $_;
next;
}
if (/(\s*#.*$)/) {
$data{" comments"} .= $_;
next;
}
if (/^(Zone|Rule)/) {
die "No id at line: $line\n" if ($id eq "");
$data{$id} .= $_;
} elsif (/^(\S+)\s+\S+/) {
$id = $1;
$data{$id} = $_;
$flag = 1;
} else {
die "Unknown format at line: $line: $file\n";
}
}
close(F);
return %data;
}

View file

@ -0,0 +1,57 @@
#
# Copyright (c) 2008, 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.
#
#
#
# This makefile is used to update the time zone tests data: aliases.txt displaynames.txt
# and VERSION. After switching to new build system in JDK8 the following make
# command should be used for test data updates:
# make JDK_HOME=<path to built JDK with latest tzdata>
# make install
#
TZDATA = ../../../../../../../src/java.base/share/data/tzdata
TZDATA_VER = `grep '^tzdata' $(TZDATA)/VERSION`
TZNAME = africa antarctica asia australasia europe northamerica \
southamerica backward
TZFILES = $(addprefix $(TZDATA)/, $(TZNAME))
ALIASLIST = aliases.txt
DISPLAYNAMES = displaynames.txt
all: $(DISPLAYNAMES) VERSION $(ALIASLIST)
$(DISPLAYNAMES): $(TZFILES) makeZoneData.pl
(cat $(TZFILES) | perl makeZoneData.pl -v -V "$(TZDATA_VER)") 2>errors
VERSION: $(TZDATA)/VERSION
echo "$(TZDATA_VER)" > VERSION
$(ALIASLIST): $(TZFILES)
rm -f $(ALIASLIST)
grep -h "^Link" $(TZFILES) >> $(ALIASLIST)
clean:
rm -f $(DISPLAYNAMES) errors year???? VERSION $(ALIASLIST)
install:
cp $(ALIASLIST) $(DISPLAYNAMES) VERSION ../../TimeZoneData/

View file

@ -0,0 +1,288 @@
#
# Copyright (c) 2008, 2024, 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.
#
#
#
#
# Perl script to generate ZoneData from Olson public time zone data.
#
# For J2SE before JDK1.3, see ../../README how to update TimeZone.java
# static TimeZoneData.
# For J2SE since JDK1.4, this script is used to generate testdata(reference)
# for ZoneData.sh which is one of TimeZone Regression test.
$continue = 0;
# verbose flag
$verbose = 0;
# version of Olson's public zone information (e.g. "tzdata2000g")
$versionName = "unknown";
# Number of testdata files.
$count = 5;
# Display name datafile
$displayNameFile = "displaynames.txt";
# time zone IDs to be generated. If it's empty, then generate all time
# zone in the tzdata files.
@javatzids = ();
#
# Parses command-line options
#
while ($#ARGV >= 0) {
if ($ARGV[0] =~ /^-v/) {
$verbose = 1;
} elsif ($ARGV[0] =~ /^-V/) {
$versionName = $ARGV[1];
shift(@ARGV);
} else {
@javatzids = &readIDs($ARGV[0]);
last;
}
shift(@ARGV);
}
# Beginning year of testdata
($sec, $min, $hour, $mday, $mon, $year, $wday, $ydat, $isdst) = gmtime();
$baseYear = $year+1900;
if ($verbose == 1) {
print STDERR "baseYear : $baseYear\n";
print STDERR "versionName : $versionName\n";
}
# Open display name datafile
open (DNFD, ">$displayNameFile") || die ("$displayNameFile : open error.\n");
while(<STDIN>) {
chop;
if (/^\#/) { # skip comment line
next;
}
@item = ("foo");
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
if ($continue == 1) {
s/\#.*//; # chop trailing comments
s/\s+$//;
s/^\s+//;
@item = split(/\s+/, $_);
@item = ($zname, @item); # push zone name
} elsif (/^Zone/) {
s/\#.*//; # chop trailing comments
s/\s+$//;
@item = split(/\s+/, $_);
$zname = $item[1];
if (defined ($zones{$name})) {
printf STDERR "WARNING: duplicate definition of zone $name\n";
}
shift(@item);
}
if (@item[0] ne "foo") {
if($#item == 3) { # find out no UNTIL line
$item[3] =~ s/%/%%/;
$zones{$item[0]} = "Zone $item[0]\t$item[1]\t$item[2]\t$item[3]";
} else {
$continue = 1;
next;
}
}
# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
if (/^Rule/) {
($rule, $name, $from, $to, $type, $in, $on, $at, $save, $letter)
= split(/\s+/, $_);
# matches specified year?
for ($i = 0; $i < $count; $i++) {
if ($from <= $baseYear+$i && ($to >= $baseYear+$i || $to eq "max")
|| ($from == $baseYear+$i && $to eq "only")) {
if ($save ne "0") {
$rules[$i]{$name . "0"} = $_;
} else {
$rules[$i]{$name . "1"} = $_;
}
} else {
if ($from <= $baseYear) {
if ($save ne "0") {
$oldRules[0]{$name} = $_;
} else {
$oldRules[1]{$name} = $_;
}
}
}
}
}
$continue = 0;
}
#
# Prepare output files
#
for ($i = 0, $fd = 0; $i < $count; $i++, $fd++) {
$filename = "year".($baseYear+$i);
open ($fd, ">$filename") || die ("$filename : open error.\n");
print $fd "# Based on $versionName\n";
}
#
# If no IDs are specified, produce test data for all zones.
#
if ($#javatzids < 0) {
@javatzids = keys(%zones);
}
foreach $z (@javatzids) {
#
# skip any Riyadh zones; ZoneData.java can't handle Riyadh zones
#
# Skip these zones for CLDR
# Africa/Windhoek: Negative DST (throughout year)
# Korea zones: CLDR metazone shares Seoul/Pyongyang, where TZDB doesn't
# Adak: CLDR's short names (Hawaii_Aleutian) differ from TZDB, HAST/HADT vs. HST/HDT
#
next if ($z =~ /Riyadh|Windhoek|Seoul|Pyongyang|Adak/);
for ($i = 0, $fd = 0; $i < $count; $i++, $fd++) {
if (!defined($zones{$z})) {
printf $fd "$z ?\n";
printf STDERR "WARNING: java zone $z not found\n";
next;
}
@item = split(/\s+/, $zones{$z});
if ($item[3] ne "-") {
printf $fd "$item[1] $item[2] ";
if (defined($rules[$i]{$item[3] . "0"})
&& defined($rules[$i]{$item[3] . "1"})) {
$rule0 = $rules[$i]{$item[3] . "0"};
$rule1 = $rules[$i]{$item[3] . "1"};
@r0 = split(/\s+/, $rule0);
@r1 = split(/\s+/, $rule1);
printf $fd "$r0[5] $r0[6] $r0[7] $r1[5] $r1[6] $r1[7] $r0[8]\n";
printf $fd "$zones{$z}\n";
printf $fd "$rule0\n";
printf $fd "$rule1\n";
if ($i == 0) {
$std = $dst = $item[4];
$std =~ s/%%s/$r1[9]/;
if ($r1[9] eq "-") {
$std =~ s/-//;
}
$dst =~ s/%%s/$r0[9]/;
if ($r0[9] eq "-") {
$dst =~ s/-//;
}
if ("$std$dst" =~ /[A-Z]/) {
print DNFD "$item[1] $std $dst\n";
}
}
} else {
printf $fd "-\n"; # In case we cannot find Rule, assume no DST.
printf $fd "$zones{$z}\n";
printf STDERR "WARNING: $z no rules defined for $item[3]\n";
if ($i == 0) {
# About 30 time zones (e.g. Asia/Tokyo needs the following
# recovery.
if ($item[4] =~ m/%/) {
@r0 = split(/\s+/, $oldRules[0]{$item[3]});
@r1 = split(/\s+/, $oldRules[1]{$item[3]});
if ($i == 0) {
$std = $dst = $item[4];
$std =~ s/%%s/$r1[9]/;
if ($r1[9] eq "-") {
$std =~ s/-//;
}
$dst =~ s/%%s/$r0[9]/;
if ($r0[9] eq "-") {
$dst =~ s/-//;
}
if ("$std$dst" =~ /[A-Z]/) {
print DNFD "$item[1] $std $dst\n";
}
}
} else {
if ("$item[4]" =~ /[A-Z]/) {
print DNFD "$item[1] $item[4]\n";
}
}
}
}
} else {
printf $fd "$item[1] $item[2] $item[3]\n";
printf $fd "$zones{$z}\n";
if ($i == 0 && "$item[4]" =~ /[A-Z]/) {
print DNFD "$item[1] $item[4]\n";
}
}
}
}
#
# Close all the output files
#
close (DNFD);
for ($i = 0, $fd = 0; $i < $count; $i++, $fd++) {
close ($fd);
}
#
# Sort the displaynames.txt file
#
open my $fh, '<', $displayNameFile || die ("Can't open $displayNameFile for sorting\n");;
chomp(my @names = <$fh>);
close $fh;
open my $fh, '>', $displayNameFile;
foreach $line (sort @names) { print $fh $line,"\n"; }
close $fh;
exit(0);
sub readIDs {
local ($file) = @_;
local (@ids, $i);
open(F, $file) || die "Fatal: can't open $file.\n";
$i = 0;
while (<F>) {
chop;
if (/^\#/) { # skip comment line
next;
}
# trim any leading and trailing space
s/^\s+//;
s/\s+$//;
if (/^\s*$/) { # skip blank line
next;
}
$ids[$i++] = $_;
}
close(F);
return @ids;
}