From c572f25040710e6b16ffa1ff820eb89a12cd808d Mon Sep 17 00:00:00 2001 From: Dmitry Samersoff Date: Wed, 6 Feb 2013 16:53:47 +0400 Subject: [PATCH 01/39] 8007277: JDK-8002048 testcase fails to compile Sun.* classes is not included to ct.sym file and symbol file have to be ignored Reviewed-by: alanb --- jdk/test/sun/management/jdp/JdpTest.sh | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/jdk/test/sun/management/jdp/JdpTest.sh b/jdk/test/sun/management/jdp/JdpTest.sh index 2aded729953..764a19f2595 100644 --- a/jdk/test/sun/management/jdp/JdpTest.sh +++ b/jdk/test/sun/management/jdp/JdpTest.sh @@ -23,7 +23,7 @@ # @test # @bug 7169888 -# @build JdpUnitTest JdpClient JdpDoSomething +# @compile -XDignore.symbol.file JdpUnitTest.java JdpClient.java JdpDoSomething.java # @run shell JdpTest.sh --jtreg --no-compile # @summary No word Failed expected in the test output @@ -46,6 +46,10 @@ _last_pid="" _compile(){ + # If the test run without JTReg, we have to compile it by our self + # Under JTReg see @compile statement above + # sun.* packages is not included to symbol file lib/ct.sym so we have + # to ignore it if [ ! -e ${_testclasses} ] then @@ -55,7 +59,8 @@ _compile(){ rm -f ${_testclasses}/*.class # Compile testcase - ${TESTJAVA}/bin/javac -d ${_testclasses} JdpUnitTest.java \ + ${COMPILEJAVA}/bin/javac -XDignore.symbol.file -d ${_testclasses} \ + JdpUnitTest.java \ JdpDoSomething.java \ JdpClient.java @@ -266,6 +271,13 @@ then exit fi +# COMPILEJAVA variable is set when we test jre +if [ "x${COMPILEJAVA}" = "x" ] +then + COMPILEJAVA="${TESTJAVA}" +fi + + #------------------------------------------------------------------------------ # reading parameters From ac96c41fe80f99196d031ae271a5c7283d8ee5cf Mon Sep 17 00:00:00 2001 From: Alexander Scherbatiy Date: Wed, 6 Feb 2013 18:25:06 +0400 Subject: [PATCH 02/39] 8000326: Focus unable to traverse in the menubar Reviewed-by: alexsch, malenkov --- jdk/src/share/classes/javax/swing/JMenuBar.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/javax/swing/JMenuBar.java b/jdk/src/share/classes/javax/swing/JMenuBar.java index 0a16c865d15..22dbe6274fe 100644 --- a/jdk/src/share/classes/javax/swing/JMenuBar.java +++ b/jdk/src/share/classes/javax/swing/JMenuBar.java @@ -70,7 +70,14 @@ import javax.accessibility.*; * of all JavaBeansTM * has been added to the java.beans package. * Please see {@link java.beans.XMLEncoder}. - * + *

+ * Warning: + * By default, pressing the Tab key does not transfer focus from a + * JMenuBar which is added to a container together with other Swing + * components, because the focusTraversalKeysEnabled property + * of JMenuBar is set to false. To resolve this, + * you should call the JMenuBar.setFocusTraversalKeysEnabled(true) + * method. * @beaninfo * attribute: isContainer true * description: A container for holding and displaying menus. From 218dc713ff1a2488b3d75bfdd3ce5623b40ecb92 Mon Sep 17 00:00:00 2001 From: Lance Andersen Date: Wed, 6 Feb 2013 14:15:05 -0500 Subject: [PATCH 03/39] 8006505: additional changes for JSR 310 support Reviewed-by: naoto, ulfzibis --- jdk/src/share/classes/java/sql/JDBCType.java | 12 +++++- jdk/src/share/classes/java/sql/SQLInput.java | 36 +++++++++++++++- jdk/src/share/classes/java/sql/SQLOutput.java | 42 ++++++++++++++++++- jdk/src/share/classes/java/sql/Types.java | 18 ++++++++ 4 files changed, 104 insertions(+), 4 deletions(-) diff --git a/jdk/src/share/classes/java/sql/JDBCType.java b/jdk/src/share/classes/java/sql/JDBCType.java index f1453059605..74ee8e01682 100644 --- a/jdk/src/share/classes/java/sql/JDBCType.java +++ b/jdk/src/share/classes/java/sql/JDBCType.java @@ -190,7 +190,17 @@ public enum JDBCType implements SQLType { /** * Identifies the generic SQL type {@code REF_CURSOR}. */ - REF_CURSOR(Types.REF_CURSOR); + REF_CURSOR(Types.REF_CURSOR), + + /** + * Identifies the generic SQL type {@code TIME_WITH_TIMEZONE}. + */ + TIME_WITH_TIMEZONE(Types.TIME_WITH_TIMEZONE), + + /** + * Identifies the generic SQL type {@code TIMESTAMP_WITH_TIMEZONE}. + */ + TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE); /** * The Integer value for the JDBCType. It maps to a value in diff --git a/jdk/src/share/classes/java/sql/SQLInput.java b/jdk/src/share/classes/java/sql/SQLInput.java index c607e83cbcb..8d2540dc499 100644 --- a/jdk/src/share/classes/java/sql/SQLInput.java +++ b/jdk/src/share/classes/java/sql/SQLInput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, 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 @@ -421,4 +421,38 @@ public interface SQLInput { */ RowId readRowId() throws SQLException; + //--------------------------JDBC 4.2 ----------------------------- + + /** + * Reads the next attribute in the stream and returns it as an + * {@code Object} in the Java programming language. The + * actual type of the object returned is determined by the specified + * Java data type, and any customizations present in this + * stream's type map. + * + *

A type map is registered with the stream by the JDBC driver before the + * stream is passed to the application. + * + *

When the attribute at the head of the stream is an SQL {@code NULL} + * the method returns {@code null}. If the attribute is an SQL + * structured or distinct + * type, it determines the SQL type of the attribute at the head of the stream. + * If the stream's type map has an entry for that SQL type, the driver + * constructs an object of the appropriate class and calls the method + * {@code SQLData.readSQL} on that object, which reads additional data from the + * stream, using the protocol described for that method. + *

+ * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param type Class representing the Java data type to convert the attribute to. + * @return the attribute at the head of the stream as an {@code Object} in the + * Java programming language;{@code null} if the attribute is SQL {@code NULL} + * @exception SQLException if a database access error occurs + * @exception SQLFeatureNotSupportedException if the JDBC driver does not support + * this method + * @since 1.8 + */ + default T readObject(Class type) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } } diff --git a/jdk/src/share/classes/java/sql/SQLOutput.java b/jdk/src/share/classes/java/sql/SQLOutput.java index 8aa1d145329..0edfc998aa3 100644 --- a/jdk/src/share/classes/java/sql/SQLOutput.java +++ b/jdk/src/share/classes/java/sql/SQLOutput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, 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 @@ -272,7 +272,7 @@ package java.sql; * Otherwise, it calls the SQLData.writeSQL * method of the given object, which * writes the object's attributes to the stream. - * The implementation of the method SQLData.writeSQ + * The implementation of the method SQLData.writeSQL * calls the appropriate SQLOutput writer method(s) * for writing each of the object's attributes in order. * The attributes must be read from an SQLInput @@ -433,5 +433,43 @@ package java.sql; */ void writeSQLXML(SQLXML x) throws SQLException; + //--------------------------JDBC 4.2 ----------------------------- + + /** + * Writes to the stream the data contained in the given object. The + * object will be converted to the specified targetSqlType + * before being sent to the stream. + *

+ * When the {@code object} is {@code null}, this + * method writes an SQL {@code NULL} to the stream. + *

+ * If the object has a custom mapping (is of a class implementing the + * interface {@code SQLData}), + * the JDBC driver should call the method {@code SQLData.writeSQL} to + * write it to the SQL data stream. + * If, on the other hand, the object is of a class implementing + * {@code Ref}, {@code Blob}, {@code Clob}, {@code NClob}, + * {@code Struct}, {@code java.net.URL}, + * or {@code Array}, the driver should pass it to the database as a + * value of the corresponding SQL type. + *

+ * The default implementation will throw {@code SQLFeatureNotSupportedException} + * + * @param x the object containing the input parameter value + * @param targetSqlType the SQL type to be sent to the database. + * @exception SQLException if a database access error occurs or + * if the Java Object specified by x is an InputStream + * or Reader object and the value of the scale parameter is less + * than zero + * @exception SQLFeatureNotSupportedException if + * the JDBC driver does not support this data type + * @see JDBCType + * @see SQLType + * @since 1.8 + */ + default void writeObject(Object x, SQLType targetSqlType) throws SQLException { + throw new SQLFeatureNotSupportedException(); + } } + diff --git a/jdk/src/share/classes/java/sql/Types.java b/jdk/src/share/classes/java/sql/Types.java index d6fc80a3232..f12ff0dc1da 100644 --- a/jdk/src/share/classes/java/sql/Types.java +++ b/jdk/src/share/classes/java/sql/Types.java @@ -319,6 +319,24 @@ public class Types { */ public static final int REF_CURSOR = 2012; + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type + * {@code TIME WITH TIMEZONE}. + * + * @since 1.8 + */ + public static final int TIME_WITH_TIMEZONE = 2013; + + /** + * The constant in the Java programming language, sometimes referred to + * as a type code, that identifies the generic SQL type + * {@code TIMESTAMP WITH TIMEZONE}. + * + * @since 1.8 + */ + public static final int TIMESTAMP_WITH_TIMEZONE = 2014; + // Prevent instantiation private Types() {} } From 925fe9142b1581b531068d1760fe2f48c7684bc9 Mon Sep 17 00:00:00 2001 From: Martin Buchholz Date: Wed, 6 Feb 2013 17:59:54 -0800 Subject: [PATCH 04/39] 8006995: java launcher fails to open executable JAR > 2GB Use O_LARGEFILE consistently when opening jar files Reviewed-by: alanb, sherman --- jdk/src/share/bin/parse_manifest.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/bin/parse_manifest.c b/jdk/src/share/bin/parse_manifest.c index ec3014931f2..61c5b883081 100644 --- a/jdk/src/share/bin/parse_manifest.c +++ b/jdk/src/share/bin/parse_manifest.c @@ -563,7 +563,7 @@ JLI_ParseManifest(char *jarfile, manifest_info *info) if ((fd = open(jarfile, O_RDONLY #ifdef O_LARGEFILE - | O_LARGEFILE /* large file mode on solaris */ + | O_LARGEFILE /* large file mode */ #endif #ifdef O_BINARY | O_BINARY /* use binary mode on windows */ @@ -618,6 +618,9 @@ JLI_JarUnpackFile(const char *jarfile, const char *filename, int *size) { void *data = NULL; fd = open(jarfile, O_RDONLY +#ifdef O_LARGEFILE + | O_LARGEFILE /* large file mode */ +#endif #ifdef O_BINARY | O_BINARY /* use binary mode on windows */ #endif @@ -661,6 +664,9 @@ JLI_ManifestIterate(const char *jarfile, attribute_closure ac, void *user_data) int rc; if ((fd = open(jarfile, O_RDONLY +#ifdef O_LARGEFILE + | O_LARGEFILE /* large file mode */ +#endif #ifdef O_BINARY | O_BINARY /* use binary mode on windows */ #endif From 19982b2e807269a49a362b1f84516284dbab761e Mon Sep 17 00:00:00 2001 From: Katja Kantserova Date: Thu, 7 Feb 2013 11:22:04 +0100 Subject: [PATCH 05/39] 8007142: Add utility classes for writing better multiprocess tests in jtreg Reviewed-by: alanb, rbackman --- .../lib/testlibrary/OutputAnalyzerTest.java | 181 ++++++++++ .../testlibrary/jdk/testlibrary/JcmdBase.java | 79 +++++ .../jdk/testlibrary/JdkFinder.java | 82 +++++ .../jdk/testlibrary/OutputAnalyzer.java | 324 ++++++++++++++++++ .../jdk/testlibrary/OutputBuffer.java | 61 ++++ .../jdk/testlibrary/ProcessTools.java | 151 ++++++++ .../jdk/testlibrary/StreamPumper.java | 78 +++++ 7 files changed, 956 insertions(+) create mode 100644 jdk/test/lib/testlibrary/OutputAnalyzerTest.java create mode 100644 jdk/test/lib/testlibrary/jdk/testlibrary/JcmdBase.java create mode 100644 jdk/test/lib/testlibrary/jdk/testlibrary/JdkFinder.java create mode 100644 jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java create mode 100644 jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java create mode 100644 jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java create mode 100644 jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java diff --git a/jdk/test/lib/testlibrary/OutputAnalyzerTest.java b/jdk/test/lib/testlibrary/OutputAnalyzerTest.java new file mode 100644 index 00000000000..f8ad49e7a43 --- /dev/null +++ b/jdk/test/lib/testlibrary/OutputAnalyzerTest.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2013, 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 + * @summary Test the OutputAnalyzer utility class + * @library /testlibrary + */ + +import jdk.testlibrary.OutputAnalyzer; + +public class OutputAnalyzerTest { + + public static void main(String args[]) throws Exception { + + String stdout = "aaaaaa"; + String stderr = "bbbbbb"; + String nonExistingString = "cccc"; + + OutputAnalyzer output = new OutputAnalyzer(stdout, stderr); + + if (!stdout.equals(output.getStdout())) { + throw new Exception("getStdout() returned '" + output.getStdout() + + "', expected '" + stdout + "'"); + } + + if (!stderr.equals(output.getStderr())) { + throw new Exception("getStderr() returned '" + output.getStderr() + + "', expected '" + stderr + "'"); + } + + try { + output.shouldContain(stdout); + output.stdoutShouldContain(stdout); + output.shouldContain(stderr); + output.stderrShouldContain(stderr); + } catch (RuntimeException e) { + throw new Exception("shouldContain() failed", e); + } + + try { + output.shouldContain(nonExistingString); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldContain(stderr); + throw new Exception( + "stdoutShouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldContain(stdout); + throw new Exception( + "stdoutShouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.shouldNotContain(nonExistingString); + output.stdoutShouldNotContain(nonExistingString); + output.stderrShouldNotContain(nonExistingString); + } catch (RuntimeException e) { + throw new Exception("shouldNotContain() failed", e); + } + + try { + output.shouldNotContain(stdout); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldNotContain(stdout); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldNotContain(stderr); + throw new Exception("shouldContain() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + String stdoutPattern = "[a]"; + String stderrPattern = "[b]"; + String nonExistingPattern = "[c]"; + + // Should match + try { + output.shouldMatch(stdoutPattern); + output.stdoutShouldMatch(stdoutPattern); + output.shouldMatch(stderrPattern); + output.stderrShouldMatch(stderrPattern); + } catch (RuntimeException e) { + throw new Exception("shouldMatch() failed", e); + } + + try { + output.shouldMatch(nonExistingPattern); + throw new Exception("shouldMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldMatch(stderrPattern); + throw new Exception( + "stdoutShouldMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldMatch(stdoutPattern); + throw new Exception( + "stderrShouldMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + // Should not match + try { + output.shouldNotMatch(nonExistingPattern); + output.stdoutShouldNotMatch(nonExistingPattern); + output.stderrShouldNotMatch(nonExistingPattern); + } catch (RuntimeException e) { + throw new Exception("shouldNotMatch() failed", e); + } + + try { + output.shouldNotMatch(stdoutPattern); + throw new Exception("shouldNotMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stdoutShouldNotMatch(stdoutPattern); + throw new Exception("shouldNotMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + + try { + output.stderrShouldNotMatch(stderrPattern); + throw new Exception("shouldNotMatch() failed to throw exception"); + } catch (RuntimeException e) { + // expected + } + } + +} diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/JcmdBase.java b/jdk/test/lib/testlibrary/jdk/testlibrary/JcmdBase.java new file mode 100644 index 00000000000..de5807f9bec --- /dev/null +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JcmdBase.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.testlibrary; + +import java.util.ArrayList; + +public class JcmdBase { + + private static ProcessBuilder processBuilder = new ProcessBuilder(); + + /** + * Attach jcmd to the current process + * + * @param commandArgs + * jcmd command line parameters, e.g. JFR.start + * @return jcmd output + * @throws Exception + */ + public final static OutputAnalyzer jcmd(String... commandArgs) + throws Exception { + ArrayList cmd = new ArrayList(); + String cmdString = ""; + + // jcmd from the jdk to be tested + String jcmdPath = JdkFinder.getTool("jcmd", false); + cmd.add(jcmdPath); + cmdString += jcmdPath; + + String pid = Integer.toString(ProcessTools.getProcessId()); + cmd.add(pid); + cmdString += " " + pid; + + for (int i = 0; i < commandArgs.length; i++) { + cmd.add(commandArgs[i]); + cmdString += " " + commandArgs[i]; + } + + // Log command line for debugging purpose + System.out.println("Command line:"); + System.out.println(cmdString); + + processBuilder.command(cmd); + OutputAnalyzer output = new OutputAnalyzer(processBuilder.start()); + + // Log output for debugging purpose + System.out.println("Command output:"); + System.out.println(output.getOutput()); + + if (output.getExitValue() != 0) { + throw new Exception(processBuilder.command() + + " resulted in exit value " + output.getExitValue() + + " , expected to get 0"); + } + + return output; + } + +} diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/JdkFinder.java b/jdk/test/lib/testlibrary/jdk/testlibrary/JdkFinder.java new file mode 100644 index 00000000000..fa038faccd4 --- /dev/null +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JdkFinder.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.testlibrary; + +import java.io.File; + +public final class JdkFinder { + + private JdkFinder() { + } + + private static String getExecutable(String executable, String property) { + String binPath = System.getProperty(property); + if (binPath == null) { + throw new RuntimeException( + "System property '" + property + "' not set"); + } + + binPath += File.separatorChar + "bin" + File.separatorChar + executable; + File toolFile = new File(binPath); + if (!toolFile.exists()) { + throw new RuntimeException(binPath + " does not exist"); + } + + return binPath; + } + + /** + * Returns the full path to a java launcher in jdk/bin based on system + * property. + * + * @param stableJdk + * see {@link #getTool(String, boolean)} + * @return Full path to a java launcher in jdk/bin. + */ + public static String getJavaLauncher(boolean stableJdk) { + return getTool("java", stableJdk); + } + + /** + * Returns the full path to an executable in jdk/bin based on system + * property. Depending on value of {@code stableJdk} the method will look for + * either 'compile.jdk' or 'test.jdk' system properties. + * 'test.jdk' is normally set by jtreg. When running test separately, + * set this property using '-Dtest.jdk=/path/to/jdk'. + * + * @param stableJdk + * If {@code true} the {@code tool} will be retrieved + * from the compile (stable) JDK. + * If {@code false} the {@code tool} will be retrieved + * from the test JDK. + * @return Full path to an executable in jdk/bin. + */ + public static String getTool(String tool, boolean stableJdk) { + if (stableJdk) { + return getExecutable(tool, "compile.jdk"); + } else { + return getExecutable(tool, "test.jdk"); + } + } +} diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java new file mode 100644 index 00000000000..ba02081398a --- /dev/null +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputAnalyzer.java @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.testlibrary; + +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class OutputAnalyzer { + + private final String stdout; + private final String stderr; + private final int exitValue; + + /** + * Create an OutputAnalyzer, a utility class for verifying output and exit + * value from a Process + * + * @param process + * Process to analyze + * @throws IOException + * If an I/O error occurs. + */ + public OutputAnalyzer(Process process) throws IOException { + OutputBuffer output = ProcessTools.getOutput(process); + exitValue = process.exitValue(); + this.stdout = output.getStdout(); + this.stderr = output.getStderr(); + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param buf + * String buffer to analyze + */ + public OutputAnalyzer(String buf) { + this(buf, buf); + } + + /** + * Create an OutputAnalyzer, a utility class for verifying output + * + * @param stdout + * stdout buffer to analyze + * @param stderr + * stderr buffer to analyze + */ + public OutputAnalyzer(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + exitValue = -1; + } + + /** + * Verify that the stdout and stderr contents of output buffer contains the + * string + * + * @param expectedString + * String that buffer should contain + * @throws RuntimeException + * If the string was not found + */ + public void shouldContain(String expectedString) { + if (!stdout.contains(expectedString) + && !stderr.contains(expectedString)) { + throw new RuntimeException("'" + expectedString + + "' missing from stdout/stderr: [" + stdout + stderr + + "]\n"); + } + } + + /** + * Verify that the stdout contents of output buffer contains the string + * + * @param expectedString + * String that buffer should contain + * @throws RuntimeException + * If the string was not found + */ + public void stdoutShouldContain(String expectedString) { + if (!stdout.contains(expectedString)) { + throw new RuntimeException("'" + expectedString + + "' missing from stdout: [" + stdout + "]\n"); + } + } + + /** + * Verify that the stderr contents of output buffer contains the string + * + * @param expectedString + * String that buffer should contain + * @throws RuntimeException + * If the string was not found + */ + public void stderrShouldContain(String expectedString) { + if (!stderr.contains(expectedString)) { + throw new RuntimeException("'" + expectedString + + "' missing from stderr: [" + stderr + "]\n"); + } + } + + /** + * Verify that the stdout and stderr contents of output buffer does not + * contain the string + * + * @param expectedString + * String that the buffer should not contain + * @throws RuntimeException + * If the string was found + */ + public void shouldNotContain(String notExpectedString) { + if (stdout.contains(notExpectedString)) { + throw new RuntimeException("'" + notExpectedString + + "' found in stdout: [" + stdout + "]\n"); + } + if (stderr.contains(notExpectedString)) { + throw new RuntimeException("'" + notExpectedString + + "' found in stderr: [" + stderr + "]\n"); + } + } + + /** + * Verify that the stdout contents of output buffer does not contain the + * string + * + * @param expectedString + * String that the buffer should not contain + * @throws RuntimeException + * If the string was found + */ + public void stdoutShouldNotContain(String notExpectedString) { + if (stdout.contains(notExpectedString)) { + throw new RuntimeException("'" + notExpectedString + + "' found in stdout: [" + stdout + "]\n"); + } + } + + /** + * Verify that the stderr contents of output buffer does not contain the + * string + * + * @param expectedString + * String that the buffer should not contain + * @throws RuntimeException + * If the string was found + */ + public void stderrShouldNotContain(String notExpectedString) { + if (stderr.contains(notExpectedString)) { + throw new RuntimeException("'" + notExpectedString + + "' found in stderr: [" + stderr + "]\n"); + } + } + + /** + * Verify that the stdout and stderr contents of output buffer matches + * the pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public void shouldMatch(String pattern) { + Matcher stdoutMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + Matcher stderrMatcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (!stdoutMatcher.find() && !stderrMatcher.find()) { + throw new RuntimeException("'" + pattern + + "' missing from stdout/stderr: [" + stdout + stderr + + "]\n"); + } + } + + /** + * Verify that the stdout contents of output buffer matches the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public void stdoutShouldMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (!matcher.find()) { + throw new RuntimeException("'" + pattern + + "' missing from stdout: [" + stdout + "]\n"); + } + } + + /** + * Verify that the stderr contents of output buffer matches the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was not found + */ + public void stderrShouldMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (!matcher.find()) { + throw new RuntimeException("'" + pattern + + "' missing from stderr: [" + stderr + "]\n"); + } + } + + /** + * Verify that the stdout and stderr contents of output buffer does not + * match the pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public void shouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (matcher.find()) { + throw new RuntimeException("'" + pattern + + "' found in stdout: [" + stdout + "]\n"); + } + matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (matcher.find()) { + throw new RuntimeException("'" + pattern + + "' found in stderr: [" + stderr + "]\n"); + } + } + + /** + * Verify that the stdout contents of output buffer does not match the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public void stdoutShouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stdout); + if (matcher.find()) { + throw new RuntimeException("'" + pattern + + "' found in stdout: [" + stdout + "]\n"); + } + } + + /** + * Verify that the stderr contents of output buffer does not match the + * pattern + * + * @param pattern + * @throws RuntimeException If the pattern was found + */ + public void stderrShouldNotMatch(String pattern) { + Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(stderr); + if (matcher.find()) { + throw new RuntimeException("'" + pattern + + "' found in stderr: [" + stderr + "]\n"); + } + } + + /** + * Verifiy the exit value of the process + * + * @param expectedExitValue + * Expected exit value from process + * @throws RuntimeException + * If the exit value from the process did not match the expected + * value + */ + public void shouldHaveExitValue(int expectedExitValue) { + if (getExitValue() != expectedExitValue) { + throw new RuntimeException("Exit value " + getExitValue() + + " , expected to get " + expectedExitValue); + } + } + + /** + * Get the contents of the output buffer (stdout and stderr) + * + * @return Content of the output buffer + */ + public String getOutput() { + return stdout + stderr; + } + + /** + * Get the contents of the stdout buffer + * + * @return Content of the stdout buffer + */ + public String getStdout() { + return stdout; + } + + /** + * Get the contents of the stderr buffer + * + * @return Content of the stderr buffer + */ + public String getStderr() { + return stderr; + } + + /** + * Get the process exit value + * + * @return Process exit value + */ + public int getExitValue() { + return exitValue; + } +} diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java new file mode 100644 index 00000000000..b5e021e8a9d --- /dev/null +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.testlibrary; + +public class OutputBuffer { + private final String stdout; + private final String stderr; + + /** + * Create an OutputBuffer, a class for storing and managing stdout and + * stderr results separately + * + * @param stdout + * stdout result + * @param stderr + * stderr result + */ + public OutputBuffer(String stdout, String stderr) { + this.stdout = stdout; + this.stderr = stderr; + } + + /** + * Returns the stdout result + * + * @return stdout result + */ + public String getStdout() { + return stdout; + } + + /** + * Returns the stderr result + * + * @return stderr result + */ + public String getStderr() { + return stderr; + } +} diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java new file mode 100644 index 00000000000..16783aebc06 --- /dev/null +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.testlibrary; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; + +import sun.management.VMManagement; + +public final class ProcessTools { + + private ProcessTools() { + } + + /** + * Pumps stdout and stderr from running the process into a String. + * + * @param processHandler + * ProcessHandler to run. + * @return Output from process. + * @throws IOException + * If an I/O error occurs. + */ + public static OutputBuffer getOutput(ProcessBuilder processBuilder) + throws IOException { + return getOutput(processBuilder.start()); + } + + /** + * Pumps stdout and stderr the running process into a String. + * + * @param process + * Process to pump. + * @return Output from process. + * @throws IOException + * If an I/O error occurs. + */ + public static OutputBuffer getOutput(Process process) throws IOException { + ByteArrayOutputStream stderrBuffer = new ByteArrayOutputStream(); + ByteArrayOutputStream stdoutBuffer = new ByteArrayOutputStream(); + StreamPumper outPumper = new StreamPumper(process.getInputStream(), + stdoutBuffer); + StreamPumper errPumper = new StreamPumper(process.getErrorStream(), + stderrBuffer); + Thread outPumperThread = new Thread(outPumper); + Thread errPumperThread = new Thread(errPumper); + + outPumperThread.setDaemon(true); + errPumperThread.setDaemon(true); + + outPumperThread.start(); + errPumperThread.start(); + + try { + process.waitFor(); + outPumperThread.join(); + errPumperThread.join(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return null; + } + + return new OutputBuffer(stdoutBuffer.toString(), + stderrBuffer.toString()); + } + + /** + * Get the process id of the current running Java process + * + * @return Process id + */ + public static int getProcessId() throws Exception { + + // Get the current process id using a reflection hack + RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); + Field jvm = runtime.getClass().getDeclaredField("jvm"); + + jvm.setAccessible(true); + VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime); + + Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId"); + + pid_method.setAccessible(true); + + int pid = (Integer) pid_method.invoke(mgmt); + + return pid; + } + + /** + * Get platform specific VM arguments (e.g. -d64 on 64bit Solaris) + * + * @return String[] with platform specific arguments, empty if there are + * none + */ + public static String[] getPlatformSpecificVMArgs() { + String osName = System.getProperty("os.name"); + String dataModel = System.getProperty("sun.arch.data.model"); + + if (osName.equals("SunOS") && dataModel.equals("64")) { + return new String[] { "-d64" }; + } + + return new String[] {}; + } + + /** + * Create ProcessBuilder using the java launcher from the jdk to be tested + * and with any platform specific arguments prepended + */ + public static ProcessBuilder createJavaProcessBuilder(String... command) + throws Exception { + String javapath = JdkFinder.getJavaLauncher(false); + + ArrayList args = new ArrayList<>(); + args.add(javapath); + Collections.addAll(args, getPlatformSpecificVMArgs()); + Collections.addAll(args, command); + + return new ProcessBuilder(args.toArray(new String[args.size()])); + + } + +} diff --git a/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java b/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java new file mode 100644 index 00000000000..60adca4e3da --- /dev/null +++ b/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2013, 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. + */ + +package jdk.testlibrary; + +import java.io.OutputStream; +import java.io.InputStream; +import java.io.IOException; + +public final class StreamPumper implements Runnable { + + private static final int BUF_SIZE = 256; + + private final OutputStream out; + private final InputStream in; + + /** + * Create a StreamPumper that reads from in and writes to out. + * + * @param in + * The stream to read from. + * @param out + * The stream to write to. + */ + public StreamPumper(InputStream in, OutputStream out) { + this.in = in; + this.out = out; + } + + /** + * Implements Thread.run(). Continuously read from {@code in} and write to + * {@code out} until {@code in} has reached end of stream. Abort on + * interruption. Abort on IOExceptions. + */ + @Override + public void run() { + int length; + InputStream localIn = in; + OutputStream localOut = out; + byte[] buffer = new byte[BUF_SIZE]; + + try { + while ((length = localIn.read(buffer)) > 0 && !Thread.interrupted()) { + localOut.write(buffer, 0, length); + } + } catch (IOException e) { + // Just abort if something like this happens. + e.printStackTrace(); + } finally { + try { + localOut.flush(); + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} From ea5819f8d36ba632a81e7654181701f3d2053d19 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Fri, 8 Feb 2013 09:35:14 -0800 Subject: [PATCH 06/39] 8007038: ArrayIndexOutOfBoundsException on calling localizedDateTime().print() with JapaneseChrono Reviewed-by: okutsu --- .../provider/CalendarNameProviderImpl.java | 3 + jdk/test/java/util/Calendar/Bug8007038.java | 108 ++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 jdk/test/java/util/Calendar/Bug8007038.java diff --git a/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java b/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java index 6aa2893e173..79cbe0a4d60 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java +++ b/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java @@ -58,6 +58,9 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av if (field == DAY_OF_WEEK || field == YEAR) { --value; } + if (value < 0 || value >= strings.length) { + return null; + } name = strings[value]; // If name is empty in standalone, try its `format' style. if (name.length() == 0 diff --git a/jdk/test/java/util/Calendar/Bug8007038.java b/jdk/test/java/util/Calendar/Bug8007038.java new file mode 100644 index 00000000000..e4f1a66082b --- /dev/null +++ b/jdk/test/java/util/Calendar/Bug8007038.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013, 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 8007038 + * @summary Verify ArrayIndexOutOfBoundsException is not thrown on + * on calling localizedDateTime().print() with JapaneseChrono + * @compile -XDignore.symbol.file Bug8007038.java + * @run main Bug8007038 + */ + +import java.util.*; +import static java.util.Calendar.*; +import sun.util.locale.provider.CalendarDataUtility; + +public class Bug8007038 { + private final static String[] calTypes = { + "gregory", + "buddhist", + "japanese", + "roc", + "islamic", + }; + private final static int[][] eraMinMax = { + {GregorianCalendar.BC, GregorianCalendar.AD}, + {0, 1}, + {0, 4}, + {0, 1}, + {0, 1}, + {0, 1}, + }; + private final static Locale[] testLocs = { + Locale.ROOT, + Locale.forLanguageTag("ja-JP-u-ca-japanese"), + Locale.forLanguageTag("th-TH"), + Locale.forLanguageTag("th-TH-u-ca-buddhist"), + Locale.forLanguageTag("zh-TW-u-ca-roc"), + Locale.forLanguageTag("ar-EG-u-ca-islamic"), + Locale.forLanguageTag("xx-YY-u-ca-bogus"), + }; + + public static void main(String[] args) { + for (int calIdx = 0; calIdx < calTypes.length; calIdx++) { + for (int locIdx = 0; locIdx < testLocs.length; locIdx++) { + // era + for (int fieldIdx = eraMinMax[calIdx][0]; fieldIdx <= eraMinMax[calIdx][1]; fieldIdx++) { + checkValueRange(calTypes[calIdx], ERA, fieldIdx, LONG, testLocs[locIdx], true); + } + checkValueRange(calTypes[calIdx], ERA, eraMinMax[calIdx][0]-1, LONG, + testLocs[locIdx], false); + checkValueRange(calTypes[calIdx], ERA, eraMinMax[calIdx][1]+1, + LONG, testLocs[locIdx], false); + + // month + for (int fieldIdx = JANUARY; fieldIdx <= UNDECIMBER ; fieldIdx++) { + checkValueRange(calTypes[calIdx], MONTH, fieldIdx, LONG, testLocs[locIdx], true); + } + checkValueRange(calTypes[calIdx], MONTH, JANUARY-1, LONG, testLocs[locIdx], false); + checkValueRange(calTypes[calIdx], MONTH, UNDECIMBER+1, LONG, testLocs[locIdx], false); + + // day-of-week + for (int fieldIdx = SUNDAY; fieldIdx <= SATURDAY; fieldIdx++) { + checkValueRange(calTypes[calIdx], DAY_OF_WEEK, fieldIdx, LONG, testLocs[locIdx], true); + } + checkValueRange(calTypes[calIdx], DAY_OF_WEEK, SUNDAY-1, LONG, testLocs[locIdx], false); + checkValueRange(calTypes[calIdx], DAY_OF_WEEK, SATURDAY+1, LONG, testLocs[locIdx], false); + + // am/pm + for (int fieldIdx = AM; fieldIdx <= PM; fieldIdx++) { + checkValueRange(calTypes[calIdx], AM_PM, fieldIdx, LONG, testLocs[locIdx], true); + } + checkValueRange(calTypes[calIdx], AM_PM, AM-1, LONG, testLocs[locIdx], false); + checkValueRange(calTypes[calIdx], AM_PM, PM+1, LONG, testLocs[locIdx], false); + } + } + } + + private static void checkValueRange(String calType, int field, int value, int style, Locale l, boolean isNonNull) { + String ret = CalendarDataUtility.retrieveFieldValueName(calType, field, value, style, l); + System.out.print("retrieveFieldValueName("+calType+", "+field+", "+value+", "+style+", "+l+")"); + if ((ret != null) == isNonNull) { + System.out.println(" returned "+ret); + } else { + throw new RuntimeException("The call returned "+ret); + } + } +} From 826105d54895223e1a3dc976a727b7062aaf5a24 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Fri, 8 Feb 2013 16:00:23 -0800 Subject: [PATCH 07/39] 8005623: Retrofit FunctionalInterface annotations to core platform interfaces Reviewed-by: mduigou, chegar, alanb --- jdk/src/share/classes/java/io/Closeable.java | 4 ++-- jdk/src/share/classes/java/io/FileFilter.java | 4 ++-- jdk/src/share/classes/java/io/FilenameFilter.java | 6 +++--- jdk/src/share/classes/java/io/Flushable.java | 4 ++-- jdk/src/share/classes/java/lang/AutoCloseable.java | 3 ++- jdk/src/share/classes/java/lang/Comparable.java | 4 ++-- jdk/src/share/classes/java/lang/Iterable.java | 3 ++- jdk/src/share/classes/java/lang/Readable.java | 5 ++--- jdk/src/share/classes/java/lang/Runnable.java | 6 +++--- jdk/src/share/classes/java/lang/Thread.java | 3 ++- jdk/src/share/classes/java/nio/file/DirectoryStream.java | 6 +++--- jdk/src/share/classes/java/nio/file/PathMatcher.java | 4 ++-- jdk/src/share/classes/java/util/Comparator.java | 4 ++-- .../share/classes/java/util/function/BinaryOperator.java | 3 ++- jdk/src/share/classes/java/util/function/Block.java | 3 ++- .../classes/java/util/function/DoubleBinaryOperator.java | 3 ++- jdk/src/share/classes/java/util/function/DoubleBlock.java | 3 ++- .../share/classes/java/util/function/DoubleFunction.java | 3 ++- .../share/classes/java/util/function/DoubleSupplier.java | 3 ++- .../classes/java/util/function/DoubleUnaryOperator.java | 3 ++- jdk/src/share/classes/java/util/function/Function.java | 3 ++- .../share/classes/java/util/function/IntBinaryOperator.java | 3 ++- jdk/src/share/classes/java/util/function/IntBlock.java | 3 ++- jdk/src/share/classes/java/util/function/IntFunction.java | 3 ++- jdk/src/share/classes/java/util/function/IntSupplier.java | 3 ++- .../share/classes/java/util/function/IntUnaryOperator.java | 3 ++- .../classes/java/util/function/LongBinaryOperator.java | 3 ++- jdk/src/share/classes/java/util/function/LongBlock.java | 3 ++- jdk/src/share/classes/java/util/function/LongFunction.java | 3 ++- jdk/src/share/classes/java/util/function/LongSupplier.java | 3 ++- .../share/classes/java/util/function/LongUnaryOperator.java | 3 ++- jdk/src/share/classes/java/util/function/Predicate.java | 3 ++- jdk/src/share/classes/java/util/function/Supplier.java | 3 ++- jdk/src/share/classes/java/util/function/UnaryOperator.java | 3 ++- jdk/src/share/classes/java/util/logging/Filter.java | 5 ++--- .../classes/java/util/prefs/PreferenceChangeListener.java | 3 ++- 36 files changed, 75 insertions(+), 52 deletions(-) diff --git a/jdk/src/share/classes/java/io/Closeable.java b/jdk/src/share/classes/java/io/Closeable.java index 26c7ea00e36..530cde86171 100644 --- a/jdk/src/share/classes/java/io/Closeable.java +++ b/jdk/src/share/classes/java/io/Closeable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -34,7 +34,7 @@ import java.io.IOException; * * @since 1.5 */ - +@FunctionalInterface public interface Closeable extends AutoCloseable { /** diff --git a/jdk/src/share/classes/java/io/FileFilter.java b/jdk/src/share/classes/java/io/FileFilter.java index 15f00d630d3..f973d77cea7 100644 --- a/jdk/src/share/classes/java/io/FileFilter.java +++ b/jdk/src/share/classes/java/io/FileFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, 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 @@ -35,6 +35,7 @@ package java.io; * * @since 1.2 */ +@FunctionalInterface public interface FileFilter { /** @@ -46,5 +47,4 @@ public interface FileFilter { * should be included */ boolean accept(File pathname); - } diff --git a/jdk/src/share/classes/java/io/FilenameFilter.java b/jdk/src/share/classes/java/io/FilenameFilter.java index 915adf54097..71b88af4646 100644 --- a/jdk/src/share/classes/java/io/FilenameFilter.java +++ b/jdk/src/share/classes/java/io/FilenameFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, 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 @@ -39,8 +39,8 @@ package java.io; * @see java.io.File#list(java.io.FilenameFilter) * @since JDK1.0 */ -public -interface FilenameFilter { +@FunctionalInterface +public interface FilenameFilter { /** * Tests if a specified file should be included in a file list. * diff --git a/jdk/src/share/classes/java/io/Flushable.java b/jdk/src/share/classes/java/io/Flushable.java index e598ea88426..8912316d4d2 100644 --- a/jdk/src/share/classes/java/io/Flushable.java +++ b/jdk/src/share/classes/java/io/Flushable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2013, 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 @@ -34,7 +34,7 @@ import java.io.IOException; * * @since 1.5 */ - +@FunctionalInterface public interface Flushable { /** diff --git a/jdk/src/share/classes/java/lang/AutoCloseable.java b/jdk/src/share/classes/java/lang/AutoCloseable.java index d928a9d0f1c..ce0fffe5939 100644 --- a/jdk/src/share/classes/java/lang/AutoCloseable.java +++ b/jdk/src/share/classes/java/lang/AutoCloseable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2013, 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 @@ -31,6 +31,7 @@ package java.lang; * @author Josh Bloch * @since 1.7 */ +@FunctionalInterface public interface AutoCloseable { /** * Closes this resource, relinquishing any underlying resources. diff --git a/jdk/src/share/classes/java/lang/Comparable.java b/jdk/src/share/classes/java/lang/Comparable.java index d8531972bb3..123e10aa4da 100644 --- a/jdk/src/share/classes/java/lang/Comparable.java +++ b/jdk/src/share/classes/java/lang/Comparable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, 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 @@ -93,7 +93,7 @@ import java.util.*; * @see java.util.Comparator * @since 1.2 */ - +@FunctionalInterface public interface Comparable { /** * Compares this object with the specified object for order. Returns a diff --git a/jdk/src/share/classes/java/lang/Iterable.java b/jdk/src/share/classes/java/lang/Iterable.java index 24efc8644af..a47319243f0 100644 --- a/jdk/src/share/classes/java/lang/Iterable.java +++ b/jdk/src/share/classes/java/lang/Iterable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -35,6 +35,7 @@ import java.util.Iterator; * * @since 1.5 */ +@FunctionalInterface public interface Iterable { /** diff --git a/jdk/src/share/classes/java/lang/Readable.java b/jdk/src/share/classes/java/lang/Readable.java index 7e4e924390e..e3d08d34b62 100644 --- a/jdk/src/share/classes/java/lang/Readable.java +++ b/jdk/src/share/classes/java/lang/Readable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -34,7 +34,7 @@ import java.io.IOException; * * @since 1.5 */ - +@FunctionalInterface public interface Readable { /** @@ -51,5 +51,4 @@ public interface Readable { * @throws java.nio.ReadOnlyBufferException if cb is a read only buffer */ public int read(java.nio.CharBuffer cb) throws IOException; - } diff --git a/jdk/src/share/classes/java/lang/Runnable.java b/jdk/src/share/classes/java/lang/Runnable.java index 6aeb8928c98..b9f1df7a0cc 100644 --- a/jdk/src/share/classes/java/lang/Runnable.java +++ b/jdk/src/share/classes/java/lang/Runnable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, 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 @@ -52,8 +52,8 @@ package java.lang; * @see java.util.concurrent.Callable * @since JDK1.0 */ -public -interface Runnable { +@FunctionalInterface +public interface Runnable { /** * When an object implementing interface Runnable is used * to create a thread, starting the thread causes the object's diff --git a/jdk/src/share/classes/java/lang/Thread.java b/jdk/src/share/classes/java/lang/Thread.java index 64987bdc2fa..8aab573ded7 100644 --- a/jdk/src/share/classes/java/lang/Thread.java +++ b/jdk/src/share/classes/java/lang/Thread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, 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 @@ -1851,6 +1851,7 @@ class Thread implements Runnable { * @see ThreadGroup#uncaughtException * @since 1.5 */ + @FunctionalInterface public interface UncaughtExceptionHandler { /** * Method invoked when the given thread terminates due to the diff --git a/jdk/src/share/classes/java/nio/file/DirectoryStream.java b/jdk/src/share/classes/java/nio/file/DirectoryStream.java index dd13c9a3f6b..48da97e7b4d 100644 --- a/jdk/src/share/classes/java/nio/file/DirectoryStream.java +++ b/jdk/src/share/classes/java/nio/file/DirectoryStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, 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 @@ -117,8 +117,7 @@ import java.io.IOException; */ public interface DirectoryStream - extends Closeable, Iterable -{ + extends Closeable, Iterable { /** * An interface that is implemented by objects that decide if a directory * entry should be accepted or filtered. A {@code Filter} is passed as the @@ -130,6 +129,7 @@ public interface DirectoryStream * * @since 1.7 */ + @FunctionalInterface public static interface Filter { /** * Decides if the given directory entry should be accepted or filtered. diff --git a/jdk/src/share/classes/java/nio/file/PathMatcher.java b/jdk/src/share/classes/java/nio/file/PathMatcher.java index ab4b7ce0f00..24e61493c8b 100644 --- a/jdk/src/share/classes/java/nio/file/PathMatcher.java +++ b/jdk/src/share/classes/java/nio/file/PathMatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, 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 @@ -34,7 +34,7 @@ package java.nio.file; * @see FileSystem#getPathMatcher * @see Files#newDirectoryStream(Path,String) */ - +@FunctionalInterface public interface PathMatcher { /** * Tells if given path matches this matcher's pattern. diff --git a/jdk/src/share/classes/java/util/Comparator.java b/jdk/src/share/classes/java/util/Comparator.java index 453e9b71909..35ead373b82 100644 --- a/jdk/src/share/classes/java/util/Comparator.java +++ b/jdk/src/share/classes/java/util/Comparator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, 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 @@ -98,7 +98,7 @@ package java.util; * @see java.io.Serializable * @since 1.2 */ - +@FunctionalInterface public interface Comparator { /** * Compares its two arguments for order. Returns a negative integer, diff --git a/jdk/src/share/classes/java/util/function/BinaryOperator.java b/jdk/src/share/classes/java/util/function/BinaryOperator.java index 37653b63b37..2e9050e59f2 100644 --- a/jdk/src/share/classes/java/util/function/BinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/BinaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, 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 @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface BinaryOperator { /** diff --git a/jdk/src/share/classes/java/util/function/Block.java b/jdk/src/share/classes/java/util/function/Block.java index e468396be22..c41e9a45a5a 100644 --- a/jdk/src/share/classes/java/util/function/Block.java +++ b/jdk/src/share/classes/java/util/function/Block.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, 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 @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface Block { /** diff --git a/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java b/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java index 07ff741be96..f63403bb37e 100644 --- a/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/DoubleBinaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -29,6 +29,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface DoubleBinaryOperator /* extends BinaryOperator */ { // // @Override diff --git a/jdk/src/share/classes/java/util/function/DoubleBlock.java b/jdk/src/share/classes/java/util/function/DoubleBlock.java index d5abd87b880..ae000841ae1 100644 --- a/jdk/src/share/classes/java/util/function/DoubleBlock.java +++ b/jdk/src/share/classes/java/util/function/DoubleBlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, 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 @@ -33,6 +33,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface DoubleBlock { /** diff --git a/jdk/src/share/classes/java/util/function/DoubleFunction.java b/jdk/src/share/classes/java/util/function/DoubleFunction.java index 06c405e6d8c..d9c522c8e94 100644 --- a/jdk/src/share/classes/java/util/function/DoubleFunction.java +++ b/jdk/src/share/classes/java/util/function/DoubleFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface DoubleFunction { /** diff --git a/jdk/src/share/classes/java/util/function/DoubleSupplier.java b/jdk/src/share/classes/java/util/function/DoubleSupplier.java index 7e718a3c141..19d75353045 100644 --- a/jdk/src/share/classes/java/util/function/DoubleSupplier.java +++ b/jdk/src/share/classes/java/util/function/DoubleSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface DoubleSupplier { /** diff --git a/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java b/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java index b9ac7f6fda7..3843f8bc7ee 100644 --- a/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java +++ b/jdk/src/share/classes/java/util/function/DoubleUnaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -30,6 +30,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface DoubleUnaryOperator { /** diff --git a/jdk/src/share/classes/java/util/function/Function.java b/jdk/src/share/classes/java/util/function/Function.java index ce8ab1ed2e8..82bae01701d 100644 --- a/jdk/src/share/classes/java/util/function/Function.java +++ b/jdk/src/share/classes/java/util/function/Function.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, 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 @@ -35,6 +35,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface Function { /** diff --git a/jdk/src/share/classes/java/util/function/IntBinaryOperator.java b/jdk/src/share/classes/java/util/function/IntBinaryOperator.java index 312fb2db046..e25c2ba101f 100644 --- a/jdk/src/share/classes/java/util/function/IntBinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/IntBinaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -29,6 +29,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface IntBinaryOperator { /** diff --git a/jdk/src/share/classes/java/util/function/IntBlock.java b/jdk/src/share/classes/java/util/function/IntBlock.java index e0163163e1e..33cdbe79f51 100644 --- a/jdk/src/share/classes/java/util/function/IntBlock.java +++ b/jdk/src/share/classes/java/util/function/IntBlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, 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 @@ -33,6 +33,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface IntBlock { /** diff --git a/jdk/src/share/classes/java/util/function/IntFunction.java b/jdk/src/share/classes/java/util/function/IntFunction.java index af8d4486254..6e1418533fe 100644 --- a/jdk/src/share/classes/java/util/function/IntFunction.java +++ b/jdk/src/share/classes/java/util/function/IntFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface IntFunction { /** diff --git a/jdk/src/share/classes/java/util/function/IntSupplier.java b/jdk/src/share/classes/java/util/function/IntSupplier.java index e930e0bc407..c73fc84e3be 100644 --- a/jdk/src/share/classes/java/util/function/IntSupplier.java +++ b/jdk/src/share/classes/java/util/function/IntSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface IntSupplier { /** diff --git a/jdk/src/share/classes/java/util/function/IntUnaryOperator.java b/jdk/src/share/classes/java/util/function/IntUnaryOperator.java index 315619dcab1..2c429951c28 100644 --- a/jdk/src/share/classes/java/util/function/IntUnaryOperator.java +++ b/jdk/src/share/classes/java/util/function/IntUnaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -29,6 +29,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface IntUnaryOperator { /** diff --git a/jdk/src/share/classes/java/util/function/LongBinaryOperator.java b/jdk/src/share/classes/java/util/function/LongBinaryOperator.java index 07056784e34..f767c92a355 100644 --- a/jdk/src/share/classes/java/util/function/LongBinaryOperator.java +++ b/jdk/src/share/classes/java/util/function/LongBinaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -29,6 +29,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface LongBinaryOperator { /** diff --git a/jdk/src/share/classes/java/util/function/LongBlock.java b/jdk/src/share/classes/java/util/function/LongBlock.java index d9af3660f8b..71606ecf9ed 100644 --- a/jdk/src/share/classes/java/util/function/LongBlock.java +++ b/jdk/src/share/classes/java/util/function/LongBlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, 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 @@ -33,6 +33,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface LongBlock { /** diff --git a/jdk/src/share/classes/java/util/function/LongFunction.java b/jdk/src/share/classes/java/util/function/LongFunction.java index 449543d0764..61c4fbf6475 100644 --- a/jdk/src/share/classes/java/util/function/LongFunction.java +++ b/jdk/src/share/classes/java/util/function/LongFunction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface LongFunction { /** diff --git a/jdk/src/share/classes/java/util/function/LongSupplier.java b/jdk/src/share/classes/java/util/function/LongSupplier.java index fb76068c970..f56ad7df282 100644 --- a/jdk/src/share/classes/java/util/function/LongSupplier.java +++ b/jdk/src/share/classes/java/util/function/LongSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface LongSupplier { /** diff --git a/jdk/src/share/classes/java/util/function/LongUnaryOperator.java b/jdk/src/share/classes/java/util/function/LongUnaryOperator.java index ea2c1fc7338..f27ddf5a81a 100644 --- a/jdk/src/share/classes/java/util/function/LongUnaryOperator.java +++ b/jdk/src/share/classes/java/util/function/LongUnaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -29,6 +29,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface LongUnaryOperator { /** diff --git a/jdk/src/share/classes/java/util/function/Predicate.java b/jdk/src/share/classes/java/util/function/Predicate.java index f4e6196fbce..9b440787485 100644 --- a/jdk/src/share/classes/java/util/function/Predicate.java +++ b/jdk/src/share/classes/java/util/function/Predicate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2013, 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 @@ -31,6 +31,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface Predicate { /** diff --git a/jdk/src/share/classes/java/util/function/Supplier.java b/jdk/src/share/classes/java/util/function/Supplier.java index 404af55af99..60bc801eb91 100644 --- a/jdk/src/share/classes/java/util/function/Supplier.java +++ b/jdk/src/share/classes/java/util/function/Supplier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface Supplier { /** diff --git a/jdk/src/share/classes/java/util/function/UnaryOperator.java b/jdk/src/share/classes/java/util/function/UnaryOperator.java index 9fa99c8d96a..a8aaa0dcd6b 100644 --- a/jdk/src/share/classes/java/util/function/UnaryOperator.java +++ b/jdk/src/share/classes/java/util/function/UnaryOperator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -32,6 +32,7 @@ package java.util.function; * * @since 1.8 */ +@FunctionalInterface public interface UnaryOperator { /** diff --git a/jdk/src/share/classes/java/util/logging/Filter.java b/jdk/src/share/classes/java/util/logging/Filter.java index 73bbad11448..43837073114 100644 --- a/jdk/src/share/classes/java/util/logging/Filter.java +++ b/jdk/src/share/classes/java/util/logging/Filter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, 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 @@ -37,7 +37,7 @@ package java.util.logging; * * @since 1.4 */ - +@FunctionalInterface public interface Filter { /** @@ -46,5 +46,4 @@ public interface Filter { * @return true if the log record should be published. */ public boolean isLoggable(LogRecord record); - } diff --git a/jdk/src/share/classes/java/util/prefs/PreferenceChangeListener.java b/jdk/src/share/classes/java/util/prefs/PreferenceChangeListener.java index 2c0c51e867a..0fb96c598cb 100644 --- a/jdk/src/share/classes/java/util/prefs/PreferenceChangeListener.java +++ b/jdk/src/share/classes/java/util/prefs/PreferenceChangeListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2013, 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 @@ -34,6 +34,7 @@ package java.util.prefs; * @see NodeChangeListener * @since 1.4 */ +@FunctionalInterface public interface PreferenceChangeListener extends java.util.EventListener { /** * This method gets called when a preference is added, removed or when From 724f325f44f63a2b7383655a9d804d166e3e26a7 Mon Sep 17 00:00:00 2001 From: Doug Lea Date: Sat, 9 Feb 2013 08:35:57 +0000 Subject: [PATCH 08/39] 8005697: Add StampedLock Reviewed-by: chegar, alanb, dice, martin --- jdk/make/java/java/FILES_java.gmk | 1 + .../util/concurrent/locks/LockSupport.java | 77 +- .../util/concurrent/locks/StampedLock.java | 1377 +++++++++++++++++ .../concurrent/locks/StampedLock/Basic.java | 609 ++++++++ 4 files changed, 2040 insertions(+), 24 deletions(-) create mode 100644 jdk/src/share/classes/java/util/concurrent/locks/StampedLock.java create mode 100644 jdk/test/java/util/concurrent/locks/StampedLock/Basic.java diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk index bf0f9833670..bcf92eb44d0 100644 --- a/jdk/make/java/java/FILES_java.gmk +++ b/jdk/make/java/java/FILES_java.gmk @@ -389,6 +389,7 @@ JAVA_JAVA_java = \ java/util/concurrent/locks/ReadWriteLock.java \ java/util/concurrent/locks/ReentrantLock.java \ java/util/concurrent/locks/ReentrantReadWriteLock.java \ + java/util/concurrent/locks/StampedLock.java \ java/util/regex/Pattern.java \ java/util/regex/Matcher.java \ java/util/regex/MatchResult.java \ diff --git a/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java b/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java index 08bd8878a81..20abfacc3c8 100644 --- a/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java +++ b/jdk/src/share/classes/java/util/concurrent/locks/LockSupport.java @@ -101,14 +101,14 @@ import sun.misc.Unsafe; * // Block while not first in queue or cannot acquire lock * while (waiters.peek() != current || * !locked.compareAndSet(false, true)) { - * LockSupport.park(this); - * if (Thread.interrupted()) // ignore interrupts while waiting - * wasInterrupted = true; + * LockSupport.park(this); + * if (Thread.interrupted()) // ignore interrupts while waiting + * wasInterrupted = true; * } * * waiters.remove(); * if (wasInterrupted) // reassert interrupt status on exit - * current.interrupt(); + * current.interrupt(); * } * * public void unlock() { @@ -120,20 +120,9 @@ import sun.misc.Unsafe; public class LockSupport { private LockSupport() {} // Cannot be instantiated. - // Hotspot implementation via intrinsics API - private static final Unsafe unsafe = Unsafe.getUnsafe(); - private static final long parkBlockerOffset; - - static { - try { - parkBlockerOffset = unsafe.objectFieldOffset - (java.lang.Thread.class.getDeclaredField("parkBlocker")); - } catch (Exception ex) { throw new Error(ex); } - } - private static void setBlocker(Thread t, Object arg) { // Even though volatile, hotspot doesn't need a write barrier here. - unsafe.putObject(t, parkBlockerOffset, arg); + UNSAFE.putObject(t, parkBlockerOffset, arg); } /** @@ -149,7 +138,7 @@ public class LockSupport { */ public static void unpark(Thread thread) { if (thread != null) - unsafe.unpark(thread); + UNSAFE.unpark(thread); } /** @@ -183,7 +172,7 @@ public class LockSupport { public static void park(Object blocker) { Thread t = Thread.currentThread(); setBlocker(t, blocker); - unsafe.park(false, 0L); + UNSAFE.park(false, 0L); setBlocker(t, null); } @@ -223,7 +212,7 @@ public class LockSupport { if (nanos > 0) { Thread t = Thread.currentThread(); setBlocker(t, blocker); - unsafe.park(false, nanos); + UNSAFE.park(false, nanos); setBlocker(t, null); } } @@ -264,7 +253,7 @@ public class LockSupport { public static void parkUntil(Object blocker, long deadline) { Thread t = Thread.currentThread(); setBlocker(t, blocker); - unsafe.park(true, deadline); + UNSAFE.park(true, deadline); setBlocker(t, null); } @@ -283,7 +272,7 @@ public class LockSupport { public static Object getBlocker(Thread t) { if (t == null) throw new NullPointerException(); - return unsafe.getObjectVolatile(t, parkBlockerOffset); + return UNSAFE.getObjectVolatile(t, parkBlockerOffset); } /** @@ -312,7 +301,7 @@ public class LockSupport { * for example, the interrupt status of the thread upon return. */ public static void park() { - unsafe.park(false, 0L); + UNSAFE.park(false, 0L); } /** @@ -346,7 +335,7 @@ public class LockSupport { */ public static void parkNanos(long nanos) { if (nanos > 0) - unsafe.park(false, nanos); + UNSAFE.park(false, nanos); } /** @@ -380,6 +369,46 @@ public class LockSupport { * to wait until */ public static void parkUntil(long deadline) { - unsafe.park(true, deadline); + UNSAFE.park(true, deadline); } + + /** + * Returns the pseudo-randomly initialized or updated secondary seed. + * Copied from ThreadLocalRandom due to package access restrictions. + */ + static final int nextSecondarySeed() { + int r; + Thread t = Thread.currentThread(); + if ((r = UNSAFE.getInt(t, SECONDARY)) != 0) { + r ^= r << 13; // xorshift + r ^= r >>> 17; + r ^= r << 5; + } + else if ((r = java.util.concurrent.ThreadLocalRandom.current().nextInt()) == 0) + r = 1; // avoid zero + UNSAFE.putInt(t, SECONDARY, r); + return r; + } + + // Hotspot implementation via intrinsics API + private static final sun.misc.Unsafe UNSAFE; + private static final long parkBlockerOffset; + private static final long SEED; + private static final long PROBE; + private static final long SECONDARY; + static { + try { + UNSAFE = sun.misc.Unsafe.getUnsafe(); + Class tk = Thread.class; + parkBlockerOffset = UNSAFE.objectFieldOffset + (tk.getDeclaredField("parkBlocker")); + SEED = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomSeed")); + PROBE = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomProbe")); + SECONDARY = UNSAFE.objectFieldOffset + (tk.getDeclaredField("threadLocalRandomSecondarySeed")); + } catch (Exception ex) { throw new Error(ex); } + } + } diff --git a/jdk/src/share/classes/java/util/concurrent/locks/StampedLock.java b/jdk/src/share/classes/java/util/concurrent/locks/StampedLock.java new file mode 100644 index 00000000000..0ca43f630f7 --- /dev/null +++ b/jdk/src/share/classes/java/util/concurrent/locks/StampedLock.java @@ -0,0 +1,1377 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +package java.util.concurrent.locks; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.LockSupport; + +/** + * A capability-based lock with three modes for controlling read/write + * access. The state of a StampedLock consists of a version and mode. + * Lock acquisition methods return a stamp that represents and + * controls access with respect to a lock state; "try" versions of + * these methods may instead return the special value zero to + * represent failure to acquire access. Lock release and conversion + * methods require stamps as arguments, and fail if they do not match + * the state of the lock. The three modes are: + * + *

+ * + *

This class also supports methods that conditionally provide + * conversions across the three modes. For example, method {@link + * #tryConvertToWriteLock} attempts to "upgrade" a mode, returning + * a valid write stamp if (1) already in writing mode (2) in reading + * mode and there are no other readers or (3) in optimistic mode and + * the lock is available. The forms of these methods are designed to + * help reduce some of the code bloat that otherwise occurs in + * retry-based designs. + * + *

StampedLocks are designed for use as internal utilities in the + * development of thread-safe components. Their use relies on + * knowledge of the internal properties of the data, objects, and + * methods they are protecting. They are not reentrant, so locked + * bodies should not call other unknown methods that may try to + * re-acquire locks (although you may pass a stamp to other methods + * that can use or convert it). The use of read lock modes relies on + * the associated code sections being side-effect-free. Unvalidated + * optimistic read sections cannot call methods that are not known to + * tolerate potential inconsistencies. Stamps use finite + * representations, and are not cryptographically secure (i.e., a + * valid stamp may be guessable). Stamp values may recycle after (no + * sooner than) one year of continuous operation. A stamp held without + * use or validation for longer than this period may fail to validate + * correctly. StampedLocks are serializable, but always deserialize + * into initial unlocked state, so they are not useful for remote + * locking. + * + *

The scheduling policy of StampedLock does not consistently + * prefer readers over writers or vice versa. All "try" methods are + * best-effort and do not necessarily conform to any scheduling or + * fairness policy. A zero return from any "try" method for acquiring + * or converting locks does not carry any information about the state + * of the lock; a subsequent invocation may succeed. + * + *

Because it supports coordinated usage across multiple lock + * modes, this class does not directly implement the {@link Lock} or + * {@link ReadWriteLock} interfaces. However, a StampedLock may be + * viewed {@link #asReadLock()}, {@link #asWriteLock()}, or {@link + * #asReadWriteLock()} in applications requiring only the associated + * set of functionality. + * + *

Sample Usage. The following illustrates some usage idioms + * in a class that maintains simple two-dimensional points. The sample + * code illustrates some try/catch conventions even though they are + * not strictly needed here because no exceptions can occur in their + * bodies.
+ * + *

{@code
+ * class Point {
+ *   private double x, y;
+ *   private final StampedLock sl = new StampedLock();
+ *
+ *   void move(double deltaX, double deltaY) { // an exclusively locked method
+ *     long stamp = sl.writeLock();
+ *     try {
+ *       x += deltaX;
+ *       y += deltaY;
+ *     } finally {
+ *       sl.unlockWrite(stamp);
+ *     }
+ *   }
+ *
+ *   double distanceFromOrigin() { // A read-only method
+ *     long stamp = sl.tryOptimisticRead();
+ *     double currentX = x, currentY = y;
+ *     if (!sl.validate(stamp)) {
+ *        stamp = sl.readLock();
+ *        try {
+ *          currentX = x;
+ *          currentY = y;
+ *        } finally {
+ *           sl.unlockRead(stamp);
+ *        }
+ *     }
+ *     return Math.sqrt(currentX * currentX + currentY * currentY);
+ *   }
+ *
+ *   void moveIfAtOrigin(double newX, double newY) { // upgrade
+ *     // Could instead start with optimistic, not read mode
+ *     long stamp = sl.readLock();
+ *     try {
+ *       while (x == 0.0 && y == 0.0) {
+ *         long ws = sl.tryConvertToWriteLock(stamp);
+ *         if (ws != 0L) {
+ *           stamp = ws;
+ *           x = newX;
+ *           y = newY;
+ *           break;
+ *         }
+ *         else {
+ *           sl.unlockRead(stamp);
+ *           stamp = sl.writeLock();
+ *         }
+ *       }
+ *     } finally {
+ *       sl.unlock(stamp);
+ *     }
+ *   }
+ * }}
+ * + * @since 1.8 + * @author Doug Lea + */ +public class StampedLock implements java.io.Serializable { + /* + * Algorithmic notes: + * + * The design employs elements of Sequence locks + * (as used in linux kernels; see Lameter's + * http://www.lameter.com/gelato2005.pdf + * and elsewhere; see + * Boehm's http://www.hpl.hp.com/techreports/2012/HPL-2012-68.html) + * and Ordered RW locks (see Shirako et al + * http://dl.acm.org/citation.cfm?id=2312015) + * + * Conceptually, the primary state of the lock includes a sequence + * number that is odd when write-locked and even otherwise. + * However, this is offset by a reader count that is non-zero when + * read-locked. The read count is ignored when validating + * "optimistic" seqlock-reader-style stamps. Because we must use + * a small finite number of bits (currently 7) for readers, a + * supplementary reader overflow word is used when the number of + * readers exceeds the count field. We do this by treating the max + * reader count value (RBITS) as a spinlock protecting overflow + * updates. + * + * Waiters use a modified form of CLH lock used in + * AbstractQueuedSynchronizer (see its internal documentation for + * a fuller account), where each node is tagged (field mode) as + * either a reader or writer. Sets of waiting readers are grouped + * (linked) under a common node (field cowait) so act as a single + * node with respect to most CLH mechanics. By virtue of the + * queue structure, wait nodes need not actually carry sequence + * numbers; we know each is greater than its predecessor. This + * simplifies the scheduling policy to a mainly-FIFO scheme that + * incorporates elements of Phase-Fair locks (see Brandenburg & + * Anderson, especially http://www.cs.unc.edu/~bbb/diss/). In + * particular, we use the phase-fair anti-barging rule: If an + * incoming reader arrives while read lock is held but there is a + * queued writer, this incoming reader is queued. (This rule is + * responsible for some of the complexity of method acquireRead, + * but without it, the lock becomes highly unfair.) + * + * These rules apply to threads actually queued. All tryLock forms + * opportunistically try to acquire locks regardless of preference + * rules, and so may "barge" their way in. Randomized spinning is + * used in the acquire methods to reduce (increasingly expensive) + * context switching while also avoiding sustained memory + * thrashing among many threads. We limit spins to the head of + * queue. A thread spin-waits up to SPINS times (where each + * iteration decreases spin count with 50% probability) before + * blocking. If, upon wakening it fails to obtain lock, and is + * still (or becomes) the first waiting thread (which indicates + * that some other thread barged and obtained lock), it escalates + * spins (up to MAX_HEAD_SPINS) to reduce the likelihood of + * continually losing to barging threads. + * + * Nearly all of these mechanics are carried out in methods + * acquireWrite and acquireRead, that, as typical of such code, + * sprawl out because actions and retries rely on consistent sets + * of locally cached reads. + * + * As noted in Boehm's paper (above), sequence validation (mainly + * method validate()) requires stricter ordering rules than apply + * to normal volatile reads (of "state"). To force orderings of + * reads before a validation and the validation itself in those + * cases where this is not already forced, we use + * Unsafe.loadFence. + * + * The memory layout keeps lock state and queue pointers together + * (normally on the same cache line). This usually works well for + * read-mostly loads. In most other cases, the natural tendency of + * adaptive-spin CLH locks to reduce memory contention lessens + * motivation to further spread out contended locations, but might + * be subject to future improvements. + */ + + private static final long serialVersionUID = -6001602636862214147L; + + /** Number of processors, for spin control */ + private static final int NCPU = Runtime.getRuntime().availableProcessors(); + + /** Maximum number of retries before blocking on acquisition */ + private static final int SPINS = (NCPU > 1) ? 1 << 6 : 0; + + /** Maximum number of retries before re-blocking */ + private static final int MAX_HEAD_SPINS = (NCPU > 1) ? 1 << 12 : 0; + + /** The period for yielding when waiting for overflow spinlock */ + private static final int OVERFLOW_YIELD_RATE = 7; // must be power 2 - 1 + + /** The number of bits to use for reader count before overflowing */ + private static final int LG_READERS = 7; + + // Values for lock state and stamp operations + private static final long RUNIT = 1L; + private static final long WBIT = 1L << LG_READERS; + private static final long RBITS = WBIT - 1L; + private static final long RFULL = RBITS - 1L; + private static final long ABITS = RBITS | WBIT; + private static final long SBITS = ~RBITS; // note overlap with ABITS + + // Initial value for lock state; avoid failure value zero + private static final long ORIGIN = WBIT << 1; + + // Special value from cancelled acquire methods so caller can throw IE + private static final long INTERRUPTED = 1L; + + // Values for node status; order matters + private static final int WAITING = -1; + private static final int CANCELLED = 1; + + // Modes for nodes (int not boolean to allow arithmetic) + private static final int RMODE = 0; + private static final int WMODE = 1; + + /** Wait nodes */ + static final class WNode { + volatile WNode prev; + volatile WNode next; + volatile WNode cowait; // list of linked readers + volatile Thread thread; // non-null while possibly parked + volatile int status; // 0, WAITING, or CANCELLED + final int mode; // RMODE or WMODE + WNode(int m, WNode p) { mode = m; prev = p; } + } + + /** Head of CLH queue */ + private transient volatile WNode whead; + /** Tail (last) of CLH queue */ + private transient volatile WNode wtail; + + // views + transient ReadLockView readLockView; + transient WriteLockView writeLockView; + transient ReadWriteLockView readWriteLockView; + + /** Lock sequence/state */ + private transient volatile long state; + /** extra reader count when state read count saturated */ + private transient int readerOverflow; + + /** + * Creates a new lock, initially in unlocked state. + */ + public StampedLock() { + state = ORIGIN; + } + + /** + * Exclusively acquires the lock, blocking if necessary + * until available. + * + * @return a stamp that can be used to unlock or convert mode + */ + public long writeLock() { + long s, next; // bypass acquireWrite in fully unlocked case only + return ((((s = state) & ABITS) == 0L && + U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ? + next : acquireWrite(false, 0L)); + } + + /** + * Exclusively acquires the lock if it is immediately available. + * + * @return a stamp that can be used to unlock or convert mode, + * or zero if the lock is not available + */ + public long tryWriteLock() { + long s, next; + return ((((s = state) & ABITS) == 0L && + U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) ? + next : 0L); + } + + /** + * Exclusively acquires the lock if it is available within the + * given time and the current thread has not been interrupted. + * Behavior under timeout and interruption matches that specified + * for method {@link Lock#tryLock(long,TimeUnit)}. + * + * @return a stamp that can be used to unlock or convert mode, + * or zero if the lock is not available + * @throws InterruptedException if the current thread is interrupted + * before acquiring the lock + */ + public long tryWriteLock(long time, TimeUnit unit) + throws InterruptedException { + long nanos = unit.toNanos(time); + if (!Thread.interrupted()) { + long next, deadline; + if ((next = tryWriteLock()) != 0L) + return next; + if (nanos <= 0L) + return 0L; + if ((deadline = System.nanoTime() + nanos) == 0L) + deadline = 1L; + if ((next = acquireWrite(true, deadline)) != INTERRUPTED) + return next; + } + throw new InterruptedException(); + } + + /** + * Exclusively acquires the lock, blocking if necessary + * until available or the current thread is interrupted. + * Behavior under interruption matches that specified + * for method {@link Lock#lockInterruptibly()}. + * + * @return a stamp that can be used to unlock or convert mode + * @throws InterruptedException if the current thread is interrupted + * before acquiring the lock + */ + public long writeLockInterruptibly() throws InterruptedException { + long next; + if (!Thread.interrupted() && + (next = acquireWrite(true, 0L)) != INTERRUPTED) + return next; + throw new InterruptedException(); + } + + /** + * Non-exclusively acquires the lock, blocking if necessary + * until available. + * + * @return a stamp that can be used to unlock or convert mode + */ + public long readLock() { + long s, next; // bypass acquireRead on fully unlocked case only + return ((((s = state) & ABITS) == 0L && + U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) ? + next : acquireRead(false, 0L)); + } + + /** + * Non-exclusively acquires the lock if it is immediately available. + * + * @return a stamp that can be used to unlock or convert mode, + * or zero if the lock is not available + */ + public long tryReadLock() { + for (;;) { + long s, m, next; + if ((m = (s = state) & ABITS) == WBIT) + return 0L; + else if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) + return next; + } + else if ((next = tryIncReaderOverflow(s)) != 0L) + return next; + } + } + + /** + * Non-exclusively acquires the lock if it is available within the + * given time and the current thread has not been interrupted. + * Behavior under timeout and interruption matches that specified + * for method {@link Lock#tryLock(long,TimeUnit)}. + * + * @return a stamp that can be used to unlock or convert mode, + * or zero if the lock is not available + * @throws InterruptedException if the current thread is interrupted + * before acquiring the lock + */ + public long tryReadLock(long time, TimeUnit unit) + throws InterruptedException { + long s, m, next, deadline; + long nanos = unit.toNanos(time); + if (!Thread.interrupted()) { + if ((m = (s = state) & ABITS) != WBIT) { + if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) + return next; + } + else if ((next = tryIncReaderOverflow(s)) != 0L) + return next; + } + if (nanos <= 0L) + return 0L; + if ((deadline = System.nanoTime() + nanos) == 0L) + deadline = 1L; + if ((next = acquireRead(true, deadline)) != INTERRUPTED) + return next; + } + throw new InterruptedException(); + } + + /** + * Non-exclusively acquires the lock, blocking if necessary + * until available or the current thread is interrupted. + * Behavior under interruption matches that specified + * for method {@link Lock#lockInterruptibly()}. + * + * @return a stamp that can be used to unlock or convert mode + * @throws InterruptedException if the current thread is interrupted + * before acquiring the lock + */ + public long readLockInterruptibly() throws InterruptedException { + long next; + if (!Thread.interrupted() && + (next = acquireRead(true, 0L)) != INTERRUPTED) + return next; + throw new InterruptedException(); + } + + /** + * Returns a stamp that can later be validated, or zero + * if exclusively locked. + * + * @return a stamp, or zero if exclusively locked + */ + public long tryOptimisticRead() { + long s; + return (((s = state) & WBIT) == 0L) ? (s & SBITS) : 0L; + } + + /** + * Returns true if the lock has not been exclusively acquired + * since issuance of the given stamp. Always returns false if the + * stamp is zero. Always returns true if the stamp represents a + * currently held lock. Invoking this method with a value not + * obtained from {@link #tryOptimisticRead} or a locking method + * for this lock has no defined effect or result. + * + * @return true if the lock has not been exclusively acquired + * since issuance of the given stamp; else false + */ + public boolean validate(long stamp) { + U.loadFence(); + return (stamp & SBITS) == (state & SBITS); + } + + /** + * If the lock state matches the given stamp, releases the + * exclusive lock. + * + * @param stamp a stamp returned by a write-lock operation + * @throws IllegalMonitorStateException if the stamp does + * not match the current state of this lock + */ + public void unlockWrite(long stamp) { + WNode h; + if (state != stamp || (stamp & WBIT) == 0L) + throw new IllegalMonitorStateException(); + state = (stamp += WBIT) == 0L ? ORIGIN : stamp; + if ((h = whead) != null && h.status != 0) + release(h); + } + + /** + * If the lock state matches the given stamp, releases the + * non-exclusive lock. + * + * @param stamp a stamp returned by a read-lock operation + * @throws IllegalMonitorStateException if the stamp does + * not match the current state of this lock + */ + public void unlockRead(long stamp) { + long s, m; WNode h; + for (;;) { + if (((s = state) & SBITS) != (stamp & SBITS) || + (stamp & ABITS) == 0L || (m = s & ABITS) == 0L || m == WBIT) + throw new IllegalMonitorStateException(); + if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) { + if (m == RUNIT && (h = whead) != null && h.status != 0) + release(h); + break; + } + } + else if (tryDecReaderOverflow(s) != 0L) + break; + } + } + + /** + * If the lock state matches the given stamp, releases the + * corresponding mode of the lock. + * + * @param stamp a stamp returned by a lock operation + * @throws IllegalMonitorStateException if the stamp does + * not match the current state of this lock + */ + public void unlock(long stamp) { + long a = stamp & ABITS, m, s; WNode h; + while (((s = state) & SBITS) == (stamp & SBITS)) { + if ((m = s & ABITS) == 0L) + break; + else if (m == WBIT) { + if (a != m) + break; + state = (s += WBIT) == 0L ? ORIGIN : s; + if ((h = whead) != null && h.status != 0) + release(h); + return; + } + else if (a == 0L || a >= WBIT) + break; + else if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) { + if (m == RUNIT && (h = whead) != null && h.status != 0) + release(h); + return; + } + } + else if (tryDecReaderOverflow(s) != 0L) + return; + } + throw new IllegalMonitorStateException(); + } + + /** + * If the lock state matches the given stamp, performs one of + * the following actions. If the stamp represents holding a write + * lock, returns it. Or, if a read lock, if the write lock is + * available, releases the read lock and returns a write stamp. + * Or, if an optimistic read, returns a write stamp only if + * immediately available. This method returns zero in all other + * cases. + * + * @param stamp a stamp + * @return a valid write stamp, or zero on failure + */ + public long tryConvertToWriteLock(long stamp) { + long a = stamp & ABITS, m, s, next; + while (((s = state) & SBITS) == (stamp & SBITS)) { + if ((m = s & ABITS) == 0L) { + if (a != 0L) + break; + if (U.compareAndSwapLong(this, STATE, s, next = s + WBIT)) + return next; + } + else if (m == WBIT) { + if (a != m) + break; + return stamp; + } + else if (m == RUNIT && a != 0L) { + if (U.compareAndSwapLong(this, STATE, s, + next = s - RUNIT + WBIT)) + return next; + } + else + break; + } + return 0L; + } + + /** + * If the lock state matches the given stamp, performs one of + * the following actions. If the stamp represents holding a write + * lock, releases it and obtains a read lock. Or, if a read lock, + * returns it. Or, if an optimistic read, acquires a read lock and + * returns a read stamp only if immediately available. This method + * returns zero in all other cases. + * + * @param stamp a stamp + * @return a valid read stamp, or zero on failure + */ + public long tryConvertToReadLock(long stamp) { + long a = stamp & ABITS, m, s, next; WNode h; + while (((s = state) & SBITS) == (stamp & SBITS)) { + if ((m = s & ABITS) == 0L) { + if (a != 0L) + break; + else if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, next = s + RUNIT)) + return next; + } + else if ((next = tryIncReaderOverflow(s)) != 0L) + return next; + } + else if (m == WBIT) { + if (a != m) + break; + state = next = s + (WBIT + RUNIT); + if ((h = whead) != null && h.status != 0) + release(h); + return next; + } + else if (a != 0L && a < WBIT) + return stamp; + else + break; + } + return 0L; + } + + /** + * If the lock state matches the given stamp then, if the stamp + * represents holding a lock, releases it and returns an + * observation stamp. Or, if an optimistic read, returns it if + * validated. This method returns zero in all other cases, and so + * may be useful as a form of "tryUnlock". + * + * @param stamp a stamp + * @return a valid optimistic read stamp, or zero on failure + */ + public long tryConvertToOptimisticRead(long stamp) { + long a = stamp & ABITS, m, s, next; WNode h; + U.loadFence(); + for (;;) { + if (((s = state) & SBITS) != (stamp & SBITS)) + break; + if ((m = s & ABITS) == 0L) { + if (a != 0L) + break; + return s; + } + else if (m == WBIT) { + if (a != m) + break; + state = next = (s += WBIT) == 0L ? ORIGIN : s; + if ((h = whead) != null && h.status != 0) + release(h); + return next; + } + else if (a == 0L || a >= WBIT) + break; + else if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, next = s - RUNIT)) { + if (m == RUNIT && (h = whead) != null && h.status != 0) + release(h); + return next & SBITS; + } + } + else if ((next = tryDecReaderOverflow(s)) != 0L) + return next & SBITS; + } + return 0L; + } + + /** + * Releases the write lock if it is held, without requiring a + * stamp value. This method may be useful for recovery after + * errors. + * + * @return true if the lock was held, else false + */ + public boolean tryUnlockWrite() { + long s; WNode h; + if (((s = state) & WBIT) != 0L) { + state = (s += WBIT) == 0L ? ORIGIN : s; + if ((h = whead) != null && h.status != 0) + release(h); + return true; + } + return false; + } + + /** + * Releases one hold of the read lock if it is held, without + * requiring a stamp value. This method may be useful for recovery + * after errors. + * + * @return true if the read lock was held, else false + */ + public boolean tryUnlockRead() { + long s, m; WNode h; + while ((m = (s = state) & ABITS) != 0L && m < WBIT) { + if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) { + if (m == RUNIT && (h = whead) != null && h.status != 0) + release(h); + return true; + } + } + else if (tryDecReaderOverflow(s) != 0L) + return true; + } + return false; + } + + // status monitoring methods + + /** + * Returns combined state-held and overflow read count for given + * state s. + */ + private int getReadLockCount(long s) { + long readers; + if ((readers = s & RBITS) >= RFULL) + readers = RFULL + readerOverflow; + return (int) readers; + } + + /** + * Returns true if the lock is currently held exclusively. + * + * @return true if the lock is currently held exclusively + */ + public boolean isWriteLocked() { + return (state & WBIT) != 0L; + } + + /** + * Returns true if the lock is currently held non-exclusively. + * + * @return true if the lock is currently held non-exclusively + */ + public boolean isReadLocked() { + return (state & RBITS) != 0L; + } + + /** + * Queries the number of read locks held for this lock. This + * method is designed for use in monitoring system state, not for + * synchronization control. + * @return the number of read locks held + */ + public int getReadLockCount() { + return getReadLockCount(state); + } + + /** + * Returns a string identifying this lock, as well as its lock + * state. The state, in brackets, includes the String {@code + * "Unlocked"} or the String {@code "Write-locked"} or the String + * {@code "Read-locks:"} followed by the current number of + * read-locks held. + * + * @return a string identifying this lock, as well as its lock state + */ + public String toString() { + long s = state; + return super.toString() + + ((s & ABITS) == 0L ? "[Unlocked]" : + (s & WBIT) != 0L ? "[Write-locked]" : + "[Read-locks:" + getReadLockCount(s) + "]"); + } + + // views + + /** + * Returns a plain {@link Lock} view of this StampedLock in which + * the {@link Lock#lock} method is mapped to {@link #readLock}, + * and similarly for other methods. The returned Lock does not + * support a {@link Condition}; method {@link + * Lock#newCondition()} throws {@code + * UnsupportedOperationException}. + * + * @return the lock + */ + public Lock asReadLock() { + ReadLockView v; + return ((v = readLockView) != null ? v : + (readLockView = new ReadLockView())); + } + + /** + * Returns a plain {@link Lock} view of this StampedLock in which + * the {@link Lock#lock} method is mapped to {@link #writeLock}, + * and similarly for other methods. The returned Lock does not + * support a {@link Condition}; method {@link + * Lock#newCondition()} throws {@code + * UnsupportedOperationException}. + * + * @return the lock + */ + public Lock asWriteLock() { + WriteLockView v; + return ((v = writeLockView) != null ? v : + (writeLockView = new WriteLockView())); + } + + /** + * Returns a {@link ReadWriteLock} view of this StampedLock in + * which the {@link ReadWriteLock#readLock()} method is mapped to + * {@link #asReadLock()}, and {@link ReadWriteLock#writeLock()} to + * {@link #asWriteLock()}. + * + * @return the lock + */ + public ReadWriteLock asReadWriteLock() { + ReadWriteLockView v; + return ((v = readWriteLockView) != null ? v : + (readWriteLockView = new ReadWriteLockView())); + } + + // view classes + + final class ReadLockView implements Lock { + public void lock() { readLock(); } + public void lockInterruptibly() throws InterruptedException { + readLockInterruptibly(); + } + public boolean tryLock() { return tryReadLock() != 0L; } + public boolean tryLock(long time, TimeUnit unit) + throws InterruptedException { + return tryReadLock(time, unit) != 0L; + } + public void unlock() { unstampedUnlockRead(); } + public Condition newCondition() { + throw new UnsupportedOperationException(); + } + } + + final class WriteLockView implements Lock { + public void lock() { writeLock(); } + public void lockInterruptibly() throws InterruptedException { + writeLockInterruptibly(); + } + public boolean tryLock() { return tryWriteLock() != 0L; } + public boolean tryLock(long time, TimeUnit unit) + throws InterruptedException { + return tryWriteLock(time, unit) != 0L; + } + public void unlock() { unstampedUnlockWrite(); } + public Condition newCondition() { + throw new UnsupportedOperationException(); + } + } + + final class ReadWriteLockView implements ReadWriteLock { + public Lock readLock() { return asReadLock(); } + public Lock writeLock() { return asWriteLock(); } + } + + // Unlock methods without stamp argument checks for view classes. + // Needed because view-class lock methods throw away stamps. + + final void unstampedUnlockWrite() { + WNode h; long s; + if (((s = state) & WBIT) == 0L) + throw new IllegalMonitorStateException(); + state = (s += WBIT) == 0L ? ORIGIN : s; + if ((h = whead) != null && h.status != 0) + release(h); + } + + final void unstampedUnlockRead() { + for (;;) { + long s, m; WNode h; + if ((m = (s = state) & ABITS) == 0L || m >= WBIT) + throw new IllegalMonitorStateException(); + else if (m < RFULL) { + if (U.compareAndSwapLong(this, STATE, s, s - RUNIT)) { + if (m == RUNIT && (h = whead) != null && h.status != 0) + release(h); + break; + } + } + else if (tryDecReaderOverflow(s) != 0L) + break; + } + } + + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + state = ORIGIN; // reset to unlocked state + } + + // internals + + /** + * Tries to increment readerOverflow by first setting state + * access bits value to RBITS, indicating hold of spinlock, + * then updating, then releasing. + * + * @param s a reader overflow stamp: (s & ABITS) >= RFULL + * @return new stamp on success, else zero + */ + private long tryIncReaderOverflow(long s) { + // assert (s & ABITS) >= RFULL; + if ((s & ABITS) == RFULL) { + if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) { + ++readerOverflow; + state = s; + return s; + } + } + else if ((LockSupport.nextSecondarySeed() & + OVERFLOW_YIELD_RATE) == 0) + Thread.yield(); + return 0L; + } + + /** + * Tries to decrement readerOverflow. + * + * @param s a reader overflow stamp: (s & ABITS) >= RFULL + * @return new stamp on success, else zero + */ + private long tryDecReaderOverflow(long s) { + // assert (s & ABITS) >= RFULL; + if ((s & ABITS) == RFULL) { + if (U.compareAndSwapLong(this, STATE, s, s | RBITS)) { + int r; long next; + if ((r = readerOverflow) > 0) { + readerOverflow = r - 1; + next = s; + } + else + next = s - RUNIT; + state = next; + return next; + } + } + else if ((LockSupport.nextSecondarySeed() & + OVERFLOW_YIELD_RATE) == 0) + Thread.yield(); + return 0L; + } + + /** + * Wakes up the successor of h (normally whead). This is normally + * just h.next, but may require traversal from wtail if next + * pointers are lagging. This may fail to wake up an acquiring + * thread when one or more have been cancelled, but the cancel + * methods themselves provide extra safeguards to ensure liveness. + */ + private void release(WNode h) { + if (h != null) { + WNode q; Thread w; + U.compareAndSwapInt(h, WSTATUS, WAITING, 0); + if ((q = h.next) == null || q.status == CANCELLED) { + for (WNode t = wtail; t != null && t != h; t = t.prev) + if (t.status <= 0) + q = t; + } + if (q != null) { + for (WNode r = q;;) { // release co-waiters too + if ((w = r.thread) != null) { + r.thread = null; + U.unpark(w); + } + if ((r = q.cowait) == null) + break; + U.compareAndSwapObject(q, WCOWAIT, r, r.cowait); + } + } + } + } + + /** + * See above for explanation. + * + * @param interruptible true if should check interrupts and if so + * return INTERRUPTED + * @param deadline if nonzero, the System.nanoTime value to timeout + * at (and return zero) + * @return next state, or INTERRUPTED + */ + private long acquireWrite(boolean interruptible, long deadline) { + WNode node = null, p; + for (int spins = -1;;) { // spin while enqueuing + long s, ns; + if (((s = state) & ABITS) == 0L) { + if (U.compareAndSwapLong(this, STATE, s, ns = s + WBIT)) + return ns; + } + else if (spins > 0) { + if (LockSupport.nextSecondarySeed() >= 0) + --spins; + } + else if ((p = wtail) == null) { // initialize queue + WNode h = new WNode(WMODE, null); + if (U.compareAndSwapObject(this, WHEAD, null, h)) + wtail = h; + } + else if (spins < 0) + spins = (p == whead) ? SPINS : 0; + else if (node == null) + node = new WNode(WMODE, p); + else if (node.prev != p) + node.prev = p; + else if (U.compareAndSwapObject(this, WTAIL, p, node)) { + p.next = node; + break; + } + } + + for (int spins = SPINS;;) { + WNode np, pp; int ps; long s, ns; Thread w; + while ((np = node.prev) != p && np != null) + (p = np).next = node; // stale + if (whead == p) { + for (int k = spins;;) { // spin at head + if (((s = state) & ABITS) == 0L) { + if (U.compareAndSwapLong(this, STATE, s, ns = s+WBIT)) { + whead = node; + node.prev = null; + return ns; + } + } + else if (LockSupport.nextSecondarySeed() >= 0 && + --k <= 0) + break; + } + if (spins < MAX_HEAD_SPINS) + spins <<= 1; + } + if ((ps = p.status) == 0) + U.compareAndSwapInt(p, WSTATUS, 0, WAITING); + else if (ps == CANCELLED) { + if ((pp = p.prev) != null) { + node.prev = pp; + pp.next = node; + } + } + else { + long time; // 0 argument to park means no timeout + if (deadline == 0L) + time = 0L; + else if ((time = deadline - System.nanoTime()) <= 0L) + return cancelWaiter(node, node, false); + Thread wt = Thread.currentThread(); + U.putObject(wt, PARKBLOCKER, this); // emulate LockSupport.park + node.thread = wt; + if (node.prev == p && p.status == WAITING && // recheck + (p != whead || (state & ABITS) != 0L)) + U.park(false, time); + node.thread = null; + U.putObject(wt, PARKBLOCKER, null); + if (interruptible && Thread.interrupted()) + return cancelWaiter(node, node, true); + } + } + } + + /** + * See above for explanation. + * + * @param interruptible true if should check interrupts and if so + * return INTERRUPTED + * @param deadline if nonzero, the System.nanoTime value to timeout + * at (and return zero) + * @return next state, or INTERRUPTED + */ + private long acquireRead(boolean interruptible, long deadline) { + WNode node = null, group = null, p; + for (int spins = -1;;) { + for (;;) { + long s, m, ns; WNode h, q; Thread w; // anti-barging guard + if (group == null && (h = whead) != null && + (q = h.next) != null && q.mode != RMODE) + break; + if ((m = (s = state) & ABITS) < RFULL ? + U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT) : + (m < WBIT && (ns = tryIncReaderOverflow(s)) != 0L)) { + if (group != null) { // help release others + for (WNode r = group;;) { + if ((w = r.thread) != null) { + r.thread = null; + U.unpark(w); + } + if ((r = group.cowait) == null) + break; + U.compareAndSwapObject(group, WCOWAIT, r, r.cowait); + } + } + return ns; + } + if (m >= WBIT) + break; + } + if (spins > 0) { + if (LockSupport.nextSecondarySeed() >= 0) + --spins; + } + else if ((p = wtail) == null) { + WNode h = new WNode(WMODE, null); + if (U.compareAndSwapObject(this, WHEAD, null, h)) + wtail = h; + } + else if (spins < 0) + spins = (p == whead) ? SPINS : 0; + else if (node == null) + node = new WNode(WMODE, p); + else if (node.prev != p) + node.prev = p; + else if (p.mode == RMODE && p != whead) { + WNode pp = p.prev; // become co-waiter with group p + if (pp != null && p == wtail && + U.compareAndSwapObject(p, WCOWAIT, + node.cowait = p.cowait, node)) { + node.thread = Thread.currentThread(); + for (long time;;) { + if (deadline == 0L) + time = 0L; + else if ((time = deadline - System.nanoTime()) <= 0L) + return cancelWaiter(node, p, false); + if (node.thread == null) + break; + if (p.prev != pp || p.status == CANCELLED || + p == whead || p.prev != pp) { + node.thread = null; + break; + } + Thread wt = Thread.currentThread(); + U.putObject(wt, PARKBLOCKER, this); + if (node.thread == null) // must recheck + break; + U.park(false, time); + U.putObject(wt, PARKBLOCKER, null); + if (interruptible && Thread.interrupted()) + return cancelWaiter(node, p, true); + } + group = p; + } + node = null; // throw away + } + else if (U.compareAndSwapObject(this, WTAIL, p, node)) { + p.next = node; + break; + } + } + + for (int spins = SPINS;;) { + WNode np, pp, r; int ps; long m, s, ns; Thread w; + while ((np = node.prev) != p && np != null) + (p = np).next = node; + if (whead == p) { + for (int k = spins;;) { + if ((m = (s = state) & ABITS) != WBIT) { + if (m < RFULL ? + U.compareAndSwapLong(this, STATE, s, ns = s + RUNIT): + (ns = tryIncReaderOverflow(s)) != 0L) { + whead = node; + node.prev = null; + while ((r = node.cowait) != null) { + if (U.compareAndSwapObject(node, WCOWAIT, + r, r.cowait) && + (w = r.thread) != null) { + r.thread = null; + U.unpark(w); // release co-waiter + } + } + return ns; + } + } + else if (LockSupport.nextSecondarySeed() >= 0 && + --k <= 0) + break; + } + if (spins < MAX_HEAD_SPINS) + spins <<= 1; + } + if ((ps = p.status) == 0) + U.compareAndSwapInt(p, WSTATUS, 0, WAITING); + else if (ps == CANCELLED) { + if ((pp = p.prev) != null) { + node.prev = pp; + pp.next = node; + } + } + else { + long time; + if (deadline == 0L) + time = 0L; + else if ((time = deadline - System.nanoTime()) <= 0L) + return cancelWaiter(node, node, false); + Thread wt = Thread.currentThread(); + U.putObject(wt, PARKBLOCKER, this); + node.thread = wt; + if (node.prev == p && p.status == WAITING && + (p != whead || (state & ABITS) != WBIT)) + U.park(false, time); + node.thread = null; + U.putObject(wt, PARKBLOCKER, null); + if (interruptible && Thread.interrupted()) + return cancelWaiter(node, node, true); + } + } + } + + /** + * If node non-null, forces cancel status and unsplices it from + * queue if possible and wakes up any cowaiters (of the node, or + * group, as applicable), and in any case helps release current + * first waiter if lock is free. (Calling with null arguments + * serves as a conditional form of release, which is not currently + * needed but may be needed under possible future cancellation + * policies). This is a variant of cancellation methods in + * AbstractQueuedSynchronizer (see its detailed explanation in AQS + * internal documentation). + * + * @param node if nonnull, the waiter + * @param group either node or the group node is cowaiting with + * @param interrupted if already interrupted + * @return INTERRUPTED if interrupted or Thread.interrupted, else zero + */ + private long cancelWaiter(WNode node, WNode group, boolean interrupted) { + if (node != null && group != null) { + Thread w; + node.status = CANCELLED; + node.thread = null; + // unsplice cancelled nodes from group + for (WNode p = group, q; (q = p.cowait) != null;) { + if (q.status == CANCELLED) + U.compareAndSwapObject(p, WNEXT, q, q.next); + else + p = q; + } + if (group == node) { + WNode r; // detach and wake up uncancelled co-waiters + while ((r = node.cowait) != null) { + if (U.compareAndSwapObject(node, WCOWAIT, r, r.cowait) && + (w = r.thread) != null) { + r.thread = null; + U.unpark(w); + } + } + for (WNode pred = node.prev; pred != null; ) { // unsplice + WNode succ, pp; // find valid successor + while ((succ = node.next) == null || + succ.status == CANCELLED) { + WNode q = null; // find successor the slow way + for (WNode t = wtail; t != null && t != node; t = t.prev) + if (t.status != CANCELLED) + q = t; // don't link if succ cancelled + if (succ == q || // ensure accurate successor + U.compareAndSwapObject(node, WNEXT, + succ, succ = q)) { + if (succ == null && node == wtail) + U.compareAndSwapObject(this, WTAIL, node, pred); + break; + } + } + if (pred.next == node) // unsplice pred link + U.compareAndSwapObject(pred, WNEXT, node, succ); + if (succ != null && (w = succ.thread) != null) { + succ.thread = null; + U.unpark(w); // wake up succ to observe new pred + } + if (pred.status != CANCELLED || (pp = pred.prev) == null) + break; + node.prev = pp; // repeat if new pred wrong/cancelled + U.compareAndSwapObject(pp, WNEXT, pred, succ); + pred = pp; + } + } + } + WNode h; // Possibly release first waiter + while ((h = whead) != null) { + long s; WNode q; // similar to release() but check eligibility + if ((q = h.next) == null || q.status == CANCELLED) { + for (WNode t = wtail; t != null && t != h; t = t.prev) + if (t.status <= 0) + q = t; + } + if (h == whead) { + if (q != null && h.status == 0 && + ((s = state) & ABITS) != WBIT && // waiter is eligible + (s == 0L || q.mode == RMODE)) + release(h); + break; + } + } + return (interrupted || Thread.interrupted()) ? INTERRUPTED : 0L; + } + + // Unsafe mechanics + private static final sun.misc.Unsafe U; + private static final long STATE; + private static final long WHEAD; + private static final long WTAIL; + private static final long WNEXT; + private static final long WSTATUS; + private static final long WCOWAIT; + private static final long PARKBLOCKER; + + static { + try { + U = sun.misc.Unsafe.getUnsafe(); + Class k = StampedLock.class; + Class wk = WNode.class; + STATE = U.objectFieldOffset + (k.getDeclaredField("state")); + WHEAD = U.objectFieldOffset + (k.getDeclaredField("whead")); + WTAIL = U.objectFieldOffset + (k.getDeclaredField("wtail")); + WSTATUS = U.objectFieldOffset + (wk.getDeclaredField("status")); + WNEXT = U.objectFieldOffset + (wk.getDeclaredField("next")); + WCOWAIT = U.objectFieldOffset + (wk.getDeclaredField("cowait")); + Class tk = Thread.class; + PARKBLOCKER = U.objectFieldOffset + (tk.getDeclaredField("parkBlocker")); + + } catch (Exception e) { + throw new Error(e); + } + } +} diff --git a/jdk/test/java/util/concurrent/locks/StampedLock/Basic.java b/jdk/test/java/util/concurrent/locks/StampedLock/Basic.java new file mode 100644 index 00000000000..8c9f236d2d3 --- /dev/null +++ b/jdk/test/java/util/concurrent/locks/StampedLock/Basic.java @@ -0,0 +1,609 @@ +/* + * 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 file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Doug Lea with assistance from members of JCP JSR-166 + * Expert Group and released to the public domain, as explained at + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* + * @test + * @bug 8005697 + * @summary Basic tests for StampedLock + * @author Chris Hegarty + */ + +import java.util.Iterator; +import java.util.concurrent.Phaser; +import java.util.concurrent.TimeUnit; +import static java.util.concurrent.TimeUnit.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.StampedLock; + +public class Basic { + + static void checkResult(Locker l, Class c) { + Throwable t = l.thrown(); + if (! ((t == null && c == null) || (c != null && c.isInstance(t)))) { + fail("Mismatch in thread " + + l.getName() + ": " + + t + ", " + + (c == null ? "" : c.getName())); + } + + if (c == null) + check(l.stamp() != 0L); // must have acquired the lock + else + check(l.stamp() == 0L); // must NOT have acquired the lock + } + + //---------------------------------------------------------------- + // Mechanism to get all test threads into "running" mode. + //---------------------------------------------------------------- + static void toTheStartingGate(Phaser gate) { + try { + gate.arriveAndAwaitAdvance(); + } catch (Throwable t) { + unexpected(t); + } + } + + static abstract class Locker extends Thread { + static AtomicInteger count = new AtomicInteger(1); + private volatile Throwable thrown; + private volatile long stamp;; + protected void thrown(Throwable thrown) { this.thrown = thrown; } + public Throwable thrown() { return thrown; } + protected void stamp(long stamp) { this.stamp = stamp; } + public long stamp() { return stamp; } + + Locker() { + this("Locker"); + } + + Locker(String name) { + this.setName(name + ":" + count.getAndIncrement()); + this.setDaemon(true); + } + } + + static abstract class Reader extends Locker { + Reader() { super("Reader"); } + Reader(String name) { super(name); } + } + + static Reader reader(final StampedLock sl, final Phaser gate) { + return new Reader() { public void run() { + if (gate != null ) toTheStartingGate(gate); + stamp(sl.readLock()); + try { + check(sl.validate(stamp())); + check(sl.isReadLocked()); + check(!sl.isWriteLocked()); + } finally { sl.unlockRead(stamp()); } }}; + } + + static Reader readerView(final StampedLock sl, final Phaser gate) { + return new Reader("ReaderView") { public void run() { + if (gate != null ) toTheStartingGate(gate); + final Lock rl = sl.asReadLock(); + rl.lock(); + try { + stamp(1L); // got the lock + check(sl.isReadLocked()); + check(!sl.isWriteLocked()); + } finally { rl.unlock(); } }}; + } + + static Reader reader(StampedLock sl, Phaser gate, boolean view) { + return view ? readerView(sl, gate) : reader(sl, gate); + } + + static Reader interruptibleReader(final StampedLock sl, + final long timeout, + final TimeUnit unit, + final Phaser gate) { + return new Reader("InterruptibleReader") { public void run() { + if (gate != null ) toTheStartingGate(gate); + try { + if (timeout < 0) + stamp(sl.readLockInterruptibly()); + else + stamp(sl.tryReadLock(timeout, unit)); + check(sl.validate(stamp())); + check(sl.isReadLocked()); + check(!sl.isWriteLocked()); + } catch (Throwable x) { thrown(x); + } finally { if (stamp() != 0L) sl.unlockRead(stamp()); } }}; + } + + static Reader interruptibleReaderView(final StampedLock sl, + final long timeout, + final TimeUnit unit, + final Phaser gate) { + return new Reader("InterruptibleReaderView") { public void run() { + if (gate != null ) toTheStartingGate(gate); + final Lock rl = sl.asReadLock(); + + try { + if (timeout < 0) + rl.lockInterruptibly(); + else + rl.tryLock(timeout, unit); + stamp(1L); // got the lock + check(sl.isReadLocked()); + check(!sl.isWriteLocked()); + } catch (Throwable x) { thrown(x); + } finally { if (stamp() != 0L) rl.unlock(); } }}; + } + + static Reader interruptibleReader(final StampedLock sl, + final long timeout, + final TimeUnit unit, + final Phaser gate, + final boolean view) { + return view ? interruptibleReaderView(sl, timeout, unit, gate) + : interruptibleReader(sl, timeout, unit, gate); + } + + static abstract class Writer extends Locker { + Writer() { super("Writer"); } + Writer(String name) { super(name); } + } + + static Writer writer(final StampedLock sl, final Phaser gate) { + return new Writer() { public void run() { + if (gate != null ) toTheStartingGate(gate); + try { + stamp(sl.writeLock()); + check(sl.validate(stamp())); + check(!sl.isReadLocked()); + check(sl.isWriteLocked()); + } finally { sl.unlockWrite(stamp()); } }}; + } + + static Writer writerView(final StampedLock sl, final Phaser gate) { + return new Writer("WriterView") { public void run() { + if (gate != null ) toTheStartingGate(gate); + Lock wl = sl.asWriteLock(); + wl.lock(); + try { + stamp(1L); // got the lock + check(!sl.isReadLocked()); + check(sl.isWriteLocked()); + } finally { wl.unlock(); } }}; + } + + static Writer writer(StampedLock sl, Phaser gate, boolean view) { + return view ? writerView(sl, gate) : writer(sl, gate); + } + + static Writer interruptibleWriter(final StampedLock sl, + final long timeout, + final TimeUnit unit, + final Phaser gate) { + return new Writer("InterruptibleWriter") { public void run() { + if (gate != null ) toTheStartingGate(gate); + try { + if (timeout < 0) + stamp(sl.writeLockInterruptibly()); + else + stamp(sl.tryWriteLock(timeout, unit)); + check(sl.validate(stamp())); + check(!sl.isReadLocked()); + check(sl.isWriteLocked()); + } catch (Throwable x) { thrown(x); + } finally { if (stamp() != 0L) sl.unlockWrite(stamp()); } }}; + } + + static Writer interruptibleWriterView(final StampedLock sl, + final long timeout, + final TimeUnit unit, + final Phaser gate) { + return new Writer("InterruptibleWriterView") { public void run() { + if (gate != null ) toTheStartingGate(gate); + Lock wl = sl.asWriteLock(); + try { + if (timeout < 0) + wl.lockInterruptibly(); + else + wl.tryLock(timeout, unit); + stamp(1L); // got the lock + check(!sl.isReadLocked()); + check(sl.isWriteLocked()); + } catch (Throwable x) { thrown(x); + } finally { if (stamp() != 0L) wl.unlock(); } }}; + } + + static Writer interruptibleWriter(final StampedLock sl, + final long timeout, + final TimeUnit unit, + final Phaser gate, + final boolean view) { + return view ? interruptibleWriterView(sl, timeout, unit, gate) + : interruptibleWriter(sl, timeout, unit, gate); + } + + // Returns an infinite lazy list of all possible reader combinations. + static Iterator readerIterator(final StampedLock sl, + final Phaser gate) { + return new Iterator() { + int i = 0; + boolean view = false; + public boolean hasNext() { return true; } + public Reader next() { + switch ((i++)&7) { + case 1: case 4: case 7: + return reader(sl, gate, view ^= true); + case 2: case 5: + return interruptibleReader(sl, -1, SECONDS, gate, view ^= true); + default: + return interruptibleReader(sl, 30, SECONDS, gate, view ^= true); }} + public void remove() {throw new UnsupportedOperationException();}}; + } + + // Returns an infinite lazy list of all possible writer combinations. + static Iterator writerIterator(final StampedLock sl, + final Phaser gate) { + return new Iterator() { + int i = 0; + boolean view = false; + public boolean hasNext() { return true; } + public Writer next() { + switch ((i++)&7) { + case 1: case 4: case 7: + return writer(sl, gate, view ^= true); + case 2: case 5: + return interruptibleWriter(sl, -1, SECONDS, gate, view ^= true); + default: + return interruptibleWriter(sl, 30, SECONDS, gate, view ^= true); }} + public void remove() {throw new UnsupportedOperationException();}}; + } + + private static void realMain(String[] args) throws Throwable { + + Thread.currentThread().setName("mainThread"); + + //---------------------------------------------------------------- + // Some basic sanity + //---------------------------------------------------------------- + try { + final StampedLock sl = new StampedLock(); + check(!sl.isReadLocked()); + check(!sl.isWriteLocked()); + long stamp = sl.tryOptimisticRead(); + check(stamp != 0L); + check(sl.validate(stamp)); + check(!sl.validate(0)); + + stamp = sl.writeLock(); + try { + check(sl.validate(stamp)); + check(!sl.isReadLocked()); + check(sl.isWriteLocked()); + check(sl.tryReadLock() == 0L); + check(sl.tryReadLock(100, MILLISECONDS) == 0L); + check(sl.tryOptimisticRead() == 0L); + check(sl.tryWriteLock() == 0L); + check(sl.tryWriteLock(100, MILLISECONDS) == 0L); + check(!sl.tryUnlockRead()); + check(sl.tryConvertToWriteLock(stamp) == stamp); + try { + sl.unlockRead(stamp); + fail("Expected unlockRead to throw when not holding read lock"); + } catch (IllegalMonitorStateException x) { + pass(); + } + check(sl.validate(stamp)); + } finally { + sl.unlockWrite(stamp); + } + check(!sl.isWriteLocked()); + + stamp = sl.readLock(); + try { + check(sl.validate(stamp)); + check(sl.isReadLocked()); + check(!sl.isWriteLocked()); + check(sl.tryOptimisticRead() != 0L); + check(sl.tryWriteLock() == 0L); + check(sl.tryWriteLock(100, MILLISECONDS) == 0L); + check(!sl.tryUnlockWrite()); + check(sl.tryConvertToReadLock(stamp) == stamp); + try { + sl.unlockWrite(stamp); + fail("Expected unlockWrite to throw when not holding read lock"); + } catch (IllegalMonitorStateException x) { + pass(); + } + check(sl.validate(stamp)); + } finally { + sl.unlockRead(stamp); + } + check(!sl.isReadLocked()); + + stamp = sl.tryReadLock(100, MILLISECONDS); + try { + check(stamp != 0L); + } finally { + sl.unlockRead(stamp); + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // Multiple writers single reader + //---------------------------------------------------------------- + try { + StampedLock sl = new StampedLock(); + Phaser gate = new Phaser(102); + Iterator writers = writerIterator(sl, gate); + Iterator readers = readerIterator(sl, gate); + for (int i = 0; i < 10; i++) { + check(!sl.isReadLocked()); + check(!sl.isWriteLocked()); + check(!sl.tryUnlockRead()); + check(!sl.tryUnlockWrite()); + check(sl.tryOptimisticRead() != 0L); + Locker[] wThreads = new Locker[100];; + for (int j=0; j<100; j++) + wThreads[j] = writers.next(); + for (int j=0; j<100; j++) + wThreads[j].start(); + Reader reader = readers.next(); reader.start(); + toTheStartingGate(gate); + reader.join(); + for (int j=0; j<100; j++) + wThreads[j].join(); + for (int j=0; j<100; j++) + checkResult(wThreads[j], null); + checkResult(reader, null); + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // Multiple readers single writer + //---------------------------------------------------------------- + try { + StampedLock sl = new StampedLock(); + Phaser gate = new Phaser(102); + Iterator writers = writerIterator(sl, gate); + Iterator readers = readerIterator(sl, gate); + for (int i = 0; i < 10; i++) { + check(!sl.isReadLocked()); + check(!sl.isWriteLocked()); + check(!sl.tryUnlockRead()); + check(!sl.tryUnlockWrite()); + check(sl.tryOptimisticRead() != 0L); + Locker[] rThreads = new Locker[100];; + for (int j=0; j<100; j++) + rThreads[j] = readers.next(); + for (int j=0; j<100; j++) + rThreads[j].start(); + Writer writer = writers.next(); writer.start(); + toTheStartingGate(gate); + writer.join(); + for (int j=0; j<100; j++) + rThreads[j].join(); + for (int j=0; j<100; j++) + checkResult(rThreads[j], null); + checkResult(writer, null); + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // thread interrupted + //---------------------------------------------------------------- + try { + boolean view = false; + StampedLock sl = new StampedLock(); + for (long timeout : new long[] { -1L, 30L, -1L, 30L }) { + long stamp = sl.writeLock(); + try { + Reader r = interruptibleReader(sl, timeout, SECONDS, null, view); + r.start(); + // allow r to block + Thread.sleep(2000); + r.interrupt(); + r.join(); + checkResult(r, InterruptedException.class); + } finally { + sl.unlockWrite(stamp); + } + stamp = sl.readLock(); + try { + Writer w = interruptibleWriter(sl, timeout, SECONDS, null, view); + w.start(); + // allow w to block + Thread.sleep(2000); + w.interrupt(); + w.join(); + checkResult(w, InterruptedException.class); + } finally { + sl.unlockRead(stamp); + } + check(!sl.isReadLocked()); + check(!sl.isWriteLocked()); + check(!sl.tryUnlockRead()); + check(!sl.tryUnlockWrite()); + check(sl.tryOptimisticRead() != 0L); + if (timeout == 30L) + view = true; + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // timeout + //---------------------------------------------------------------- + try { + StampedLock sl = new StampedLock(); + for (long timeout : new long[] { 0L, 5L }) { + long stamp = sl.writeLock(); + try { + check(sl.tryReadLock(timeout, SECONDS) == 0L); + } finally { + sl.unlockWrite(stamp); + } + stamp = sl.readLock(); + try { + check(sl.tryWriteLock(timeout, SECONDS) == 0L); + } finally { + sl.unlockRead(stamp); + } + check(!sl.isReadLocked()); + check(!sl.isWriteLocked()); + check(!sl.tryUnlockRead()); + check(!sl.tryUnlockWrite()); + check(sl.tryOptimisticRead() != 0L); + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // optimistic read + //---------------------------------------------------------------- + try { + StampedLock sl = new StampedLock(); + Iterator writers = writerIterator(sl, null); + Iterator readers = readerIterator(sl, null); + for (int i = 0; i < 10; i++) { + check(!sl.isReadLocked()); + check(!sl.isWriteLocked()); + check(!sl.tryUnlockRead()); + check(!sl.tryUnlockWrite()); + long stamp = sl.tryOptimisticRead(); + check(stamp != 0L); + check(sl.tryConvertToOptimisticRead(stamp) == stamp); + Reader r = readers.next(); r.start(); + r.join(); + checkResult(r, null); + check(sl.validate(stamp)); + check(sl.tryConvertToOptimisticRead(stamp) == stamp); + Writer w = writers.next(); w.start(); + w.join(); + checkResult(w, null); + check(sl.validate(stamp) == false); + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // convert + //---------------------------------------------------------------- + try { + StampedLock sl = new StampedLock(); + for (int i = 0; i < 2; i++) { + check(!sl.isReadLocked()); + check(!sl.isWriteLocked()); + check(!sl.tryUnlockRead()); + check(!sl.tryUnlockWrite()); + long stamp = sl.tryOptimisticRead(); + check(stamp != 0L); + check((stamp = sl.tryConvertToReadLock(stamp)) != 0L); + check(sl.validate(stamp)); + check(sl.isReadLocked()); + check(sl.tryWriteLock() == 0L); + check(sl.tryWriteLock(1L, SECONDS) == 0L); + check((stamp = sl.tryConvertToWriteLock(stamp)) != 0L); + check(sl.validate(stamp)); + check(!sl.isReadLocked()); + check(sl.isWriteLocked()); + check(sl.tryReadLock(1L, SECONDS) == 0L); + if (i != 0) { + sl.unlockWrite(stamp); + continue; + } + // convert down + check((stamp = sl.tryConvertToReadLock(stamp)) != 0L); + check(sl.validate(stamp)); + check(sl.isReadLocked()); + check(!sl.isWriteLocked()); + check(sl.tryWriteLock() == 0L); + check(sl.tryWriteLock(1L, SECONDS) == 0L); + check((stamp = sl.tryConvertToOptimisticRead(stamp)) != 0L); + check(sl.validate(stamp)); + check(!sl.isReadLocked()); + check(!sl.isWriteLocked()); + check(sl.validate(stamp)); + } + } catch (Throwable t) { unexpected(t); } + + //---------------------------------------------------------------- + // views + //---------------------------------------------------------------- + try { + StampedLock sl = new StampedLock(); + + Lock rl = sl.asReadLock(); + Lock wl = sl.asWriteLock(); + for (int i = 0; i < 2; i++) { + rl.lock(); + try { + check(sl.isReadLocked()); + check(!sl.isWriteLocked()); + check(sl.tryWriteLock() == 0L); + check(sl.tryWriteLock(1L, SECONDS) == 0L); + } finally { + rl.unlock(); + } + check(!sl.isReadLocked()); + check(!sl.isWriteLocked()); + + wl.lock(); + try { + check(!sl.isReadLocked()); + check(sl.isWriteLocked()); + check(sl.tryWriteLock() == 0L); + check(sl.tryWriteLock(1L, SECONDS) == 0L); + } finally { + wl.unlock(); + } + check(!sl.isReadLocked()); + check(!sl.isWriteLocked()); + + ReadWriteLock rwl = sl.asReadWriteLock(); + rl = rwl.readLock(); + wl = rwl.writeLock(); + } + } catch (Throwable t) { unexpected(t); } + } + + //--------------------- Infrastructure --------------------------- + static volatile int passed = 0, failed = 0; + static void pass() {passed++;} + static void fail() {failed++; Thread.dumpStack();} + static void fail(String msg) {System.out.println(msg); fail();} + static void unexpected(Throwable t) {failed++; t.printStackTrace();} + static void check(boolean cond) {if (cond) pass(); else fail();} + static void equal(Object x, Object y) { + if (x == null ? y == null : x.equals(y)) pass(); + else fail(x + " not equal to " + y);} + public static void main(String[] args) throws Throwable { + try {realMain(args);} catch (Throwable t) {unexpected(t);} + System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); + if (failed > 0) throw new AssertionError("Some tests failed");} +} From d8233ec65720cf0bb8536853588cc967c4dcca28 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Sat, 9 Feb 2013 16:43:49 +0800 Subject: [PATCH 09/39] 8001104: Unbound SASL service: the GSSAPI/krb5 mech Reviewed-by: valeriep --- .../security/auth/module/Krb5LoginModule.java | 118 ++++++++----- .../JavaxSecurityAuthKerberosAccessImpl.java | 6 +- .../javax/security/auth/kerberos/KeyTab.java | 160 ++++++++++++++++-- .../sun/security/jgss/LoginConfigImpl.java | 1 + .../sun/security/jgss/krb5/Krb5Util.java | 16 +- .../sun/security/jgss/krb5/ServiceCreds.java | 83 ++++++--- .../sun/security/jgss/krb5/SubjectComber.java | 59 ++++--- .../krb5/JavaxSecurityAuthKerberosAccess.java | 7 +- .../security/krb5/internal/ktab/KeyTab.java | 10 ++ .../sun/security/provider/ConfigSpiFile.java | 1 + .../krb5/ServiceCredsCombination.java | 33 ++++ .../security/krb5/auto/AcceptPermissions.java | 16 +- .../sun/security/krb5/auto/GSSUnbound.java | 61 +++++++ jdk/test/sun/security/krb5/auto/OneKDC.java | 5 +- .../sun/security/krb5/auto/SaslUnbound.java | 113 +++++++++++++ .../security/krb5/auto/UnboundService.java | 85 ++++++++++ 16 files changed, 652 insertions(+), 122 deletions(-) create mode 100644 jdk/test/sun/security/krb5/auto/GSSUnbound.java create mode 100644 jdk/test/sun/security/krb5/auto/SaslUnbound.java create mode 100644 jdk/test/sun/security/krb5/auto/UnboundService.java diff --git a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java index 3d1744ba172..719aeee76d4 100644 --- a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java +++ b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java @@ -52,16 +52,19 @@ import sun.misc.HexDumpEncoder; * principal set and private credentials set are updated only when * commit is called. * When commit is called, the KerberosPrincipal - * is added to the Subject's - * principal set and KerberosTicket is + * is added to the Subject's principal set (unless the + * principal is specified as "*"). If isInitiator + * is true, the KerberosTicket is * added to the Subject's private credentials. * *

If the configuration entry for KerberosLoginModule * has the option storeKey set to true, then - * KerberosKey will also be added to the + * KerberosKey or KeyTab will also be added to the * subject's private credentials. KerberosKey, the principal's - * key will be either obtained from the keytab or - * derived from user's password. + * key(s) will be derived from user's password, and KeyTab is + * the keytab used when useKeyTab is set to true. The + * KeyTab object is restricted to be used by the specified + * principal unless the principal value is "*". * *

This LoginModule recognizes the doNotPrompt * option. If set to true the user will not be prompted for the password. @@ -75,8 +78,8 @@ import sun.misc.HexDumpEncoder; * *

The principal name can be specified in the configuration entry * by using the option principal. The principal name - * can either be a simple user name or a service name such as - * host/mission.eng.sun.com. The principal can also + * can either be a simple user name, a service name such as + * host/mission.eng.sun.com, or "*". The principal can also * be set using the system property sun.security.krb5.principal. * This property is checked during login. If this property is not set, then * the principal name from the configuration is used. In the @@ -87,11 +90,10 @@ import sun.misc.HexDumpEncoder; * *

The following is a list of configuration options supported * for Krb5LoginModule: - *

- *
refreshKrb5Config:
+ *
+ *
refreshKrb5Config:
*
Set this to true, if you want the configuration * to be refreshed before the login method is called.
- *

*

useTicketCache:
*
Set this to true, if you want the * TGT to be obtained @@ -112,19 +114,16 @@ import sun.misc.HexDumpEncoder; * ticketCache. * For Windows, if a ticket cannot be retrieved from the file ticket cache, * it will use Local Security Authority (LSA) API to get the TGT. - *

*

ticketCache:
*
Set this to the name of the ticket * cache that contains user's TGT. * If this is set, useTicketCache * must also be set to true; Otherwise a configuration error will * be returned.
- *

*

renewTGT:
*
Set this to true, if you want to renew * the TGT. If this is set, useTicketCache must also be * set to true; otherwise a configuration error will be returned.
- *

*

doNotPrompt:
*
Set this to true if you do not want to be * prompted for the password @@ -132,7 +131,6 @@ import sun.misc.HexDumpEncoder; * or through shared state.(Default is false) * If set to true, credential must be obtained through cache, keytab, * or shared state. Otherwise, authentication will fail.
- *

*

useKeyTab:
*
Set this to true if you * want the module to get the principal's key from the @@ -144,15 +142,15 @@ import sun.misc.HexDumpEncoder; * If it is not specified in the Kerberos configuration file * then it will look for the file * {user.home}{file.separator}krb5.keytab.
- *

*

keyTab:
*
Set this to the file name of the * keytab to get principal's secret key.
- *

*

storeKey:
- *
Set this to true to if you want the - * principal's key to be stored in the Subject's private credentials.
- *

+ *

Set this to true to if you want the keytab or the + * principal's key to be stored in the Subject's private credentials. + * For isInitiator being false, if principal + * is "*", the {@link KeyTab} stored can be used by anyone, otherwise, + * it's restricted to be used by the specified principal only.
*
principal:
*
The name of the principal that should * be used. The principal can be a simple username such as @@ -165,8 +163,13 @@ import sun.misc.HexDumpEncoder; * sun.security.krb5.principal. In addition, if this * system property is defined, then it will be used. If this property * is not set, then the principal name from the configuration will be - * used.
- *

+ * used. + * The principal name can be set to "*" when isInitiator is false. + * In this case, the acceptor is not bound to a single principal. It can + * act as any principal an initiator requests if keys for that principal + * can be found. When isInitiator is true, the principal name + * cannot be set to "*". + * *

isInitiator:
*
Set this to true, if initiator. Set this to false, if acceptor only. * (Default is true). @@ -177,18 +180,20 @@ import sun.misc.HexDumpEncoder; * Configuration * options that enable you to share username and passwords across different * authentication modules: - *
+ * 
* - * useFirstPass if, true, this LoginModule retrieves the + *
useFirstPass:
+ *
if, true, this LoginModule retrieves the * username and password from the module's shared state, * using "javax.security.auth.login.name" and * "javax.security.auth.login.password" as the respective * keys. The retrieved values are used for authentication. * If authentication fails, no attempt for a retry * is made, and the failure is reported back to the - * calling application. + * calling application.
* - * tryFirstPass if, true, this LoginModule retrieves the + *
tryFirstPass:
+ *
if, true, this LoginModule retrieves the * the username and password from the module's shared * state using "javax.security.auth.login.name" and * "javax.security.auth.login.password" as the respective @@ -198,26 +203,28 @@ import sun.misc.HexDumpEncoder; * CallbackHandler to retrieve a new username * and password, and another attempt to authenticate * is made. If the authentication fails, - * the failure is reported back to the calling application + * the failure is reported back to the calling application
* - * storePass if, true, this LoginModule stores the username and + *
storePass:
+ *
if, true, this LoginModule stores the username and * password obtained from the CallbackHandler in the * modules shared state, using * "javax.security.auth.login.name" and * "javax.security.auth.login.password" as the respective * keys. This is not performed if existing values already * exist for the username and password in the shared - * state, or if authentication fails. + * state, or if authentication fails.
* - * clearPass if, true, this LoginModule clears the + *
clearPass:
+ *
if, true, this LoginModule clears the * username and password stored in the module's shared * state after both phases of authentication - * (login and commit) have completed. - *
+ * (login and commit) have completed.
+ *
*

If the principal system property or key is already provided, the value of * "javax.security.auth.login.name" in the shared state is ignored. *

When multiple mechanisms to retrieve a ticket or key is provided, the - * preference order looks like this: + * preference order is: *

    *
  1. ticket cache *
  2. keytab @@ -225,7 +232,7 @@ import sun.misc.HexDumpEncoder; *
  3. user prompt *
*

Note that if any step fails, it will fallback to the next step. - * There's only one exception, it the shared state step fails and + * There's only one exception, if the shared state step fails and * useFirstPass=true, no user prompt is made. *

Examples of some configuration values for Krb5LoginModule in * JAAS config file and the results are: @@ -318,7 +325,7 @@ import sun.misc.HexDumpEncoder; *

useKeyTab = true * keyTab=<keytabname> * storeKey=true - * doNotPrompt=true; + * doNotPrompt=false; * *

The user will be prompted for the service principal name. * If the principal's @@ -328,6 +335,14 @@ import sun.misc.HexDumpEncoder; * If successful the TGT will be added to the * Subject's private credentials set. Otherwise the authentication will * fail. + *

    + *

    isInitiator = false useKeyTab = true + * keyTab=<keytabname> + * storeKey=true + * principal=*; + *

+ *

The acceptor will be an unbound acceptor and it can act as any principal + * as long that principal has keys in the keytab. *

    *

    * useTicketCache=true @@ -409,6 +424,7 @@ public class Krb5LoginModule implements LoginModule { private KerberosTicket kerbTicket = null; private KerberosKey[] kerbKeys = null; private StringBuffer krb5PrincName = null; + private boolean unboundServer = false; private char[] password = null; private static final String NAME = "javax.security.auth.login.name"; @@ -520,8 +536,6 @@ public class Krb5LoginModule implements LoginModule { */ public boolean login() throws LoginException { - int len; - validateConfiguration(); if (refreshKrb5Config) { try { if (debug) { @@ -544,6 +558,12 @@ public class Krb5LoginModule implements LoginModule { } } + validateConfiguration(); + + if (krb5PrincName != null && krb5PrincName.toString().equals("*")) { + unboundServer = true; + } + if (tryFirstPass) { try { attemptAuthentication(true); @@ -698,9 +718,17 @@ public class Krb5LoginModule implements LoginModule { * (encKeys == null) to check. */ if (useKeyTab) { - ktab = (keyTabName == null) - ? KeyTab.getInstance() - : KeyTab.getInstance(new File(keyTabName)); + if (!unboundServer) { + KerberosPrincipal kp = + new KerberosPrincipal(principal.getName()); + ktab = (keyTabName == null) + ? KeyTab.getInstance(kp) + : KeyTab.getInstance(kp, new File(keyTabName)); + } else { + ktab = (keyTabName == null) + ? KeyTab.getUnboundInstance() + : KeyTab.getUnboundInstance(new File(keyTabName)); + } if (isInitiator) { if (Krb5Util.keysFromJavaxKeyTab(ktab, principal).length == 0) { @@ -939,6 +967,13 @@ public class Krb5LoginModule implements LoginModule { ("Configuration Error" + " - either useTicketCache should be " + " true or renewTGT should be false"); + if (krb5PrincName != null && krb5PrincName.toString().equals("*")) { + if (isInitiator) { + throw new LoginException + ("Configuration Error" + + " - principal cannot be * when isInitiator is true"); + } + } } private boolean isCurrent(Credentials creds) @@ -1052,7 +1087,10 @@ public class Krb5LoginModule implements LoginModule { } // Let us add the kerbClientPrinc,kerbTicket and KeyTab/KerbKey (if // storeKey is true) - if (!princSet.contains(kerbClientPrinc)) { + + // We won't add "*" as a KerberosPrincipal + if (!unboundServer && + !princSet.contains(kerbClientPrinc)) { princSet.add(kerbClientPrinc); } diff --git a/jdk/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java b/jdk/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java index 4b20626ec75..fbf74718933 100644 --- a/jdk/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java +++ b/jdk/src/share/classes/javax/security/auth/kerberos/JavaxSecurityAuthKerberosAccessImpl.java @@ -31,8 +31,8 @@ import sun.security.krb5.PrincipalName; class JavaxSecurityAuthKerberosAccessImpl implements JavaxSecurityAuthKerberosAccess { - public EncryptionKey[] keyTabGetEncryptionKeys( - KeyTab ktab, PrincipalName principal) { - return ktab.getEncryptionKeys(principal); + public sun.security.krb5.internal.ktab.KeyTab keyTabTakeSnapshot( + KeyTab ktab) { + return ktab.takeSnapshot(); } } diff --git a/jdk/src/share/classes/javax/security/auth/kerberos/KeyTab.java b/jdk/src/share/classes/javax/security/auth/kerberos/KeyTab.java index 3ebce9975a2..32f644b5906 100644 --- a/jdk/src/share/classes/javax/security/auth/kerberos/KeyTab.java +++ b/jdk/src/share/classes/javax/security/auth/kerberos/KeyTab.java @@ -41,6 +41,20 @@ import sun.security.krb5.RealmException; * {@link javax.security.auth.Subject Subject} during the commit phase of the * authentication process. *

    + * If a {@code KeyTab} object is obtained from {@link #getUnboundInstance()} + * or {@link #getUnboundInstance(java.io.File)}, it is unbound and thus can be + * used by any service principal. Otherwise, if it's obtained from + * {@link #getInstance(KerberosPrincipal)} or + * {@link #getInstance(KerberosPrincipal, java.io.File)}, it is bound to the + * specific service principal and can only be used by it. + *

    + * Please note the constructors {@link #getInstance()} and + * {@link #getInstance(java.io.File)} were created when there was no support + * for unbound keytabs. These methods should not be used anymore. An object + * created with either of these methods are considered to be bound to an + * unknown principal, which means, its {@link #isBound()} returns true and + * {@link #getPrincipal()} returns null. + *

    * It might be necessary for the application to be granted a * {@link javax.security.auth.PrivateCredentialPermission * PrivateCredentialPermission} if it needs to access the KeyTab @@ -52,7 +66,7 @@ import sun.security.krb5.RealmException; * The keytab file format is described at * * http://www.ioplex.com/utilities/keytab.txt. - * + *

    * @since 1.7 */ public final class KeyTab { @@ -74,21 +88,33 @@ public final class KeyTab { // is maintained in snapshot, this field is never "resolved". private final File file; + // Bound user: normally from the "principal" value in a JAAS krb5 + // login conf. Will be null if it's "*". + private final KerberosPrincipal princ; + + private final boolean bound; + // Set up JavaxSecurityAuthKerberosAccess in KerberosSecrets static { KerberosSecrets.setJavaxSecurityAuthKerberosAccess( new JavaxSecurityAuthKerberosAccessImpl()); } - private KeyTab(File file) { + private KeyTab(KerberosPrincipal princ, File file, boolean bound) { + this.princ = princ; this.file = file; + this.bound = bound; } /** - * Returns a {@code KeyTab} instance from a {@code File} object. + * Returns a {@code KeyTab} instance from a {@code File} object + * that is bound to an unknown service principal. *

    * The result of this method is never null. This method only associates * the returned {@code KeyTab} object with the file and does not read it. + *

    + * Developers should call {@link #getInstance(KerberosPrincipal,File)} + * when the bound service principal is known. * @param file the keytab {@code File} object, must not be null * @return the keytab instance * @throws NullPointerException if the {@code file} argument is null @@ -97,23 +123,99 @@ public final class KeyTab { if (file == null) { throw new NullPointerException("file must be non null"); } - return new KeyTab(file); + return new KeyTab(null, file, true); } /** - * Returns the default {@code KeyTab} instance. + * Returns an unbound {@code KeyTab} instance from a {@code File} + * object. + *

    + * The result of this method is never null. This method only associates + * the returned {@code KeyTab} object with the file and does not read it. + * @param file the keytab {@code File} object, must not be null + * @return the keytab instance + * @throws NullPointerException if the file argument is null + * @since 1.8 + */ + public static KeyTab getUnboundInstance(File file) { + if (file == null) { + throw new NullPointerException("file must be non null"); + } + return new KeyTab(null, file, false); + } + + /** + * Returns a {@code KeyTab} instance from a {@code File} object + * that is bound to the specified service principal. + *

    + * The result of this method is never null. This method only associates + * the returned {@code KeyTab} object with the file and does not read it. + * @param princ the bound service principal, must not be null + * @param file the keytab {@code File} object, must not be null + * @return the keytab instance + * @throws NullPointerException if either of the arguments is null + * @since 1.8 + */ + public static KeyTab getInstance(KerberosPrincipal princ, File file) { + if (princ == null) { + throw new NullPointerException("princ must be non null"); + } + if (file == null) { + throw new NullPointerException("file must be non null"); + } + return new KeyTab(princ, file, true); + } + + /** + * Returns the default {@code KeyTab} instance that is bound + * to an unknown service principal. *

    * The result of this method is never null. This method only associates * the returned {@code KeyTab} object with the default keytab file and * does not read it. + *

    + * Developers should call {@link #getInstance(KerberosPrincipal)} + * when the bound service principal is known. * @return the default keytab instance. */ public static KeyTab getInstance() { - return new KeyTab(null); + return new KeyTab(null, null, true); + } + + /** + * Returns the default unbound {@code KeyTab} instance. + *

    + * The result of this method is never null. This method only associates + * the returned {@code KeyTab} object with the default keytab file and + * does not read it. + * @return the default keytab instance + * @since 1.8 + */ + public static KeyTab getUnboundInstance() { + return new KeyTab(null, null, false); + } + + /** + * Returns the default {@code KeyTab} instance that is bound + * to the specified service principal. + *

    + * The result of this method is never null. This method only associates + * the returned {@code KeyTab} object with the default keytab file and + * does not read it. + * @param princ the bound service principal, must not be null + * @return the default keytab instance + * @throws NullPointerException if {@code princ} is null + * @since 1.8 + */ + public static KeyTab getInstance(KerberosPrincipal princ) { + if (princ == null) { + throw new NullPointerException("princ must be non null"); + } + return new KeyTab(princ, null, true); } //Takes a snapshot of the keytab content - private sun.security.krb5.internal.ktab.KeyTab takeSnapshot() { + sun.security.krb5.internal.ktab.KeyTab takeSnapshot() { return sun.security.krb5.internal.ktab.KeyTab.getInstance(file); } @@ -147,6 +249,9 @@ public final class KeyTab { *

    * Any unsupported key read from the keytab is ignored and not included * in the result. + *

    + * If this keytab is bound to a specific principal, calling this method on + * another principal will return an empty array. * * @param principal the Kerberos principal, must not be null. * @return the keys (never null, may be empty) @@ -157,8 +262,11 @@ public final class KeyTab { */ public KerberosKey[] getKeys(KerberosPrincipal principal) { try { - EncryptionKey[] keys = takeSnapshot().readServiceKeys( - new PrincipalName(principal.getName())); + if (princ != null && !principal.equals(princ)) { + return new KerberosKey[0]; + } + PrincipalName pn = new PrincipalName(principal.getName()); + EncryptionKey[] keys = takeSnapshot().readServiceKeys(pn); KerberosKey[] kks = new KerberosKey[keys.length]; for (int i=0; iKeyTab */ public int hashCode() { - return Objects.hash(file); + return Objects.hash(file, princ, bound); } /** @@ -225,6 +336,31 @@ public final class KeyTab { } KeyTab otherKtab = (KeyTab) other; - return Objects.equals(otherKtab.file, file); + return Objects.equals(otherKtab.princ, princ) && + Objects.equals(otherKtab.file, file) && + bound == otherKtab.bound; + } + + /** + * Returns the service principal this {@code KeyTab} object + * is bound to. Returns {@code null} if it's not bound. + *

    + * Please note the deprecated constructors create a KeyTab object bound for + * some unknown principal. In this case, this method also returns null. + * User can call {@link #isBound()} to verify this case. + * @return the service principal + * @since 1.8 + */ + public KerberosPrincipal getPrincipal() { + return princ; + } + + /** + * Returns if the keytab is bound to a principal + * @return if the keytab is bound to a principal + * @since 1.8 + */ + public boolean isBound() { + return bound; } } diff --git a/jdk/src/share/classes/sun/security/jgss/LoginConfigImpl.java b/jdk/src/share/classes/sun/security/jgss/LoginConfigImpl.java index 41a783afef3..52e2fa4728d 100644 --- a/jdk/src/share/classes/sun/security/jgss/LoginConfigImpl.java +++ b/jdk/src/share/classes/sun/security/jgss/LoginConfigImpl.java @@ -175,6 +175,7 @@ public class LoginConfigImpl extends Configuration { options.put("useKeyTab", "true"); options.put("storeKey", "true"); options.put("doNotPrompt", "true"); + options.put("principal", "*"); options.put("isInitiator", "false"); } else { options.put("useTicketCache", "true"); diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java index f0495eef872..0d5a314ffd7 100644 --- a/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java +++ b/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Util.java @@ -242,15 +242,25 @@ public class Krb5Util { kerbTicket.getClientAddresses()); } + /** + * A helper method to get a sun..KeyTab from a javax..KeyTab + * @param ktab the javax..KeyTab object + * @return the sun..KeyTab object + */ + public static sun.security.krb5.internal.ktab.KeyTab + snapshotFromJavaxKeyTab(KeyTab ktab) { + return KerberosSecrets.getJavaxSecurityAuthKerberosAccess() + .keyTabTakeSnapshot(ktab); + } + /** * A helper method to get EncryptionKeys from a javax..KeyTab - * @param ktab the javax..KeyTab class + * @param ktab the javax..KeyTab object * @param cname the PrincipalName * @return the EKeys, never null, might be empty */ public static EncryptionKey[] keysFromJavaxKeyTab( KeyTab ktab, PrincipalName cname) { - return KerberosSecrets.getJavaxSecurityAuthKerberosAccess(). - keyTabGetEncryptionKeys(ktab, cname); + return snapshotFromJavaxKeyTab(ktab).readServiceKeys(cname); } } diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/ServiceCreds.java b/jdk/src/share/classes/sun/security/jgss/krb5/ServiceCreds.java index 21b8f57b229..824724bf34e 100644 --- a/jdk/src/share/classes/sun/security/jgss/krb5/ServiceCreds.java +++ b/jdk/src/share/classes/sun/security/jgss/krb5/ServiceCreds.java @@ -101,9 +101,22 @@ public final class ServiceCreds { if (serverPrincipal != null) { // A named principal sc.kp = new KerberosPrincipal(serverPrincipal); } else { - if (sc.allPrincs.size() == 1) { // choose the only one - sc.kp = sc.allPrincs.iterator().next(); - serverPrincipal = sc.kp.getName(); + // For compatibility reason, we set the name of default principal + // to the "only possible" name it can take, which means there is + // only one KerberosPrincipal and there is no unbound keytabs + if (sc.allPrincs.size() == 1) { + boolean hasUnbound = false; + for (KeyTab ktab: SubjectComber.findMany( + subj, null, null, KeyTab.class)) { + if (!ktab.isBound()) { + hasUnbound = true; + break; + } + } + if (!hasUnbound) { + sc.kp = sc.allPrincs.iterator().next(); + serverPrincipal = sc.kp.getName(); + } } } @@ -131,20 +144,35 @@ public final class ServiceCreds { } /** - * Gets keys for someone unknown. - * Used by TLS or as a fallback in getEKeys(). Can still return an - * empty array. + * Gets keys for "someone". Used in 2 cases: + * 1. By TLS because it needs to get keys before client comes in. + * 2. As a fallback in getEKeys() below. + * This method can still return an empty array. */ public KerberosKey[] getKKeys() { if (destroyed) { throw new IllegalStateException("This object is destroyed"); } - if (kp != null) { - return getKKeys(kp); - } else if (!allPrincs.isEmpty()) { - return getKKeys(allPrincs.iterator().next()); + KerberosPrincipal one = kp; // named principal + if (one == null && !allPrincs.isEmpty()) { // or, a known principal + one = allPrincs.iterator().next(); + } + if (one == null) { // Or, some random one + for (KeyTab ktab: ktabs) { + // Must be unbound keytab, otherwise, allPrincs is not empty + PrincipalName pn = + Krb5Util.snapshotFromJavaxKeyTab(ktab).getOneName(); + if (pn != null) { + one = new KerberosPrincipal(pn.getName()); + break; + } + } + } + if (one != null) { + return getKKeys(one); + } else { + return new KerberosKey[0]; } - return new KerberosKey[0]; } /** @@ -152,15 +180,13 @@ public final class ServiceCreds { * @param princ the target name initiator requests. Not null. * @return keys for the princ, never null, might be empty */ - private KerberosKey[] getKKeys(KerberosPrincipal princ) { - ArrayList keys = new ArrayList<>(); - if (kp != null && !princ.equals(kp)) { - return new KerberosKey[0]; // Not me + public KerberosKey[] getKKeys(KerberosPrincipal princ) { + if (destroyed) { + throw new IllegalStateException("This object is destroyed"); } - if (!allPrincs.contains(princ)) { - return new KerberosKey[0]; // Not someone I know, This check - // is necessary but a KeyTab has - // no principal name recorded. + ArrayList keys = new ArrayList<>(); + if (kp != null && !princ.equals(kp)) { // named principal + return new KerberosKey[0]; } for (KerberosKey k: kk) { if (k.getPrincipal().equals(princ)) { @@ -168,6 +194,13 @@ public final class ServiceCreds { } } for (KeyTab ktab: ktabs) { + if (ktab.getPrincipal() == null && ktab.isBound()) { + // legacy bound keytab. although we don't know who + // the bound principal is, it must be in allPrincs + if (!allPrincs.contains(princ)) { + continue; // skip this legacy bound keytab + } + } for (KerberosKey k: ktab.getKeys(princ)) { keys.add(k); } @@ -186,12 +219,12 @@ public final class ServiceCreds { } KerberosKey[] kkeys = getKKeys(new KerberosPrincipal(princ.getName())); if (kkeys.length == 0) { - // Note: old JDK does not perform real name checking. If the - // acceptor starts by name A but initiator requests for B, - // as long as their keys match (i.e. A's keys can decrypt B's - // service ticket), the authentication is OK. There are real - // customers depending on this to use different names for a - // single service. + // Fallback: old JDK does not perform real name checking. If the + // acceptor has host.sun.com but initiator requests for host, + // as long as their keys match (i.e. keys for one can decrypt + // the other's service ticket), the authentication is OK. + // There are real customers depending on this to use different + // names for a single service. kkeys = getKKeys(); } EncryptionKey[] ekeys = new EncryptionKey[kkeys.length]; diff --git a/jdk/src/share/classes/sun/security/jgss/krb5/SubjectComber.java b/jdk/src/share/classes/sun/security/jgss/krb5/SubjectComber.java index d267dbd4b21..ad1723fe09e 100644 --- a/jdk/src/share/classes/sun/security/jgss/krb5/SubjectComber.java +++ b/jdk/src/share/classes/sun/security/jgss/krb5/SubjectComber.java @@ -86,36 +86,39 @@ class SubjectComber { List answer = (oneOnly ? null : new ArrayList()); if (credClass == KeyTab.class) { - // TODO: There is currently no good way to filter out keytabs - // not for serverPrincipal. We can only check the principal - // set. If the server is not there, we can be sure none of the - // keytabs should be used, otherwise, use all for safety. - boolean useAll = false; - if (serverPrincipal != null) { - for (KerberosPrincipal princ: - subject.getPrincipals(KerberosPrincipal.class)) { - if (princ.getName().equals(serverPrincipal)) { - useAll = true; - break; + Iterator iterator = + subject.getPrivateCredentials(KeyTab.class).iterator(); + while (iterator.hasNext()) { + KeyTab t = iterator.next(); + if (serverPrincipal != null && t.isBound()) { + KerberosPrincipal name = t.getPrincipal(); + if (name != null) { + if (!serverPrincipal.equals(name.getName())) { + continue; + } + } else { + // legacy bound keytab. although we don't know who + // the bound principal is, it must be in allPrincs + boolean found = false; + for (KerberosPrincipal princ: + subject.getPrincipals(KerberosPrincipal.class)) { + if (princ.getName().equals(serverPrincipal)) { + found = true; + break; + } + } + if (!found) continue; } } - } else { - useAll = true; - } - if (useAll) { - Iterator iterator = - subject.getPrivateCredentials(KeyTab.class).iterator(); - while (iterator.hasNext()) { - KeyTab t = iterator.next(); - if (DEBUG) { - System.out.println("Found " + credClass.getSimpleName() - + " " + t); - } - if (oneOnly) { - return t; - } else { - answer.add(credClass.cast(t)); - } + // Check passed, we can add now + if (DEBUG) { + System.out.println("Found " + credClass.getSimpleName() + + " " + t); + } + if (oneOnly) { + return t; + } else { + answer.add(credClass.cast(t)); } } } else if (credClass == KerberosKey.class) { diff --git a/jdk/src/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java b/jdk/src/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java index 3992e487108..ae3dc3d0b04 100644 --- a/jdk/src/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java +++ b/jdk/src/share/classes/sun/security/krb5/JavaxSecurityAuthKerberosAccess.java @@ -35,9 +35,8 @@ import sun.security.krb5.PrincipalName; */ public interface JavaxSecurityAuthKerberosAccess { /** - * Returns keys for a principal in a keytab. - * @return the keys, never null, can be empty. + * Returns a snapshot to the backing keytab */ - public EncryptionKey[] keyTabGetEncryptionKeys( - KeyTab ktab, PrincipalName principal); + public sun.security.krb5.internal.ktab.KeyTab keyTabTakeSnapshot( + KeyTab ktab); } diff --git a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java index d1023de9de3..b556c90524c 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java @@ -46,6 +46,7 @@ import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import java.util.Vector; +import sun.security.jgss.krb5.ServiceCreds; /** * This class represents key table. The key table functions deal with storing @@ -267,6 +268,15 @@ public class KeyTab implements KeyTabConstants { } } + /** + * Returns a principal name in this keytab. Used by + * {@link ServiceCreds#getKKeys()}. + */ + public PrincipalName getOneName() { + int size = entries.size(); + return size > 0 ? entries.elementAt(size-1).service : null; + } + /** * Reads all keys for a service from the keytab file that have * etypes that have been configured for use. If there are multiple diff --git a/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java b/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java index 3a9ca47677a..03cdc5712d0 100644 --- a/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java +++ b/jdk/src/share/classes/sun/security/provider/ConfigSpiFile.java @@ -404,6 +404,7 @@ public final class ConfigSpiFile extends ConfigurationSpi { st.wordChars('$', '$'); st.wordChars('_', '_'); st.wordChars('-', '-'); + st.wordChars('*', '*'); st.lowerCaseMode(false); st.slashSlashComments(true); st.slashStarComments(true); diff --git a/jdk/test/sun/security/krb5/ServiceCredsCombination.java b/jdk/test/sun/security/krb5/ServiceCredsCombination.java index 3208560e788..5c6ac4b1894 100644 --- a/jdk/test/sun/security/krb5/ServiceCredsCombination.java +++ b/jdk/test/sun/security/krb5/ServiceCredsCombination.java @@ -62,11 +62,38 @@ public class ServiceCredsCombination { check("b", "b", princ("a"), princ("b"), oldktab(), oldktab()); check(null, null, princ("a"), princ("b"), oldktab(), oldktab()); check("x", "NOCRED", princ("a"), princ("b"), oldktab(), oldktab()); + // bound ktab + check("c", "c", princ("c"), ktab("c")); + check(null, "c", princ("c"), ktab("c")); + // unbound ktab + check("x", "x", ktab()); + check(null, null, ktab()); + // Two bound ktab + check("c1", "c1", princ("c1"), princ("c2"), ktab("c1"), ktab("c2")); + check("c2", "c2", princ("c1"), princ("c2"), ktab("c1"), ktab("c2")); + check("x", "NOCRED", princ("c1"), princ("c2"), ktab("c1"), ktab("c2")); + check(null, null, princ("c1"), princ("c2"), ktab("c1"), ktab("c2")); + // One bound, one unbound + check("c1", "c1", princ("c1"), ktab("c1"), ktab()); + check("x", "x", princ("c1"), ktab("c1"), ktab()); + check(null, null, princ("c1"), ktab("c1"), ktab()); + // Two unbound ktab + check("x", "x", ktab(), ktab()); + check(null, null, ktab(), ktab()); // pass + old ktab check("a", "a", princ("a"), princ("b"), key("a"), oldktab()); check("b", "b", princ("a"), princ("b"), key("a"), oldktab()); check(null, null, princ("a"), princ("b"), key("a"), oldktab()); check("x", "NOCRED", princ("a"), princ("b"), key("a"), oldktab()); + // pass + bound ktab + check("a", "a", princ("a"), princ("c"), key("a"), ktab("c")); + check("c", "c", princ("a"), princ("c"), key("a"), ktab("c")); + check("x", "NOCRED", princ("a"), princ("c"), key("a"), ktab("c")); + check(null, null, princ("a"), princ("c"), key("a"), ktab("c")); + // pass + unbound ktab + check("a", "a", princ("a"), key("a"), ktab()); + check("x", "x", princ("a"), key("a"), ktab()); + check(null, null, princ("a"), key("a"), ktab()); // Compatibility, automatically add princ for keys check(null, "a", key("a")); check("x", "NOCRED", key("a")); @@ -130,4 +157,10 @@ public class ServiceCredsCombination { private static KeyTab oldktab() { return KeyTab.getInstance(); } + static KeyTab ktab(String s) { + return KeyTab.getInstance(princ(s)); + } + static KeyTab ktab() { + return KeyTab.getUnboundInstance(); + } } diff --git a/jdk/test/sun/security/krb5/auto/AcceptPermissions.java b/jdk/test/sun/security/krb5/auto/AcceptPermissions.java index 3a6d422842f..1b562eaf99a 100644 --- a/jdk/test/sun/security/krb5/auto/AcceptPermissions.java +++ b/jdk/test/sun/security/krb5/auto/AcceptPermissions.java @@ -26,7 +26,8 @@ * @bug 9999999 * @summary default principal can act as anyone * @compile -XDignore.symbol.file AcceptPermissions.java - * @run main/othervm AcceptPermissions + * @run main/othervm AcceptPermissions two + * @run main/othervm AcceptPermissions unbound */ import java.nio.file.Files; @@ -83,15 +84,20 @@ public class AcceptPermissions extends SecurityManager { public static void main(String[] args) throws Exception { System.setSecurityManager(new AcceptPermissions()); new OneKDC(null).writeJAASConf(); - String two = "two {\n" + String moreEntries = "two {\n" + " com.sun.security.auth.module.Krb5LoginModule required" + " principal=\"" + OneKDC.SERVER + "\" useKeyTab=true" + " isInitiator=false storeKey=true;\n" + " com.sun.security.auth.module.Krb5LoginModule required" + " principal=\"" + OneKDC.BACKEND + "\" useKeyTab=true" + " isInitiator=false storeKey=true;\n" + + "};\n" + + "unbound {" + + " com.sun.security.auth.module.Krb5LoginModule required" + + " principal=* useKeyTab=true" + + " isInitiator=false storeKey=true;\n" + "};\n"; - Files.write(Paths.get(OneKDC.JAAS_CONF), two.getBytes(), + Files.write(Paths.get(OneKDC.JAAS_CONF), moreEntries.getBytes(), StandardOpenOption.APPEND); Context c, s; @@ -114,7 +120,7 @@ public class AcceptPermissions extends SecurityManager { // Named principal (even if there are 2 JAAS modules) initPerms(OneKDC.SERVER); c = Context.fromJAAS("client"); - s = Context.fromJAAS("two"); + s = Context.fromJAAS(args[0]); c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); s.startAsServer(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); checkPerms(); @@ -136,7 +142,7 @@ public class AcceptPermissions extends SecurityManager { // Default principal with no predictable name initPerms(); // permission not needed for cred !!! c = Context.fromJAAS("client"); - s = Context.fromJAAS("two"); + s = Context.fromJAAS(args[0]); c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); checkPerms(); diff --git a/jdk/test/sun/security/krb5/auto/GSSUnbound.java b/jdk/test/sun/security/krb5/auto/GSSUnbound.java new file mode 100644 index 00000000000..a1022d4f8c8 --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/GSSUnbound.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2012, 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 8001104 + * @summary Unbound SASL service: the GSSAPI/krb5 mech + * @compile -XDignore.symbol.file GSSUnbound.java + * @run main/othervm GSSUnbound + */ + +import java.security.Security; +import sun.security.jgss.GSSUtil; + +// Testing JGSS without JAAS +public class GSSUnbound { + + public static void main(String[] args) throws Exception { + + new OneKDC(null); + + Context c, s; + c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + s = Context.fromThinAir(); + + // This is the only setting needed for JGSS without JAAS. The default + // JAAS config entries are already created by OneKDC. + System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); + + c.startAsClient(OneKDC.BACKEND, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); + + Context.handshake(c, s); + + Context.transmit("i say high --", c, s); + Context.transmit(" you say low", s, c); + + s.dispose(); + c.dispose(); + } +} diff --git a/jdk/test/sun/security/krb5/auto/OneKDC.java b/jdk/test/sun/security/krb5/auto/OneKDC.java index 5c87abb961a..90a7e8e8748 100644 --- a/jdk/test/sun/security/krb5/auto/OneKDC.java +++ b/jdk/test/sun/security/krb5/auto/OneKDC.java @@ -76,6 +76,8 @@ public class OneKDC extends KDC { Config.refresh(); writeKtab(KTAB); + Security.setProperty("auth.login.defaultCallbackHandler", + "OneKDC$CallbackForClient"); } /** @@ -93,7 +95,7 @@ public class OneKDC extends KDC { " com.sun.security.auth.module.Krb5LoginModule required;\n};\n" + "com.sun.security.jgss.krb5.accept {\n" + " com.sun.security.auth.module.Krb5LoginModule required\n" + - " principal=\"" + SERVER + "\"\n" + + " principal=\"*\"\n" + " useKeyTab=true\n" + " isInitiator=false\n" + " storeKey=true;\n};\n" + @@ -112,7 +114,6 @@ public class OneKDC extends KDC { " isInitiator=false;\n};\n" ).getBytes()); fos.close(); - Security.setProperty("auth.login.defaultCallbackHandler", "OneKDC$CallbackForClient"); } /** diff --git a/jdk/test/sun/security/krb5/auto/SaslUnbound.java b/jdk/test/sun/security/krb5/auto/SaslUnbound.java new file mode 100644 index 00000000000..64d9a1b3c6e --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/SaslUnbound.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2012, 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 8001104 + * @summary Unbound SASL service: the GSSAPI/krb5 mech + * @compile -XDignore.symbol.file SaslUnbound.java + * @run main/othervm SaslUnbound 0 + * @run main/othervm/fail SaslUnbound 1 + * @run main/othervm/fail SaslUnbound 2 + * @run main/othervm/fail SaslUnbound 3 + * @run main/othervm/fail SaslUnbound 4 + */ +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.*; + +public class SaslUnbound { + + public static void main(String[] args) throws Exception { + + String serverProtocol, serverName; + switch (args[0].charAt(0)) { + case '1': // Using another protocol, should fail + serverProtocol = "serv"; + serverName = null; + break; + case '2': // Using another protocol, should fail + serverProtocol = "otherwise"; + serverName = null; + break; + case '3': // Using another protocol, should fail + serverProtocol = "otherwise"; + serverName = "host." + OneKDC.REALM; + break; + case '4': // Bound to another serverName, should fail. + serverProtocol = "server"; + serverName = "host2." + OneKDC.REALM; + break; + default: // Good unbound server + serverProtocol = "server"; + serverName = null; + break; + } + new OneKDC(null).writeJAASConf(); + System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); + + HashMap clntprops = new HashMap(); + clntprops.put(Sasl.QOP, "auth-conf"); + SaslClient sc = Sasl.createSaslClient( + new String[]{"GSSAPI"}, null, "server", + "host." + OneKDC.REALM, clntprops, null); + + final HashMap srvprops = new HashMap(); + srvprops.put(Sasl.QOP, "auth,auth-int,auth-conf"); + SaslServer ss = Sasl.createSaslServer("GSSAPI", serverProtocol, + serverName, srvprops, + new CallbackHandler() { + public void handle(Callback[] callbacks) + throws IOException, UnsupportedCallbackException { + for (Callback cb : callbacks) { + if (cb instanceof RealmCallback) { + ((RealmCallback) cb).setText(OneKDC.REALM); + } else if (cb instanceof AuthorizeCallback) { + ((AuthorizeCallback) cb).setAuthorized(true); + } + } + } + }); + + byte[] token = new byte[0]; + while (!sc.isComplete() || !ss.isComplete()) { + if (!sc.isComplete()) { + token = sc.evaluateChallenge(token); + } + if (!ss.isComplete()) { + token = ss.evaluateResponse(token); + } + } + System.out.println(ss.getNegotiatedProperty(Sasl.BOUND_SERVER_NAME)); + byte[] hello = "hello".getBytes(); + token = sc.wrap(hello, 0, hello.length); + token = ss.unwrap(token, 0, token.length); + if (!Arrays.equals(hello, token)) { + throw new Exception("Message altered"); + } + } +} diff --git a/jdk/test/sun/security/krb5/auto/UnboundService.java b/jdk/test/sun/security/krb5/auto/UnboundService.java new file mode 100644 index 00000000000..c6d093c9266 --- /dev/null +++ b/jdk/test/sun/security/krb5/auto/UnboundService.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2012, 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 8001104 + * @summary Unbound SASL service: the GSSAPI/krb5 mech + * @compile -XDignore.symbol.file UnboundService.java + * @run main/othervm UnboundService null null + * @run main/othervm UnboundService server/host.rabbit.hole null + * @run main/othervm UnboundService server/host.rabbit.hole@RABBIT.HOLE null + * @run main/othervm/fail UnboundService backend/host.rabbit.hole null + * @run main/othervm UnboundService null server@host.rabbit.hole + * @run main/othervm UnboundService server/host.rabbit.hole server@host.rabbit.hole + * @run main/othervm UnboundService server/host.rabbit.hole@RABBIT.HOLE server@host.rabbit.hole + * @run main/othervm/fail UnboundService backend/host.rabbit.hole server@host.rabbit.hole + */ + +import java.io.File; +import java.io.FileOutputStream; +import sun.security.jgss.GSSUtil; + +public class UnboundService { + + /** + * @param args JAAS config pricipal and GSSCredential creation name + */ + public static void main(String[] args) throws Exception { + + String principal = args[0]; + if (principal.equals("null")) principal = null; + + String server = args[1]; + if (server.equals("null")) server = null; + + new OneKDC(null).writeJAASConf(); + File f = new File(OneKDC.JAAS_CONF); + try (FileOutputStream fos = new FileOutputStream(f)) { + fos.write(( + "client {\n" + + " com.sun.security.auth.module.Krb5LoginModule required;\n};\n" + + "unbound {\n" + + " com.sun.security.auth.module.Krb5LoginModule required\n" + + " useKeyTab=true\n" + + " principal=" + + (principal==null? "*" :("\"" + principal + "\"")) + "\n" + + " doNotPrompt=true\n" + + " isInitiator=false\n" + + " storeKey=true;\n};\n" + ).getBytes()); + } + + Context c, s; + c = Context.fromJAAS("client"); + s = Context.fromJAAS("unbound"); + + c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID); + s.startAsServer(server, GSSUtil.GSS_KRB5_MECH_OID); + + Context.handshake(c, s); + + s.dispose(); + c.dispose(); + } +} From 76953b4d1e941a364ef931eef42447adb30e397a Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Sat, 9 Feb 2013 16:43:58 +0800 Subject: [PATCH 10/39] 8007761: NTLM coding errors Reviewed-by: chegar --- .../share/classes/com/sun/security/ntlm/Client.java | 3 +-- .../share/classes/com/sun/security/ntlm/NTLM.java | 12 ++++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/jdk/src/share/classes/com/sun/security/ntlm/Client.java b/jdk/src/share/classes/com/sun/security/ntlm/Client.java index fcad176b052..7117cdcdc93 100644 --- a/jdk/src/share/classes/com/sun/security/ntlm/Client.java +++ b/jdk/src/share/classes/com/sun/security/ntlm/Client.java @@ -138,8 +138,7 @@ public final class Client extends NTLM { domain = domainFromServer; } if (domain == null) { - throw new NTLMException(NTLMException.NO_DOMAIN_INFO, - "No domain info"); + domain = ""; } int flags = 0x88200 | (inputFlags & 3); diff --git a/jdk/src/share/classes/com/sun/security/ntlm/NTLM.java b/jdk/src/share/classes/com/sun/security/ntlm/NTLM.java index f0949b13a0a..b85fcee7812 100644 --- a/jdk/src/share/classes/com/sun/security/ntlm/NTLM.java +++ b/jdk/src/share/classes/com/sun/security/ntlm/NTLM.java @@ -136,10 +136,10 @@ class NTLM { int readInt(int offset) throws NTLMException { try { - return internal[offset] & 0xff + - (internal[offset+1] & 0xff << 8) + - (internal[offset+2] & 0xff << 16) + - (internal[offset+3] & 0xff << 24); + return (internal[offset] & 0xff) + + ((internal[offset+1] & 0xff) << 8) + + ((internal[offset+2] & 0xff) << 16) + + ((internal[offset+3] & 0xff) << 24); } catch (ArrayIndexOutOfBoundsException ex) { throw new NTLMException(NTLMException.PACKET_READ_ERROR, "Input message incorrect size"); @@ -148,8 +148,8 @@ class NTLM { int readShort(int offset) throws NTLMException { try { - return internal[offset] & 0xff + - (internal[offset+1] & 0xff << 8); + return (internal[offset] & 0xff) + + ((internal[offset+1] & 0xff << 8)); } catch (ArrayIndexOutOfBoundsException ex) { throw new NTLMException(NTLMException.PACKET_READ_ERROR, "Input message incorrect size"); From 8a4107ab649f877a4a6ca29f978629aa19d606f2 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Sun, 10 Feb 2013 08:07:59 -0800 Subject: [PATCH 11/39] 8007519: [unpack200] produces bad class files when producing BootstrapMethods attribute Reviewed-by: alanb --- jdk/test/ProblemList.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 1870b0b9219..69255074326 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -317,13 +317,16 @@ sun/tools/jconsole/ImmutableResourceTest.sh generic-all # 7132203 sun/jvmstat/monitor/MonitoredVm/CR6672135.java generic-all -# Tests take too long, see 7143279 -tools/pack200/CommandLineTests.java generic-all -tools/pack200/Pack200Test.java generic-all +# Tests take too long, on sparcs see 7143279 +tools/pack200/CommandLineTests.java solaris-all, macosx-all +tools/pack200/Pack200Test.java solaris-all, macosx-all # 7150569 tools/launcher/UnicodeTest.java macosx-all +# 8006039 +tools/launcher/I18NJarTest.java macosx-all + # 8007410 tools/launcher/FXLauncherTest.java linux-all From 83b9b38fc5e75b659f5327340318cb348b075228 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Sun, 10 Feb 2013 08:49:39 -0800 Subject: [PATCH 12/39] 8007902: [unpack200] incorrect BootstrapMethods attribute Reviewed-by: jjh --- .../com/sun/java/util/jar/pack/unpack.cpp | 3 ++- jdk/test/tools/pack200/Pack200Test.java | 4 ++-- .../pack200/pack200-verifier/data/golden.jar | Bin 423427 -> 433984 bytes 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp index bc91827f66c..4b5e38a0de1 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp @@ -4758,8 +4758,8 @@ int unpacker::write_bsms(int naOffset, int na) { PTRLIST_QSORT(cp.requested_bsms, outputEntry_cmp); // append the BootstrapMethods attribute (after the InnerClasses attr): putref(cp.sym[cpool::s_BootstrapMethods]); + // make a note of the offset, for lazy patching int sizeOffset = (int)wpoffset(); - byte* sizewp = wp; putu4(-99); // attr size will be patched putu2(cur_class_local_bsm_count); int written_bsms = 0; @@ -4776,6 +4776,7 @@ int unpacker::write_bsms(int naOffset, int na) { written_bsms += 1; } assert(written_bsms == cur_class_local_bsm_count); // else insane + byte* sizewp = wp_at(sizeOffset); putu4_at(sizewp, (int)(wp - (sizewp+4))); // size of code attr putu2_at(wp_at(naOffset), ++na); // increment class attr count } diff --git a/jdk/test/tools/pack200/Pack200Test.java b/jdk/test/tools/pack200/Pack200Test.java index 476ece18216..d897bf86824 100644 --- a/jdk/test/tools/pack200/Pack200Test.java +++ b/jdk/test/tools/pack200/Pack200Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2013, 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 @@ -30,7 +30,7 @@ import java.util.jar.*; /* * @test - * @bug 6521334 6712743 + * @bug 6521334 6712743 8007902 * @summary check for memory leaks, test general packer/unpacker functionality\ * using native and java unpackers * @compile -XDignore.symbol.file Utils.java Pack200Test.java diff --git a/jdk/test/tools/pack200/pack200-verifier/data/golden.jar b/jdk/test/tools/pack200/pack200-verifier/data/golden.jar index 913fe14340e22ba8b47f4fdceb2e0b1919cbd370..511cc0f43ab044021c1ed5ff60b76f4da4472e0f 100644 GIT binary patch delta 11227 zcmb7~Wl&sQv+t2%g1bu~xVr^+X9yaC1$TF!0E4>@5+Jw-cZcBa?gWAlt|2GS`<_$p zxgYMWx~po{+TFdocdu2o*N0#ILrzJ0x=1lUC?f*!;gFG$;ntNDq=GO*G2t6A5#H#6 zw-ptn;QrTO`TK0+Xzs(|ZsF$6VQb=P!r|d=W6$B{?rLG;z#;8qZ*O7d?&RvmZf0-d z=C&a6#+!U#;Uaca$;;Adk%F^m!!RPv* zb467A`gT(u&NxkQ3Z5eU1SnzHFX<@3>MlXpwoc_7k)YPI6 z+B)s6^p@yRa0LU?@qO#GOF3SJ3n|gu1}CzWiyc3a8}V-g1_N-&b<4LI1cRQc6@zh? zJ`CM{BnifV z>bIV!sKIUq+q7(8n6>z^o;ypUcrBR>!wYkse!i*f|w1?!#IB?-SMF;A@?>_l)v2&mOfcTP!$I(BQ z?Tut~^rHeMFY?ot!6;-&=u)U7Cz_16V+Liy8;?i;ENslO**8#SuwJ}#X0Wx>BYeq@ zaWUDSYwaD6croxyUPIw!`=E(&A@98Krf)*5fNLMcr(J3@jU5osy5$5o@z43rUZC9n z1{+le>E-NF^J>XA_?^=*8H@)1(%7))kVj7{X!|M-MA^5Eya+ME0L$&CJxiyxhOpMZ zl_72em$tIt-!$l!94z|&-kg?#RMs((Vb`4?Q~{-Sn5(yRDbB6=gH_+=E4_p@0TCH| zf1hE<)odVBtFUI(*=8LA)I0?DZ?&64f3uDI-I`W!;hh@I*#Jak3c~hnZ`r8Nc6klE>2Ho;oHd3AD^)Y zx~V0|a;DW-lm`>!GA23!k%zU86%5PPr^sZlgfx;UE-JV7&pBi_oE2XQHzvJ_q-MTU{gS$6`1P%ls@9`b>Ay zwys=|SP+FKUDI&{r}i3I?5W(a{v06+7IstdHZ^xno)LBOT-iZdUI(fu1`|*pDyxwU%sxHDR2W{fXA>Y5QF_@$GFt}Nm{r!=*uJ>=@ap-uM$YPoW30@)n@^XsTB!Ls*4Z

    gljgBPE%t%ikrIUk2b%&FYo%LziLeB zF8t;0p;zFXRa3QM>OB_gteqBR2s9KYA0$a26$&!@B zk(5MsHZttmcQ!CIN?#BOWLQ_{8c;688%~$tfr_w02jo7T#+T!=-EI4rj2)cEPtG%} z3zYJt`e39xq6rl^5t~nbtT6X*n6|!c@|Loh`%|H5;JHeDriqR(Z{b3<%_D-6_6>B$ zUxf2r+%q5K@Z>t2@-VIwcM8bws~C+|cwzzZ=F7t4IHaMpk~y3Jf7 zh4)MEpS9mHhLw7TPLz~#YULsLTcui*v0eswUv4|^W!8xFW=?bzg}{Oir}#=|l0_c;|L$a`Z+0#hk6(yDM7an7EU2w~`^YN@%#$EdITROr-+dQEdJ zk1L^J41+xHG4e)1YhX{@$*lNoMVE-RK+HTX31)cS^@<%a49Zzpj`!|0_M*krppGK- zoi)Sex>mL4Q@U`WQU2RZH|$BFmS(w5^9X|hn*jCTD)`dxhTJBW{8EPWl!uH>*8U$w zlw1V@>69|b9?eJPFn9``21?ZQ=D$c;!^m$Asa(8m3?XJXSn1qzD|1SPvt zB?hgObsZ>Zn31ZkoTs$zqZ}~B^{8C(0{eOi&B~zSjEtx6-Ak?vC_v#nj41`%>_2kx zJ^6|As)823_kj)k3ppt%i+sD$>fQa(CneKOy~2hvU)ZR7ML`k|0Gys&qJw^+zPmy+ zaBsGn`ZJW>UoZT6N1xZz+~lp;Uf<`-<$56lI3kT9H+KJ=^3UxsfzbC4!DwJ*!O!l! z@a2JreOuT2P*k^X8=)MUOOysMByF(!PHy@N3$MTI5LkRqQ|J{bwJl=C#F5MniTjW(=G{O|v5$)caYuW{=8i%{Lx&MXP4tqJ*yh2di#{{(fh%Sf zQTV2I49y7ok?CrBz?n;mXu!0PUhZfYn@bPRtQ1V|hHutdFGEyhN*>D8Mm&X$bz~Zx z9>F;RBcTWr*P7kEd`8SmvMhjfcX8_}O9kPoMT(zZr`ij&@o^~2CJSm7U;;|{93+BC*GDMj)xgbJIlC-JxNEdiFT@W1Kp!e8n^k;5lZLaS zFU}E$DIg}9;G+*wYu6nj_>n9WrrFl+QS>7H@Y$xK!Sq;|frWeJVjC!_E6~*Ai|eO* z2hZKkQDDh3W1LiJM9I9{btZKmqv~z1PYi#-hD_H4VO68oC@_3EX5V51<>67;1gtTr z%QutGPi~6VPe`X?$1BD6;)X~{tj$kn5h1DhV+L8%4=0225D2(OH2 z@#i3Cp*`tgJ1+2cPnO}m=Zu81AefkUdCWXjb>%BFHf2w2V@44x>`6L$cOh+;fii7B zq;Vx?nx8XL$=8CQF|&&=Xs#~hs~#?&WzztC#j&yxH0P%j<@+Z<7(V%I{(-U4{IE24JZB ze%ylJ?~yck8z9@v#soO!0>-x`6mW5RC3nJS7Whn78*Gq=DAt?byX+V9 zw6eXqK*IQA%xex)I}a<5$)qNzV#Bsa4P#<+sbJ5PTRCM=@?t`~_qg6k-|5u0SzVwi z0g74y|G|4?H}%v&of8oUrfo5Xw^6nW#3 z0e>1-BVb*L`S3A3psN8I5Gm>RLc59HtCfqeLRrMs#PluiOCt|CcUrSLf&;MJgNdZ> zKIe#tmkY8pol|A5{*l&4hjbSe;&SwxppO#?hT3#>sU(KGCpOwa$1r35c|=(>R4${1 zkWb)tTs1N&tEDtU6f6NDxVDuV8FFp(#6xuF!yC(p6bZS=AOGArxFMK6<+J(0y%|H< z`DEt#&8y3vj@pv#9&Kj!nLvfXsv`@=>Y2~{^7duz)bK6ItLN)t%Iw=+0gfj-?USaI z1J!Ghswz>dVCo^2?EN?;44GL>wM5-|hF_<=FIA!>PDWfX&3skdA;_@%qb&`07ZOD;$d@f0G!5l~M>UbOe0e>$7hG{-MQ1S+GAfeo0IFuIBr5Pak#8Uq^8- z_G0JXJ{=sb+B*JZP9<4MuSW{^fzL3se40M3^X2bxEAV)tyLv+h@yn$t?<7EIpz2E?7PZtql1?K>O zxP!?3z#W?iNy#%e8M#XhIS@`f1^GbnQ+PsUC_4CbH-9*|cj7682zkyavXjVW77cgJ zqVRrf2Q|{6(m*e^rZt)9!~(^guGX30MFF8IUp+0q(i96_&U%}#-~bzcUK9gT+=#+P_Te-M6G0=^>+YI8pYYCVS;OM0Kq2ggq`Ph{|2bAT>ogm@Zb%PGnB z*h((}E!`bn6t89!BEy$Uz`*k+$veF~IPg5(wwg+hAMLi~>TUyviCmEla|Mg)-lqgZ z8`81huUEUL<((f;YN(d9v|SusCLK$aoDuqw-%$OjRtw3)4o?WcD7s}zyE&)xz3&An zI^o(RlCVW^wviR%Rxjun4Jj<=X4c#fr6f~mWAFKYf67KQ0`k$?qy;e-mQG+oB+oW zoN}Ywxw)pRF;g6@(}qWWRQ&ciy&)$_f~BZ3xv1a#4X0X^%Iwse(x{g4jT$OR?>W3} zHuH<-q|Pmr0+^%XHdJQY#+yF1b5WP1{d3>%QHY;TA6tr!KygP@-1=(z!WlSJdIW#v z2KSN4n7Jih<-%pvPfg+L6wc(~&JymS3LZ@lETG1D&PXtZVs6KPb$8FN*1|#-1wTR~ z@|OVQ7m`qI67~X4zVBcyB)TZ(7cxtJB*Z#N<|covH?Jn<^WbRFqOR~*<*T|%{s_Kg z1wDsarh!s26D%$H(?#*+SqPXQYm`Yu&qh=-@j$bI{V-RFTKx-xa`|09>fFz>Anjnx zSgwKh1OxA}5^S88Y$eGoR0&&C!`6&b$o1?<^xEg}`3?vpW!S~gWgn2Wb^}X?hPJ2d zx2U=xN*J%)Uj_5_C0*-2xQY$#uip&&Z7V=pEQ5IuMm2@QE2l%faM;14a9&Cp zUQUM3kiCicSqN|9*&+M#A&T~KWf*Ve3v)#70#0%HXhj54a(wCQ_;+CPKxtD&WjJS% zf;R>d@=~9BM_j}QZu&^DN{LI3x|X8%xJMq_dO8M~7yS`y);e^o0ig7Y_Q7;yFTLEg zweq}pqozwrOiRy2R;1TnZ}WY_wWa1d4-}@J#&}uv&84YQ5#<-*zLplj;q>ArTthKg z{g*dCscEA!Li>mN(ZeGJgJBv#rpvezp*jkctQvbE&#>VzS(^$lpft^wiM85XSTO3$ zLzADeK`K!-sEk0#f1xLf#5t?wr9_mWxd6FXYUTAyZ78GCrAd9Xjd*A;t#smv0svu%w;`bIu4al*3maOwDjtLjB_9Hq7fRFvFm(DGTOXYf7X&l{ zcov#JY{VSy#JgR~>V9PdeS3lA>#a+;Fq-uEyMNPcLN%{I-VoGn3ftwZ=R=5gDYTCr z#t=!iK+%q%lL%Wcy~79qz+-ck_tug9=iRuEv=C+jxle~f#o>9>F6 z`jYL+8)0a9BGrM+@hbj7`3*9UhZ!A!5Dtz`2M!MWA26NmA@hHbXvY6HiProVkp6EB zU8RrWkH0|jr)z|3{f7LnRSmJe)`7YRnHHa@fP=Z>c#QoCvERC~ede zv2N7Kn*~QzY1cMVH_&5O>#UXE{t9vs_4S^w*S51e%bUKK=*Z5_wi9?bz;9{auEl2DT8;-RPthhbIic??zAxT043LsOrgmU2?7=MrOSrH_>rW@|7zk;tx zxFz_BSl+03%AH|Y93iM3T&tqgljN_^kGm)${R5nVi(hl#zW6ndAFT94110K{8@(N2 zt;`Qslw#A+h*aDZV_E*l2?CcK0FO&o1R8C6tTr`!%D0r%Xj(?IpQb3xH9~vnf8rB4 zOrS;7?8)Cy?UpB8aqQ@HD>uKg?V_TjnZ`!2(3SSO>6%fvxoL~Ft}vP=16VHC{f7q^ zDyzY=KXg!zYhy8suWJzr;jruv-sBuM9Bk z08epT3IK0!>eGyX>nT{=p*V;w85@o`T#UWG>!b6K^k);D6SGF;6}mq5-_&w+%RN8` zi60KgKC$}G`NEHU|I7h?C7A~fPQi71Ojc0g% zn+{GhUV-pD8M1n^elik7MK|4R6^)z_}<--KLODkJYLbrqQ2@qU3*ZfX_jUC+0tuYg^)%+I&yT`?~eYVLi@x-LP73UC9*DB~r+%v3-kcO0QW(sDMf>DH^yccOqZH zpv7}P1g8Yog+Vpv&dA~Eojv8khw*ur`D0VL@|Ub(^mdb3KfbgMJ+p`j<}BlrTRJ); zC_-f8%t*RhYM$m5rGR(&!twwTG7XZ)u2sDM4el`TwYp%S)FGT%(n-v%Pf+)^fT9v` z+(<*t=IE}mSv#uB2YJJ2HV9^AuO(&cMBdqtMM+4dq2xl`nf!B-Ubf#ZP&X z18_kqLTfVXp$Rja%HZVDnmwK=$7fb)>si+>8j;7!=G}3{hV`0it~F}`8B&uW#uybP zJ$x0BQhLBcy?c+%g~b?s+3lTgigx&PPTeix*lH4&fVGHOHL(Ze{m;xq(u}XJxLeFC zkOw#9PiLLBmYnv5a=7L>dcXYB>fWS1j)i$tj-dGF#|tf!I)D#{V^u?Sw8(y6Dwa&i z>X1z|zWZ!$<(Dg)9(%YI?Qlg_R8jcj0Al4sJh{4$7Cy+*|(=n=x|FD ztCH%7~?A0>zwKx;k%t0-oTO2B~6QmH|&D4|jwNkDC%wDe;CRzjK z*S&ma7Xy|_QKQI%HGH}1%p2NL(`fk^CcF(I`3?!74m27ZyF^P-SIIkv-9OO;B2=N= zJSvJ;Ww4mPP@{9ku^e%>Fq6k6RaRFoPRgX>#a;Ud*#N%%-cw@}D67U(Y z^z%8VqRVePlHB#jHVoB`u5)QaTH~KAxh~}JGET|cyyGVqUY}+vGl&8a(yeAbMO-|c0J7cv~ z_P~-PZ@;{;co9OM7U`hF!m53LgTb&a74}T8xTORRzlQOLJv51jqdH zBk=vGO$-!+VJ z&I8>f7$Z2AvubtEJ1asw;WFI28_$o=j1rvUf~;24*cq=gr-&17;SWcdvSTE83^3~J z!5Vqs9HU=53XZQ?#q?YmVQ>H1uW;m=Z^&Rlzh^dPlS zuL6T5AuEK3weJt;D*#o4EuGa&zi4s|9o6nL+v3{N(gq2eCOkywTMyk8A81}`(I^Lo zmYcy!!qi|!YORv1N`YkVoZPyxDY?tnh0JpoPoH4J9CK)H{g~$IZPUhPsB0naGqpZZ z+b)+Ee;j~;{;SQpZ(I_DJ(>uQ7F=)cZsj1QbV*6r0<-Z4ni!P*th9dn(`C7XJJKFh z{$`1tNG!VBd57cj<7hnQI`!)+ET3+Hrab%o>Pd^rPg*6ek*Gg4`K&+d=|B0R=DO`T z!J4CrCa7O0VV9ggd5S{HUM6&kU7cz5S>&9FY4LK0hzuU6y9(2nsdg_gw!p)3&f9LB z8h&IlCCY(OR%HcS+|55eA}K$ustLV(9OU)H*~TMDGz5QPcMdZI)sGFqP$*C={3);^ABtm~Y8n2lad(9@zZ)mp zk;1;@;C>~Dk9hbVbFqUXlo0D481>K<1MV-N4y4-KO7z6mrpXoM{!6~dgr^uoaFHF* zoGz#A)Ze~!*SWl%)k2Y9=8$WeHB9zp*bQ$G(d*k`Lv-f_%jFWk4+8s+zn>ynCBC_z z(xQWAQC52POlAiJu7OfL8a7aG$=#epRdukCY<&702T~w5gR{QU3RsU`(}J%&CV$L) zoqu==QYY)!YJN>Fzw+eOTdE!gd0Fas$$yH`s{*Me0c~&?_sefotnQW%luTc0vyuuw zsrbw(3eD@_h)boX&Vo-BklP33VN8>(9}viTvEZojrHG&4b~M`Xs1RhaL*dT?$!_P^ zGmk^Ln1DwG^1tu5Ia1wx949zS-=>Nl&Kk`$y90IA}Q~Tw{A~SaVa+spCktNW}=pPdcZaq$0Oq8Nhr^0X1Yz6 zz`B;(1nZ>cO~eR(1;W8E8N*5y{ARZ(C&pu}46~vS__p9$Zk+WZng{xITZ#&5n&W5M z0Afd;p>kcK3PrhjuJ0%Mkk_WL#es6&=u{NHZcM-Qb^d|!^!Gxah*}-_GK!!+W^~ZPzUYB{>T|8Nvz%H? zp6tB4Zx32>anG$_g^f+Ja`Oe`w{B9RvdKM#4z>AJs}au$dpYmc>tQT*4$3j5V7K{d z6c5xK9y|SVYkkWel%M4HWPQI01BYDr8ZeAo@?AaP>^dxdhSYR4nj+iA_pYF*B@nsA9CA--=lbpliQ&#opDx`X?`dN{TZ0Svut~do4#ef#F>?_;;zaq_8Cq%-F2MRCrgpt1lc$GE-~EjI zO5aiRm|dnz4a%U$2wMB)rG*oih4xXJ@XW>r6+^n-YqTNwMpD->`BQpXtD{B>;vg7V zIC78TAv*SiZF6Pcm&Gd}($p()=5}oOc4J>?ZR|I}W}|bbs@uljPq?zR22%8H70_0K zwl&S==~Ml5<@^AvYCWWoMb`~g{S_2J$~=SCbNbDVg(Gv%H%G0PRQOu9+DqQP3cTl4 zAWC3-bG|FKkR3O2JE2YgJ19$P2$-{&(@bQd>bvl}X3jm@N}B$;$Aga_(6dz!f}CkW zPw5$P9mAA%;O5cZm^3=0xubAMeDKD}?^A{e@ZVDX=B*^$L3|3Q?5Aa}JG#5@&-fiu zDh2_U=a}LR7!=?6rKF#1ILx){Cp+E=gpeB~k=(oMn6&9|kmu%kXZNNZ{Np zn%DX{VThV9`k~dM{-tpom5HcD!756>`PiekTL!HddlTpNEJfH^sG#N5)8yV5SD{NL znJ^$L{wAcTPk)-d1LFkZ)x*(&rVqKNqVB-*3yn9)g`uo7e+{GQBcU_8O$ZE|G^Y+# zc)Z8KqEH>+sUbEf_QZK506*Wui?U|z*8cX&`LU@DQ`D8AQ{I)zxHO5Uz31{zN?Jd{ z|2bJmKeS0)L>taDio!HnR76O0m&VdcZf+9hxo9|XKf)8&D?79^H?++&l$TZf%cUiq ze#Zrd(GR?!x*-oIxwnx)>Urhpbc?KsC6o}@pTkd2_avT8VDpEU1ux6|1T&(6ifH^e zilQu;Ir8dqM&VMk%GQ&ZdV#V&gq4Ry;ZU{?``w>PMvE|4Cd200EmI?%%evruD7-LB zeQc-Rt3{*?=J?zbx2pa?>83e?U4D2^C}g9xp1 z0P>+nQX;~+d6=5pxN>nosVsryP*g`CDIyIOB9y@qsEF9)#CLiU09Y1VFQY!g9poQG!s6C2<}&I$5ydx)GKL0& z&yaotF@w(vJx-WUQ!Snw>=8dd6Lt)4srvhiw9#AFhN2_QO_-fzH_n4yBJ-QjaYP(O zE7*aQs;DW5IdBhA2;nU6M@^R7>1n?u7b#|Y zj)N5K#7<7#65XhuQY-`!SCp+GsiE1F`|xs#y>hiz>5tpeiJClnX(a()o&z%ZK-KTo zZ!wGJDvWHtWe*(2YV{&#IApOSAL?dn0?H`PO{kFjX7kFJ(cQQ$tBn6+33 z$F|&yn*}xTWF9jG_KT4Z5{IgEr%_aYb?l==Ly-r?olg>}B6rfm7`BVtb^OE?*8KfF Zy Date: Mon, 11 Feb 2013 18:44:22 +0400 Subject: [PATCH 13/39] 8007536: Incorrect copyright header in JDP files Copyright header in JDP files missed the "classpath exception" rule. Reviewed-by: mikael --- .../sun/management/jdp/JdpBroadcaster.java | 6 +++-- .../sun/management/jdp/JdpController.java | 6 +++-- .../sun/management/jdp/JdpException.java | 6 +++-- .../sun/management/jdp/JdpGenericPacket.java | 6 +++-- .../sun/management/jdp/JdpJmxPacket.java | 6 +++-- .../classes/sun/management/jdp/JdpPacket.java | 7 +++--- .../sun/management/jdp/JdpPacketReader.java | 6 +++-- .../sun/management/jdp/JdpPacketWriter.java | 6 +++-- .../sun/management/jdp/package-info.java | 24 +++++++++++++++++++ 9 files changed, 56 insertions(+), 17 deletions(-) diff --git a/jdk/src/share/classes/sun/management/jdp/JdpBroadcaster.java b/jdk/src/share/classes/sun/management/jdp/JdpBroadcaster.java index df5f23458e5..b1766e6f7f6 100644 --- a/jdk/src/share/classes/sun/management/jdp/JdpBroadcaster.java +++ b/jdk/src/share/classes/sun/management/jdp/JdpBroadcaster.java @@ -1,10 +1,12 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/jdk/src/share/classes/sun/management/jdp/JdpController.java b/jdk/src/share/classes/sun/management/jdp/JdpController.java index d8d0ed46930..3083c972cac 100644 --- a/jdk/src/share/classes/sun/management/jdp/JdpController.java +++ b/jdk/src/share/classes/sun/management/jdp/JdpController.java @@ -1,10 +1,12 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/jdk/src/share/classes/sun/management/jdp/JdpException.java b/jdk/src/share/classes/sun/management/jdp/JdpException.java index 03404223e94..7c312d45db7 100644 --- a/jdk/src/share/classes/sun/management/jdp/JdpException.java +++ b/jdk/src/share/classes/sun/management/jdp/JdpException.java @@ -1,10 +1,12 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/jdk/src/share/classes/sun/management/jdp/JdpGenericPacket.java b/jdk/src/share/classes/sun/management/jdp/JdpGenericPacket.java index 8e88b148265..74b8a589568 100644 --- a/jdk/src/share/classes/sun/management/jdp/JdpGenericPacket.java +++ b/jdk/src/share/classes/sun/management/jdp/JdpGenericPacket.java @@ -1,10 +1,12 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/jdk/src/share/classes/sun/management/jdp/JdpJmxPacket.java b/jdk/src/share/classes/sun/management/jdp/JdpJmxPacket.java index 7d5ccc2f892..60aea2bd40f 100644 --- a/jdk/src/share/classes/sun/management/jdp/JdpJmxPacket.java +++ b/jdk/src/share/classes/sun/management/jdp/JdpJmxPacket.java @@ -1,10 +1,12 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/jdk/src/share/classes/sun/management/jdp/JdpPacket.java b/jdk/src/share/classes/sun/management/jdp/JdpPacket.java index ba0ec4f97ac..9260112a52f 100644 --- a/jdk/src/share/classes/sun/management/jdp/JdpPacket.java +++ b/jdk/src/share/classes/sun/management/jdp/JdpPacket.java @@ -1,10 +1,12 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or @@ -20,7 +22,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package sun.management.jdp; import java.io.IOException; diff --git a/jdk/src/share/classes/sun/management/jdp/JdpPacketReader.java b/jdk/src/share/classes/sun/management/jdp/JdpPacketReader.java index 9f3957ab5ce..f69c07d6c0c 100644 --- a/jdk/src/share/classes/sun/management/jdp/JdpPacketReader.java +++ b/jdk/src/share/classes/sun/management/jdp/JdpPacketReader.java @@ -1,10 +1,12 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/jdk/src/share/classes/sun/management/jdp/JdpPacketWriter.java b/jdk/src/share/classes/sun/management/jdp/JdpPacketWriter.java index 7ebd002608c..2af2fdc0100 100644 --- a/jdk/src/share/classes/sun/management/jdp/JdpPacketWriter.java +++ b/jdk/src/share/classes/sun/management/jdp/JdpPacketWriter.java @@ -1,10 +1,12 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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. + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or diff --git a/jdk/src/share/classes/sun/management/jdp/package-info.java b/jdk/src/share/classes/sun/management/jdp/package-info.java index e21e461214f..4a0d169efa7 100644 --- a/jdk/src/share/classes/sun/management/jdp/package-info.java +++ b/jdk/src/share/classes/sun/management/jdp/package-info.java @@ -1,3 +1,27 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ /** * Summary * ------- From 249b55b573809725df1c523da7091c06d75333b5 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Mon, 11 Feb 2013 10:07:01 -0800 Subject: [PATCH 14/39] 8007420: add test for 6805864 to com/sun/jdi, add test for 7182152 to java/lang/instrument Reviewed-by: coleenp, sspitsyn --- jdk/test/com/sun/jdi/RedefineAbstractClass.sh | 153 ++++++++++++++++ .../RedefineSubclassWithTwoInterfaces.sh | 167 ++++++++++++++++++ ...edefineSubclassWithTwoInterfacesAgent.java | 44 +++++ .../RedefineSubclassWithTwoInterfacesApp.java | 80 +++++++++ ...RedefineSubclassWithTwoInterfacesImpl.java | 34 ++++ ...defineSubclassWithTwoInterfacesImpl_1.java | 34 ++++ ...edefineSubclassWithTwoInterfacesIntf1.java | 28 +++ ...edefineSubclassWithTwoInterfacesIntf2.java | 28 +++ ...defineSubclassWithTwoInterfacesRemote.java | 47 +++++ ...defineSubclassWithTwoInterfacesTarget.java | 30 ++++ ...fineSubclassWithTwoInterfacesTarget_1.java | 30 ++++ 11 files changed, 675 insertions(+) create mode 100644 jdk/test/com/sun/jdi/RedefineAbstractClass.sh create mode 100644 jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh create mode 100644 jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesAgent.java create mode 100644 jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesApp.java create mode 100644 jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesImpl.java create mode 100644 jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesImpl_1.java create mode 100644 jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesIntf1.java create mode 100644 jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesIntf2.java create mode 100644 jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesRemote.java create mode 100644 jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesTarget.java create mode 100644 jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesTarget_1.java diff --git a/jdk/test/com/sun/jdi/RedefineAbstractClass.sh b/jdk/test/com/sun/jdi/RedefineAbstractClass.sh new file mode 100644 index 00000000000..9e6e484dc04 --- /dev/null +++ b/jdk/test/com/sun/jdi/RedefineAbstractClass.sh @@ -0,0 +1,153 @@ +#!/bin/sh + +# +# Copyright (c) 2009, 2013, 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 6805864 +# @summary Redefine an abstract class that is called via a concrete +# class and via two interface objects and verify that the right +# methods are called. +# @author Daniel D. Daugherty +# +# @run shell RedefineAbstractClass.sh + +compileOptions=-g + +# Uncomment this to see the JDI trace +#jdbOptions=-dbgtrace + +createJavaFile() +{ + cat < $1.java.1 + +public class $1 { + public static void main(String[] args) { + System.out.println("This is RedefineAbstractClass"); + + MyConcreteClass foo = new MyConcreteClass(); + // do the work once before redefine + foo.doWork(); + + System.out.println("stop here for redefine"); // @1 breakpoint + + // do the work again after redefine + foo.doWork(); + + System.out.println("stop here to check results"); // @2 breakpoint + } +} + +interface MyInterface1 { + public boolean checkFunc(); + public boolean isMyInterface1(); +} + +interface MyInterface2 { + public boolean checkFunc(); + public boolean isMyInterface2(); +} + +abstract class MyAbstractClass implements MyInterface1, MyInterface2 { + static int counter = 0; + public boolean checkFunc() { + counter++; + System.out.println("MyAbstractClass.checkFunc() called."); + // @1 uncomment System.out.println("This is call " + counter + " to checkFunc"); + return true; + } + public boolean isMyInterface1() { + System.out.println("MyAbstractClass.isMyInterface1() called."); + return true; + } + public boolean isMyInterface2() { + System.out.println("MyAbstractClass.isMyInterface2() called."); + return true; + } +} + +class MyConcreteClass extends MyAbstractClass { + public void doWork() { + // checkFunc() is called via invokevirtual here; MyConcreteClass + // inherits via MyAbstractClass + System.out.println("In doWork() calling checkFunc(): " + checkFunc()); + + MyInterface1 if1 = (MyInterface1) this; + // checkFunc() is called via invokeinterface here; this call will + // use the first itable entry + System.out.println("In doWork() calling if1.checkFunc(): " + if1.checkFunc()); + + MyInterface2 if2 = (MyInterface2) this; + // checkFunc() is called via invokeinterface here; this call will + // use the second itable entry + System.out.println("In doWork() calling if2.checkFunc(): " + if2.checkFunc()); + } +} + +EOF +} + +# This is called to feed cmds to jdb. +dojdbCmds() +{ + setBkpts @1 + setBkpts @2 + runToBkpt @1 + # modified version of redefineClass function + vers=2 + abs_class=MyAbstractClass + cmd redefine $pkgDot$abs_class $tmpFileDir/vers$vers/$abs_class.class + cp $tmpFileDir/$classname.java.$vers \ + $tmpFileDir/$classname.java + # end modified version of redefineClass function + + # this will continue to the second breakpoint + cmd cont +} + + +mysetup() +{ + if [ -z "$TESTSRC" ] ; then + TESTSRC=. + fi + + for ii in . $TESTSRC $TESTSRC/.. ; do + if [ -r "$ii/ShellScaffold.sh" ] ; then + . $ii/ShellScaffold.sh + break + fi + done +} + +# You could replace this next line with the contents +# of ShellScaffold.sh and this script will run just the same. +mysetup + +runit + +debuggeeFailIfNotPresent 'This is call 4 to checkFunc' +debuggeeFailIfNotPresent 'This is call 5 to checkFunc' +debuggeeFailIfNotPresent 'This is call 6 to checkFunc' +pass diff --git a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh new file mode 100644 index 00000000000..8e1c81f3c17 --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh @@ -0,0 +1,167 @@ +# +# Copyright (c) 2013, 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 7182152 +# @summary Redefine a subclass that implements two interfaces and +# verify that the right methods are called. +# @author Daniel D. Daugherty +# +# @run shell MakeJAR3.sh RedefineSubclassWithTwoInterfacesAgent 'Can-Redefine-Classes: true' +# @run build RedefineSubclassWithTwoInterfacesApp +# @run shell RedefineSubclassWithTwoInterfaces.sh +# + +if [ "${TESTJAVA}" = "" ] +then + echo "TESTJAVA not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${TESTSRC}" = "" ] +then + echo "TESTSRC not set. Test cannot execute. Failed." + exit 1 +fi + +if [ "${TESTCLASSES}" = "" ] +then + echo "TESTCLASSES not set. Test cannot execute. Failed." + exit 1 +fi + +JAVAC="${TESTJAVA}"/bin/javac +JAVA="${TESTJAVA}"/bin/java + +echo "INFO: building the replacement classes." + +cp "${TESTSRC}"/RedefineSubclassWithTwoInterfacesTarget_1.java \ + RedefineSubclassWithTwoInterfacesTarget.java +cp "${TESTSRC}"/RedefineSubclassWithTwoInterfacesImpl_1.java \ + RedefineSubclassWithTwoInterfacesImpl.java +"${JAVAC}" -cp "${TESTCLASSES}" -d . \ + RedefineSubclassWithTwoInterfacesTarget.java \ + RedefineSubclassWithTwoInterfacesImpl.java +status="$?" +if [ "$status" != 0 ]; then + echo "FAIL: compile of *_1.java files failed." + exit "$status" +fi + +mv RedefineSubclassWithTwoInterfacesTarget.java \ + RedefineSubclassWithTwoInterfacesTarget_1.java +mv RedefineSubclassWithTwoInterfacesTarget.class \ + RedefineSubclassWithTwoInterfacesTarget_1.class +mv RedefineSubclassWithTwoInterfacesImpl.java \ + RedefineSubclassWithTwoInterfacesImpl_1.java +mv RedefineSubclassWithTwoInterfacesImpl.class \ + RedefineSubclassWithTwoInterfacesImpl_1.class + +echo "INFO: launching RedefineSubclassWithTwoInterfacesApp" + +# TraceRedefineClasses options: +# +# 0x00000001 | 1 - name each target class before loading, after +# loading and after redefinition is completed +# 0x00000002 | 2 - print info if parsing, linking or +# verification throws an exception +# 0x00000004 | 4 - print timer info for the VM operation +# 0x00001000 | 4096 - detect calls to obsolete methods +# 0x00002000 | 8192 - fail a guarantee() in addition to detection +# 0x00004000 | 16384 - detect old/obsolete methods in metadata +# 0x00100000 | 1048576 - impl details: vtable updates +# 0x00200000 | 2097152 - impl details: itable updates +# +# 1+2+4+4096+8192+16384+1048576+2097152 == 3174407 + +"${JAVA}" ${TESTVMOPTS} \ + -XX:TraceRedefineClasses=3174407 \ + -javaagent:RedefineSubclassWithTwoInterfacesAgent.jar \ + -classpath "${TESTCLASSES}" \ + RedefineSubclassWithTwoInterfacesApp > output.log 2>&1 +status="$?" + +echo "INFO: " +cat output.log +echo "INFO: " + +if [ "$status" != 0 ]; then + echo "FAIL: RedefineSubclassWithTwoInterfacesApp failed." + exit "$status" +fi + +# When this bug manifests, RedefineClasses() will fail to update +# one of the itable entries to refer to the new method. The log +# will include the following line when the bug occurs: +# +# guarantee(false) failed: OLD and/or OBSOLETE method(s) found +# +# If this guarantee happens, the test should fail in the status +# check above, but just in case it doesn't, we check for "guarantee". +# + +FAIL_MESG="guarantee" +grep "$FAIL_MESG" output.log +status=$? +if [ "$status" = 0 ]; then + echo "FAIL: found '$FAIL_MESG' in the test output." + result=1 +else + echo "INFO: did NOT find '$FAIL_MESG' in the test output." + # be optimistic here + result=0 +fi + +PASS1_MESG="before any redefines" +cnt=`grep "$PASS1_MESG" output.log | grep 'version-0' | wc -l | sed 's/^ *//'` +case "$cnt" in +2) + echo "INFO: found 2 version-0 '$PASS1_MESG' mesgs." + ;; +*) + echo "FAIL: did NOT find 2 version-0 '$PASS1_MESG' mesgs." + echo "INFO: grep '$PASS1_MESG' output:" + grep "$PASS1_MESG" output.log + result=1 + ;; +esac + +PASS2_MESG="after redefine" +cnt=`grep "$PASS2_MESG" output.log | grep 'version-1' | wc -l | sed 's/^ *//'` +case "$cnt" in +2) + echo "INFO: found 2 version-1 '$PASS2_MESG' mesgs." + ;; +*) + echo "FAIL: did NOT find 2 version-1 '$PASS2_MESG' mesgs." + echo "INFO: grep '$PASS2_MESG' output:" + grep "$PASS2_MESG" output.log + result=1 + ;; +esac + +if [ "$result" = 0 ]; then + echo "PASS: test passed both positive and negative output checks." +fi + +exit $result diff --git a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesAgent.java b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesAgent.java new file mode 100644 index 00000000000..abd9931d88e --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesAgent.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013, 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.lang.instrument.Instrumentation; + +public class RedefineSubclassWithTwoInterfacesAgent { + private static Instrumentation instrumentation; + + private RedefineSubclassWithTwoInterfacesAgent() { + } + + public static void premain(String agentArgs, Instrumentation inst) { + System.out.println("Hello from " + + "RedefineSubclassWithTwoInterfacesAgent!"); + System.out.println("isRedefineClassesSupported()=" + + inst.isRedefineClassesSupported()); + + instrumentation = inst; + } + + public static Instrumentation getInstrumentation() { + return instrumentation; + } +} diff --git a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesApp.java b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesApp.java new file mode 100644 index 00000000000..bb62058bfde --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesApp.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, 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.*; +import java.lang.instrument.*; + +public class RedefineSubclassWithTwoInterfacesApp { + public static void main(String args[]) throws Exception { + System.out.println("Hello from RedefineSubclassWithTwoInterfacesApp!"); + + new RedefineSubclassWithTwoInterfacesApp().doTest(); + + System.exit(0); + } + + private void doTest() throws Exception { + RedefineSubclassWithTwoInterfacesImpl impl + = new RedefineSubclassWithTwoInterfacesImpl(); + RedefineSubclassWithTwoInterfacesRemote remote + = new RedefineSubclassWithTwoInterfacesRemote(impl, impl); + String mesg; + + // make echo() calls before any redefinitions: + mesg = remote.echo1("test message #1.1"); + System.out.println("RedefineSubclassWithTwoInterfacesApp: echo1 mesg='" + + mesg + "' before any redefines"); + mesg = remote.echo2("test message #2.1"); + System.out.println("RedefineSubclassWithTwoInterfacesApp: echo2 mesg='" + + mesg + "' before any redefines"); + + + // redefining RedefineSubclassWithTwoInterfacesImpl before + // RedefineSubclassWithTwoInterfacesTarget fails: + do_redefine("RedefineSubclassWithTwoInterfacesImpl", 1); + do_redefine("RedefineSubclassWithTwoInterfacesTarget", 1); + + mesg = remote.echo1("test message #1.2"); + System.out.println("RedefineSubclassWithTwoInterfacesApp: echo1 mesg='" + + mesg + "' after redefine"); + mesg = remote.echo2("test message #2.2"); + System.out.println("RedefineSubclassWithTwoInterfacesApp: echo2 mesg='" + + mesg + "' after redefine"); + } + + private static void do_redefine(String className, int counter) + throws Exception { + File f = new File(className + "_" + counter + ".class"); + System.out.println("Reading test class from " + f); + InputStream redefineStream = new FileInputStream(f); + + byte[] redefineBuffer + = NamedBuffer.loadBufferFromStream(redefineStream); + + ClassDefinition redefineParamBlock = new ClassDefinition( + Class.forName(className), redefineBuffer); + + RedefineSubclassWithTwoInterfacesAgent.getInstrumentation(). + redefineClasses(new ClassDefinition[] {redefineParamBlock}); + } +} diff --git a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesImpl.java b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesImpl.java new file mode 100644 index 00000000000..f42e79fc19a --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesImpl.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013, 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. + */ + +// Reproducing this bug only requires an EMCP version of the +// RedefineSubclassWithTwoInterfacesImpl class so +// RedefineSubclassWithTwoInterfacesImpl.java and +// RedefineSubclassWithTwoInterfacesImpl_1.java are identical. +public class RedefineSubclassWithTwoInterfacesImpl + extends RedefineSubclassWithTwoInterfacesTarget + implements RedefineSubclassWithTwoInterfacesIntf1, + RedefineSubclassWithTwoInterfacesIntf2 { + // This class is acting in the role of: + // wlstest.unit.diagnostics.common.apps.echoejb.EchoBean4_nh7k_Impl +} diff --git a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesImpl_1.java b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesImpl_1.java new file mode 100644 index 00000000000..f42e79fc19a --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesImpl_1.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013, 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. + */ + +// Reproducing this bug only requires an EMCP version of the +// RedefineSubclassWithTwoInterfacesImpl class so +// RedefineSubclassWithTwoInterfacesImpl.java and +// RedefineSubclassWithTwoInterfacesImpl_1.java are identical. +public class RedefineSubclassWithTwoInterfacesImpl + extends RedefineSubclassWithTwoInterfacesTarget + implements RedefineSubclassWithTwoInterfacesIntf1, + RedefineSubclassWithTwoInterfacesIntf2 { + // This class is acting in the role of: + // wlstest.unit.diagnostics.common.apps.echoejb.EchoBean4_nh7k_Impl +} diff --git a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesIntf1.java b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesIntf1.java new file mode 100644 index 00000000000..b6e2542c9d8 --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesIntf1.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013, 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. + */ + +public interface RedefineSubclassWithTwoInterfacesIntf1 { + // This interface is acting in the role of: + // wlstest.unit.diagnostics.common.apps.echoejb.EchoBean4_nh7k_Intf + String echo(String s); +} diff --git a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesIntf2.java b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesIntf2.java new file mode 100644 index 00000000000..66fe1624f2c --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesIntf2.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013, 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. + */ + +public interface RedefineSubclassWithTwoInterfacesIntf2 { + // This interface is acting in the role of: + // weblogic.ejb.container.interfaces.WLEnterpriseBean + String echo(String s); +} diff --git a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesRemote.java b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesRemote.java new file mode 100644 index 00000000000..e50e049413e --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesRemote.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013, 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. + */ + +public class RedefineSubclassWithTwoInterfacesRemote { + // This class is acting in the role of: + // wlstest.unit.diagnostics.common.apps.echoejb.EchoBean4_nh7k_EchoRemoteImpl + // since it is calling the echo() method via an interface. + private RedefineSubclassWithTwoInterfacesIntf1 intf1; + private RedefineSubclassWithTwoInterfacesIntf2 intf2; + + RedefineSubclassWithTwoInterfacesRemote( + RedefineSubclassWithTwoInterfacesIntf1 intf1, + RedefineSubclassWithTwoInterfacesIntf2 intf2) { + this.intf1 = intf1; + this.intf2 = intf2; + } + + // There is actually a bit more logic in the call stack from + // EchoBean4_nh7k_EchoRemoteImpl.echo() to EchoBean4_nh7k_Intf.echo() + public String echo1(String s) { + return "intf1<" + intf1.echo(s) + ">"; + } + + public String echo2(String s) { + return "intf2<" + intf2.echo(s) + ">"; + } +} diff --git a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesTarget.java b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesTarget.java new file mode 100644 index 00000000000..55c1d58ee59 --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesTarget.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013, 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. + */ + +public class RedefineSubclassWithTwoInterfacesTarget { + // This class is acting in the role of: + // wlstest.unit.diagnostics.common.apps.echoejb.EchoBean4 + public String echo(String s) { + return "echo: (version-0) <" + s + ">"; + } +} diff --git a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesTarget_1.java b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesTarget_1.java new file mode 100644 index 00000000000..429d0fe906f --- /dev/null +++ b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfacesTarget_1.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2013, 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. + */ + +public class RedefineSubclassWithTwoInterfacesTarget { + // This class is acting in the role of: + // wlstest.unit.diagnostics.common.apps.echoejb.EchoBean4 + public String echo(String s) { + return "echo: (version-1) <" + s + ">"; + } +} From b74073c0db5f5cb61f6b80e8ca168909bd5e09f5 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Mon, 11 Feb 2013 20:16:18 +0000 Subject: [PATCH 15/39] 8007405: Update java.lang.reflect API to replace SYNTHESIZED with MANDATED Reviewed-by: darcy --- .../classes/java/lang/reflect/Executable.java | 4 ++ .../classes/java/lang/reflect/Modifier.java | 6 +-- .../classes/java/lang/reflect/Parameter.java | 52 +++++++++++++------ 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/jdk/src/share/classes/java/lang/reflect/Executable.java b/jdk/src/share/classes/java/lang/reflect/Executable.java index ad1a5808632..4c785e3e87f 100644 --- a/jdk/src/share/classes/java/lang/reflect/Executable.java +++ b/jdk/src/share/classes/java/lang/reflect/Executable.java @@ -278,6 +278,10 @@ public abstract class Executable extends AccessibleObject * this object. Returns an array of length 0 if the executable * has no parameters. * + * The parameters of the underlying executable do not necessarily + * have unique names, or names that are legal identifiers in the + * Java programming language (JLS 3.8). + * * @return an array of {@code Parameter} objects representing all * the parameters to the executable this object represents */ diff --git a/jdk/src/share/classes/java/lang/reflect/Modifier.java b/jdk/src/share/classes/java/lang/reflect/Modifier.java index 24cebe29f9f..8c2b2cc5f5e 100644 --- a/jdk/src/share/classes/java/lang/reflect/Modifier.java +++ b/jdk/src/share/classes/java/lang/reflect/Modifier.java @@ -342,13 +342,13 @@ class Modifier { static final int SYNTHETIC = 0x00001000; static final int ANNOTATION = 0x00002000; static final int ENUM = 0x00004000; - static final int SYNTHESIZED = 0x00010000; + static final int MANDATED = 0x00008000; static boolean isSynthetic(int mod) { return (mod & SYNTHETIC) != 0; } - static boolean isSynthesized(int mod) { - return (mod & SYNTHESIZED) != 0; + static boolean isMandated(int mod) { + return (mod & MANDATED) != 0; } /** diff --git a/jdk/src/share/classes/java/lang/reflect/Parameter.java b/jdk/src/share/classes/java/lang/reflect/Parameter.java index 04bc274ca9f..3ecd7c674ea 100644 --- a/jdk/src/share/classes/java/lang/reflect/Parameter.java +++ b/jdk/src/share/classes/java/lang/reflect/Parameter.java @@ -44,7 +44,7 @@ public final class Parameter implements AnnotatedElement { private final String name; private final int modifiers; private final Executable executable; - private int index; + private final int index; /** * Package-private constructor for {@code Parameter}. @@ -95,9 +95,14 @@ public final class Parameter implements AnnotatedElement { } /** - * Returns a string representation of the parameter's modifiers, - * its attributes, its type, its name, and a trailing ... if it is - * a variadic parameter. + * Returns a string describing this parameter. The format is the + * modifiers for the parameter, if any, in canonical order as + * recommended by The Java™ Language + * Specification, followed by the fully- qualified type of + * the parameter (excluding the last [] if the parameter is + * variable arity), followed by "..." if the parameter is variable + * arity, followed by a space, followed by the name of the + * parameter. * * @return A string representation of the parameter and associated * information. @@ -118,7 +123,7 @@ public final class Parameter implements AnnotatedElement { sb.append(typename); sb.append(" "); - sb.append(name); + sb.append(getName()); return sb.toString(); } @@ -143,11 +148,23 @@ public final class Parameter implements AnnotatedElement { } /** - * Returns the name of the parameter represented by this - * {@code Parameter} object. + * Returns the name of the parameter. The names of the parameters + * of a single executable must all the be distinct. When names + * from the originating source are available, they are returned. + * Otherwise, an implementation of this method is free to create a + * name of this parameter, subject to the unquiness requirments. */ public String getName() { - return name; + // As per the spec, if a parameter has no name, return argX, + // where x is the index. + // + // Note: spec updates now outlaw empty strings as parameter + // names. The .equals("") is for compatibility with current + // JVM behavior. It may be removed at some point. + if(name == null || name.equals("")) + return "arg" + index; + else + return name; } /** @@ -190,20 +207,21 @@ public final class Parameter implements AnnotatedElement { private transient volatile Class parameterClassCache = null; /** - * Returns {@code true} if this parameter is a synthesized - * construct; returns {@code false} otherwise. + * Returns {@code true} if this parameter is implicitly declared + * in source code; returns {@code false} otherwise. * - * @return true if and only if this parameter is a synthesized - * construct as defined by - * The Java™ Language Specification. + * @return true if and only if this parameter is implicitly + * declared as defined by The Java™ Language + * Specification. */ - public boolean isSynthesized() { - return Modifier.isSynthesized(getModifiers()); + public boolean isImplicit() { + return Modifier.isMandated(getModifiers()); } /** - * Returns {@code true} if this parameter is a synthetic - * construct; returns {@code false} otherwise. + * Returns {@code true} if this parameter is neither implicitly + * nor explicitly declared in source code; returns {@code false} + * otherwise. * * @jls 13.1 The Form of a Binary * @return true if and only if this parameter is a synthetic From 62b85e6a17801f4c702d149898da9a9d2df8ce95 Mon Sep 17 00:00:00 2001 From: Mike Duigou Date: Wed, 6 Feb 2013 11:28:25 -0800 Subject: [PATCH 16/39] 8006594: Add jdk_core target to jdk/test/Makefile Reviewed-by: alanb --- jdk/make/jprt.properties | 3 +++ jdk/test/Makefile | 19 ++++++++++++++----- jdk/test/ProblemList.txt | 4 ++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/jdk/make/jprt.properties b/jdk/make/jprt.properties index a6d2ea1d0d4..8f7038e1f3b 100644 --- a/jdk/make/jprt.properties +++ b/jdk/make/jprt.properties @@ -63,6 +63,7 @@ jprt.vm.default.test.targets= \ ${jprt.my.test.target.set:TESTNAME=jvm98} # Default jdk test targets (testset=default) +# NOTE: This does not match test/Makefile :: jdk_default jprt.make.rule.default.test.targets= \ ${jprt.my.test.target.set:TESTNAME=jdk_lang}, \ ${jprt.my.test.target.set:TESTNAME=jdk_math} @@ -72,6 +73,7 @@ jprt.vm.core.test.targets= \ ${jprt.vm.default.test.targets} # Core jdk test targets (testset=core) +# NOTE: please keep this in sync with test/Makefile :: jdk_core jprt.make.rule.core.test.targets= \ ${jprt.make.rule.default.test.targets}, \ ${jprt.my.test.target.set:TESTNAME=jdk_util}, \ @@ -97,6 +99,7 @@ jprt.vm.all.test.targets= \ ${jprt.my.test.target.set:TESTNAME=jbb_default} # All jdk test targets (testset=all) +# NOTE: This does not match test/Makefile :: jdk_all jprt.make.rule.all.test.targets= \ ${jprt.make.rule.core.test.targets}, \ ${jprt.my.test.target.set:TESTNAME=jdk_awt}, \ diff --git a/jdk/test/Makefile b/jdk/test/Makefile index 408aaaeed25..093d4649b21 100644 --- a/jdk/test/Makefile +++ b/jdk/test/Makefile @@ -342,8 +342,8 @@ prep: clean # Cleanup clean: - $(RM) -r $(ABS_TEST_OUTPUT_DIR) - $(RM) $(ARCHIVE_BUNDLE) + @$(RM) -r $(ABS_TEST_OUTPUT_DIR) + @$(RM) $(ARCHIVE_BUNDLE) ################################################################ @@ -401,7 +401,7 @@ $(EXCLUDELIST): $(PROBLEM_LISTS) $(TEST_DEPENDENCIES) ($(ECHO) "#") ;\ ) | $(SED) -e 's@^[\ ]*@@' \ | $(EGREP) -v '^#' > $@.temp1 - for tdir in $(TESTDIRS) SOLARIS_10_SH_BUG_NO_EMPTY_FORS ; do \ + @for tdir in $(TESTDIRS) SOLARIS_10_SH_BUG_NO_EMPTY_FORS ; do \ ( ( $(CAT) $@.temp1 | $(EGREP) "^$${tdir}" ) ; $(ECHO) "#" ) >> $@.temp2 ; \ done @$(ECHO) "# at least one line" >> $@.temp2 @@ -431,6 +431,7 @@ endef # ------------------------------------------------------------------ # Batches of tests (somewhat arbitrary assigments to jdk_* targets) +# NOTE: These *do not* run the same tests as make/jprt.properties JDK_DEFAULT_TARGETS = JDK_ALL_TARGETS = @@ -614,15 +615,24 @@ jdk_util: $(call TestDirs, java/util sun/util) # ------------------------------------------------------------------ # Run default tests +# note that this *does not* have the same meaning as jprt.properties :: jprt.make.rule.default.test.targets jdk_default: $(JDK_DEFAULT_TARGETS) @$(SummaryInfo) +# Run core tests +# please keep this in sync with jdk/make/jprt.properties :: jprt.make.rule.core.test.targets +jdk_core: jdk_lang jdk_math jdk_util jdk_io jdk_net jdk_nio \ + jdk_security1 jdk_security2 jdk_security3 jdk_rmi \ + jdk_management jdk_jmx jdk_text jdk_tools jdk_jfr jdk_other + @$(SummaryInfo) + # Run all tests +# note that this *does not* have the same meaning as jprt.properties :: jprt.make.rule.all.test.targets jdk_all: $(JDK_ALL_TARGETS) @$(SummaryInfo) # These are all phony targets -PHONY_LIST += $(JDK_ALL_TARGETS) +PHONY_LIST += $(JDK_ALL_TARGETS) jdk_default jdk_core jdk_all # ------------------------------------------------------------------ @@ -892,4 +902,3 @@ PHONY_LIST += jck_all _generic_jck_tests \ .PHONY: all clean prep $(PHONY_LIST) ################################################################ - diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 69255074326..840a9274293 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -45,8 +45,8 @@ # as to why they are here and use a label: # generic-all Problems on all platforms # generic-ARCH Where ARCH is one of: sparc, sparcv9, x64, i586, etc. -# OSNAME-all Where OSNAME is one of: solaris, linux, windows -# OSNAME-ARCH Specific on to one OSNAME and ARCH, e.g. solaris-x64 +# OSNAME-all Where OSNAME is one of: solaris, linux, windows, macosx +# OSNAME-ARCH Specific on to one OSNAME and ARCH, e.g. solaris-amd64 # OSNAME-REV Specific on to one OSNAME and REV, e.g. solaris-5.8 # # More than one label is allowed but must be on the same line. From fb6927c36c6bc9add551771dddfaf95d97e81dd7 Mon Sep 17 00:00:00 2001 From: Jia-Hong Chen Date: Wed, 6 Feb 2013 14:45:02 -0800 Subject: [PATCH 17/39] 8005194: [parfait] #353 sun/awt/image/jpeg/imageioJPEG.c Memory leak of pointer 'scale' allocated with calloc() Reviewed-by: prr, vadim --- jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c index 0f39761750a..b405618be98 100644 --- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c +++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c @@ -2694,6 +2694,11 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_writeImage scale[i] = (UINT8*) malloc((maxBandValue + 1) * sizeof(UINT8)); if (scale[i] == NULL) { + // Cleanup before throwing an out of memory exception + for (j = 0; j < i; j++) { + free(scale[j]); + } + free(scale); JNU_ThrowByName( env, "java/lang/OutOfMemoryError", "Writing JPEG Stream"); return JNI_FALSE; From fc6a9c2d07f467d276ad7d6d9f914456562248a3 Mon Sep 17 00:00:00 2001 From: Mikhail Cherkasov Date: Fri, 8 Feb 2013 22:08:10 +0400 Subject: [PATCH 18/39] 8005932: Java 7 on mac os x only provides text clipboard formats Reviewed-by: alexp, denis --- jdk/src/macosx/lib/flavormap.properties | 6 +- .../AbsoluteComponentCenterCalculator.java | 37 ++++ .../DataFlavorSearcher.java | 47 ++++ .../InterprocessMessages.java | 28 +++ .../MissedHtmlAndRtfBug.html | 27 +++ .../MissedHtmlAndRtfBug.java | 205 ++++++++++++++++++ .../MissedHtmlAndRtfBug/MyTransferable.java | 62 ++++++ .../NextFramePositionCalculator.java | 20 ++ .../MissedHtmlAndRtfBug/SourcePanel.java | 26 +++ .../MissedHtmlAndRtfBug/TargetPanel.java | 83 +++++++ 10 files changed, 539 insertions(+), 2 deletions(-) create mode 100644 jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/AbsoluteComponentCenterCalculator.java create mode 100644 jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/DataFlavorSearcher.java create mode 100644 jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/InterprocessMessages.java create mode 100644 jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.html create mode 100644 jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.java create mode 100644 jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/MyTransferable.java create mode 100644 jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/NextFramePositionCalculator.java create mode 100644 jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/SourcePanel.java create mode 100644 jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/TargetPanel.java diff --git a/jdk/src/macosx/lib/flavormap.properties b/jdk/src/macosx/lib/flavormap.properties index 5e17d6e3d83..4a9f5fe3ffe 100644 --- a/jdk/src/macosx/lib/flavormap.properties +++ b/jdk/src/macosx/lib/flavormap.properties @@ -1,7 +1,7 @@ # # This properties file is used to initialize the default -# java.awt.datatransfer.SystemFlavorMap. It contains the X11 platform-specific, -# default mappings between common X11 selection atoms and platform-independent +# java.awt.datatransfer.SystemFlavorMap. It contains the Mac OS X platform-specific, +# default mappings between common Mac OS X selection atoms and platform-independent # MIME type strings, which will be converted into # java.awt.datatransfer.DataFlavors. # @@ -76,3 +76,5 @@ FILE_NAME=application/x-java-file-list;class=java.util.List text/uri-list=application/x-java-file-list;class=java.util.List PNG=image/x-java-image;class=java.awt.Image JFIF=image/x-java-image;class=java.awt.Image +RICH_TEXT=text/rtf +HTML=text/html;charset=utf-8;eoln="\r\n";terminators=1 diff --git a/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/AbsoluteComponentCenterCalculator.java b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/AbsoluteComponentCenterCalculator.java new file mode 100644 index 00000000000..6a9f630dec5 --- /dev/null +++ b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/AbsoluteComponentCenterCalculator.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, 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.awt.*; + +class AbsoluteComponentCenterCalculator { + private AbsoluteComponentCenterCalculator() { + } + + public static int calculateXCenterCoordinate(Component component) { + return (int) component.getLocationOnScreen().getX() + (component.getWidth() / 2); + } + + public static int calculateYCenterCoordinate(Component component) { + return (int) component.getLocationOnScreen().getY() + (component.getHeight() / 2); + } +} diff --git a/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/DataFlavorSearcher.java b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/DataFlavorSearcher.java new file mode 100644 index 00000000000..2b46cf643ba --- /dev/null +++ b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/DataFlavorSearcher.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013, 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.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.FlavorTable; +import java.awt.datatransfer.SystemFlavorMap; +import java.util.Arrays; + +public class DataFlavorSearcher { + static public String[] HTML_NAMES = new String[]{"HTML", "HTML Format"}; + static public String[] RICH_TEXT_NAMES = new String[]{"RICH_TEXT", "Rich Text Format"}; + + static public DataFlavor getByteDataFlavorForNative(String[] nats) { + FlavorTable flavorTable = (FlavorTable) SystemFlavorMap.getDefaultFlavorMap(); + + for (String nat : nats) { + java.util.List flavors = flavorTable.getFlavorsForNative(nat); + for (DataFlavor flavor : flavors) { + if (flavor != null + && flavor.getRepresentationClass().equals(byte[].class)) { + return flavor; + } + } + } + throw new RuntimeException("No data flavor was found for natives: " + Arrays.toString(nats)); + } +} diff --git a/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/InterprocessMessages.java b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/InterprocessMessages.java new file mode 100644 index 00000000000..d66982d0e31 --- /dev/null +++ b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/InterprocessMessages.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2013, 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. + */ + +interface InterprocessMessages { + final static int EXECUTION_IS_SUCCESSFULL = 0; + final static int DATA_IS_CORRUPTED = 212; +} + diff --git a/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.html b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.html new file mode 100644 index 00000000000..03f470d2dec --- /dev/null +++ b/jdk/test/java/awt/DataFlavor/MissedHtmlAndRtfBug/MissedHtmlAndRtfBug.html @@ -0,0 +1,27 @@ + + ZoneInfo///////////////////////////////// + + // ZoneInfo starts with UTC1900 + private static final long UTC1900 = -2208988800L; + // ZoneInfo ends with UTC2037 + private static final long UTC2037 = + LocalDateTime.of(2038, 1, 1, 0, 0, 0).toEpochSecond(ZoneOffset.UTC) - 1; + + /* Get a ZoneInfo instance. + * + * @param standardTransitions the standard transitions, not null + * @param standardOffsets the standard offsets, not null + * @param savingsInstantTransitions the standard transitions, not null + * @param wallOffsets the wall offsets, not null + * @param lastRules the recurring last rules, size 15 or less, not null + */ + private static ZoneInfo getZoneInfo(String zoneId, + long[] standardTransitions, + int[] standardOffsets, + long[] savingsInstantTransitions, + int[] wallOffsets, + ZoneOffsetTransitionRule[] lastRules) { + int rawOffset = 0; + int dstSavings = 0; + int checksum = 0; + int[] params = null; + boolean willGMTOffsetChange = false; + + // rawOffset, pick the last one + if (standardTransitions.length > 0) + rawOffset = standardOffsets[standardOffsets.length - 1] * 1000; + else + rawOffset = standardOffsets[0] * 1000; + + // transitions, offsets; + long[] transitions = null; + int[] offsets = null; + int nOffsets = 0; + int nTrans = 0; + + if (savingsInstantTransitions.length != 0) { + transitions = new long[250]; + offsets = new int[100]; // TBD: ZoneInfo actually can't handle + // offsets.length > 16 (4-bit index limit) + // last year in trans table + // It should not matter to use before or after offset for year + int lastyear = LocalDateTime.ofEpochSecond( + savingsInstantTransitions[savingsInstantTransitions.length - 1], 0, + ZoneOffset.ofTotalSeconds(wallOffsets[savingsInstantTransitions.length - 1])).getYear(); + // int lastyear = savingsLocalTransitions[savingsLocalTransitions.length - 1].getYear(); + + int i = 0, k = 1; + while (i < savingsInstantTransitions.length && + savingsInstantTransitions[i] < UTC1900) { + i++; // skip any date before UTC1900 + } + if (i < savingsInstantTransitions.length) { + // javazic writes the last GMT offset into index 0! + if (i < savingsInstantTransitions.length) { + offsets[0] = standardOffsets[standardOffsets.length - 1] * 1000; + nOffsets = 1; + } + // ZoneInfo has a beginning entry for 1900. + // Only add it if this is not the only one in table + nOffsets = addTrans(transitions, nTrans++, offsets, nOffsets, + UTC1900, + wallOffsets[i], + getStandardOffset(standardTransitions, standardOffsets, UTC1900)); + } + for (; i < savingsInstantTransitions.length; i++) { + //if (savingsLocalTransitions[i * 2].getYear() > LASTYEAR) { + if (savingsInstantTransitions[i] > UTC2037) { + // no trans beyond LASTYEAR + lastyear = LASTYEAR; + break; + } + long trans = savingsInstantTransitions[i]; + while (k < standardTransitions.length) { + // some standard offset transitions don't exist in + // savingInstantTrans, if the offset "change" doesn't + // really change the "effectiveWallOffset". For example + // the 1999/2000 pair in Zone Arg/Buenos_Aires, in which + // the daylightsaving "happened" but it actually does + // not result in the timezone switch. ZoneInfo however + // needs them in its transitions table + long trans_s = standardTransitions[k]; + if (trans_s >= UTC1900) { + if (trans_s > trans) + break; + if (trans_s < trans) { + if (nOffsets + 2 >= offsets.length) { + offsets = Arrays.copyOf(offsets, offsets.length + 100); + } + if (nTrans + 1 >= transitions.length) { + transitions = Arrays.copyOf(transitions, transitions.length + 100); + } + nOffsets = addTrans(transitions, nTrans++, offsets, nOffsets, + trans_s, + wallOffsets[i], + standardOffsets[k+1]); + } + } + k++; + } + if (nOffsets + 2 >= offsets.length) { + offsets = Arrays.copyOf(offsets, offsets.length + 100); + } + if (nTrans + 1 >= transitions.length) { + transitions = Arrays.copyOf(transitions, transitions.length + 100); + } + nOffsets = addTrans(transitions, nTrans++, offsets, nOffsets, + trans, + wallOffsets[i + 1], + getStandardOffset(standardTransitions, standardOffsets, trans)); + } + // append any leftover standard trans + while (k < standardTransitions.length) { + long trans = standardTransitions[k]; + if (trans >= UTC1900) { + int offset = wallOffsets[i]; + int offsetIndex = indexOf(offsets, 0, nOffsets, offset); + if (offsetIndex == nOffsets) + nOffsets++; + transitions[nTrans++] = ((trans * 1000) << TRANSITION_NSHIFT) | + (offsetIndex & OFFSET_MASK); + } + k++; + } + if (lastRules.length > 1) { + // fill the gap between the last trans until LASTYEAR + while (lastyear++ < LASTYEAR) { + for (ZoneOffsetTransitionRule zotr : lastRules) { + ZoneOffsetTransition zot = zotr.createTransition(lastyear); + //long trans = zot.getDateTimeBefore().toEpochSecond(); + long trans = zot.toEpochSecond(); + if (nOffsets + 2 >= offsets.length) { + offsets = Arrays.copyOf(offsets, offsets.length + 100); + } + if (nTrans + 1 >= transitions.length) { + transitions = Arrays.copyOf(transitions, transitions.length + 100); + } + nOffsets = addTrans(transitions, nTrans++, offsets, nOffsets, + trans, + zot.getOffsetAfter().getTotalSeconds(), + getStandardOffset(standardTransitions, standardOffsets, trans)); + } + } + ZoneOffsetTransitionRule startRule = lastRules[lastRules.length - 2]; + ZoneOffsetTransitionRule endRule = lastRules[lastRules.length - 1]; + params = new int[10]; + if (startRule.getOffsetBefore().compareTo(startRule.getOffsetAfter()) < 0 && + endRule.getOffsetBefore().compareTo(endRule.getOffsetAfter()) > 0) { + ZoneOffsetTransitionRule tmp; + tmp = startRule; + startRule = endRule; + endRule = tmp; + } + params[0] = startRule.getMonth().getValue() - 1; + // params[1] = startRule.getDayOfMonthIndicator(); + // params[2] = toCalendarDOW[startRule.getDayOfWeek().getValue()]; + int dom = startRule.getDayOfMonthIndicator(); + DayOfWeek dow = startRule.getDayOfWeek(); + if (dow == null) { + params[1] = startRule.getDayOfMonthIndicator(); + params[2] = 0; + } else { + // ZoneRulesBuilder adjusts < 0 case (-1, for last, don't have + // "<=" case yet) to positive value if not February (it appears + // we don't have February cutoff in tzdata table yet) + // Ideally, if JSR310 can just pass in the nagative and + // we can then pass in the dom = -1, dow > 0 into ZoneInfo + // + // hacking, assume the >=24 is the result of ZRB optimization for + // "last", it works for now. + if (dom < 0 || dom >= 24) { + params[1] = -1; + params[2] = toCalendarDOW[dow.getValue()]; + } else { + params[1] = dom; + // To specify a day of week on or after an exact day of month, + // set the month to an exact month value, day-of-month to the + // day on or after which the rule is applied, and day-of-week + // to a negative Calendar.DAY_OF_WEEK DAY_OF_WEEK field value. + params[2] = -toCalendarDOW[dow.getValue()]; + } + } + params[3] = startRule.getLocalTime().toSecondOfDay() * 1000; + params[4] = toSTZTime[startRule.getTimeDefinition().ordinal()]; + + params[5] = endRule.getMonth().getValue() - 1; + // params[6] = endRule.getDayOfMonthIndicator(); + // params[7] = toCalendarDOW[endRule.getDayOfWeek().getValue()]; + dom = endRule.getDayOfMonthIndicator(); + dow = endRule.getDayOfWeek(); + if (dow == null) { + params[6] = dom; + params[7] = 0; + } else { + // hacking: see comment above + if (dom < 0 || dom >= 24) { + params[6] = -1; + params[7] = toCalendarDOW[dow.getValue()]; + } else { + params[6] = dom; + params[7] = -toCalendarDOW[dow.getValue()]; + } + } + params[8] = endRule.getLocalTime().toSecondOfDay() * 1000; + params[9] = toSTZTime[endRule.getTimeDefinition().ordinal()]; + dstSavings = (startRule.getOffsetAfter().getTotalSeconds() + - startRule.getOffsetBefore().getTotalSeconds()) * 1000; + // Note: known mismatching -> Asia/Amman + // ZoneInfo : startDayOfWeek=5 <= Thursday + // startTime=86400000 <= 24 hours + // This: startDayOfWeek=6 + // startTime=0 + // Below is the workaround, it probably slows down everyone a little + if (params[2] == 6 && params[3] == 0 && zoneId.equals("Asia/Amman")) { + params[2] = 5; + params[3] = 86400000; + } + } else if (nTrans > 0) { // only do this if there is something in table already + if (lastyear < LASTYEAR) { + // ZoneInfo has an ending entry for 2037 + long trans = OffsetDateTime.of(LASTYEAR, Month.JANUARY.getValue(), 1, 0, 0, 0, 0, + ZoneOffset.ofTotalSeconds(rawOffset/1000)) + .toEpochSecond(); + int offsetIndex = indexOf(offsets, 0, nOffsets, rawOffset/1000); + if (offsetIndex == nOffsets) + nOffsets++; + transitions[nTrans++] = (trans * 1000) << TRANSITION_NSHIFT | + (offsetIndex & OFFSET_MASK); + } else if (savingsInstantTransitions.length > 2) { + // Workaround: create the params based on the last pair for + // zones like Israel and Iran which have trans defined + // up until 2037, but no "transition rule" defined + // + // Note: Known mismatching for Israel, Asia/Jerusalem/Tel Aviv + // ZoneInfo: startMode=3 + // startMonth=2 + // startDay=26 + // startDayOfWeek=6 + // + // This: startMode=1 + // startMonth=2 + // startDay=27 + // startDayOfWeek=0 + // these two are actually the same for 2037, the SimpleTimeZone + // for the last "known" year + int m = savingsInstantTransitions.length; + long startTrans = savingsInstantTransitions[m - 2]; + int startOffset = wallOffsets[m - 2 + 1]; + int startStd = getStandardOffset(standardTransitions, standardOffsets, startTrans); + long endTrans = savingsInstantTransitions[m - 1]; + int endOffset = wallOffsets[m - 1 + 1]; + int endStd = getStandardOffset(standardTransitions, standardOffsets, endTrans); + + if (startOffset > startStd && endOffset == endStd) { + /* + m = savingsLocalTransitions.length; + LocalDateTime startLDT = savingsLocalTransitions[m -4]; //gap + LocalDateTime endLDT = savingsLocalTransitions[m - 1]; //over + */ + // last - 1 trans + m = savingsInstantTransitions.length - 2; + ZoneOffset before = ZoneOffset.ofTotalSeconds(wallOffsets[m]); + ZoneOffset after = ZoneOffset.ofTotalSeconds(wallOffsets[m + 1]); + ZoneOffsetTransition trans = ZoneOffsetTransition.of( + LocalDateTime.ofEpochSecond(savingsInstantTransitions[m], 0, before), + before, + after); + LocalDateTime startLDT; + if (trans.isGap()) { + startLDT = trans.getDateTimeBefore(); + } else { + startLDT = trans.getDateTimeAfter(); + } + // last trans + m = savingsInstantTransitions.length - 1; + before = ZoneOffset.ofTotalSeconds(wallOffsets[m]); + after = ZoneOffset.ofTotalSeconds(wallOffsets[m + 1]); + trans = ZoneOffsetTransition.of( + LocalDateTime.ofEpochSecond(savingsInstantTransitions[m], 0, before), + before, + after); + LocalDateTime endLDT; + if (trans.isGap()) { + endLDT = trans.getDateTimeAfter(); + } else { + endLDT = trans.getDateTimeBefore(); + } + params = new int[10]; + params[0] = startLDT.getMonthValue() - 1; + params[1] = startLDT.getDayOfMonth(); + params[2] = 0; + params[3] = startLDT.toLocalTime().toSecondOfDay() * 1000; + params[4] = SimpleTimeZone.WALL_TIME; + params[5] = endLDT.getMonthValue() - 1; + params[6] = endLDT.getDayOfMonth(); + params[7] = 0; + params[8] = endLDT.toLocalTime().toSecondOfDay() * 1000; + params[9] = SimpleTimeZone.WALL_TIME; + dstSavings = (startOffset - startStd) * 1000; + } + } + } + if (transitions != null && transitions.length != nTrans) { + if (nTrans == 0) { + transitions = null; + } else { + transitions = Arrays.copyOf(transitions, nTrans); + } + } + if (offsets != null && offsets.length != nOffsets) { + if (nOffsets == 0) { + offsets = null; + } else { + offsets = Arrays.copyOf(offsets, nOffsets); + } + } + if (transitions != null) { + Checksum sum = new Checksum(); + for (i = 0; i < transitions.length; i++) { + long val = transitions[i]; + int dst = (int)((val >>> DST_NSHIFT) & 0xfL); + int saving = (dst == 0) ? 0 : offsets[dst]; + int index = (int)(val & OFFSET_MASK); + int offset = offsets[index]; + long second = (val >> TRANSITION_NSHIFT); + // javazic uses "index of the offset in offsets", + // instead of the real offset value itself to + // calculate the checksum. Have to keep doing + // the same thing, checksum is part of the + // ZoneInfo serialization form. + sum.update(second + index); + sum.update(index); + sum.update(dst == 0 ? -1 : dst); + } + checksum = (int)sum.getValue(); + } + } + return new ZoneInfo(zoneId, rawOffset, dstSavings, checksum, transitions, + offsets, params, willGMTOffsetChange); + } + + private static int getStandardOffset(long[] standardTransitions, + int[] standardOffsets, + long epochSec) { + int index = Arrays.binarySearch(standardTransitions, epochSec); + if (index < 0) { + // switch negative insert position to start of matched range + index = -index - 2; + } + return standardOffsets[index + 1]; + } + + private static int toCalendarDOW[] = new int[] { + -1, + Calendar.MONDAY, + Calendar.TUESDAY, + Calendar.WEDNESDAY, + Calendar.THURSDAY, + Calendar.FRIDAY, + Calendar.SATURDAY, + Calendar.SUNDAY + }; + + private static int toSTZTime[] = new int[] { + SimpleTimeZone.UTC_TIME, + SimpleTimeZone.WALL_TIME, + SimpleTimeZone.STANDARD_TIME, + }; + + private static final long OFFSET_MASK = 0x0fL; + private static final long DST_MASK = 0xf0L; + private static final int DST_NSHIFT = 4; + private static final int TRANSITION_NSHIFT = 12; + private static final int LASTYEAR = 2037; + + // from: 0 for offset lookup, 1 for dstsvings lookup + private static int indexOf(int[] offsets, int from, int nOffsets, int offset) { + offset *= 1000; + for (; from < nOffsets; from++) { + if (offsets[from] == offset) + return from; + } + offsets[from] = offset; + return from; + } + + // return updated nOffsets + private static int addTrans(long transitions[], int nTrans, + int offsets[], int nOffsets, + long trans, int offset, int stdOffset) { + int offsetIndex = indexOf(offsets, 0, nOffsets, offset); + if (offsetIndex == nOffsets) + nOffsets++; + int dstIndex = 0; + if (offset != stdOffset) { + dstIndex = indexOf(offsets, 1, nOffsets, offset - stdOffset); + if (dstIndex == nOffsets) + nOffsets++; + } + transitions[nTrans] = ((trans * 1000) << TRANSITION_NSHIFT) | + ((dstIndex << DST_NSHIFT) & DST_MASK) | + (offsetIndex & OFFSET_MASK); + return nOffsets; + } + + ///////////////////////////////////////////////////////////// + // ZoneInfo checksum, copy/pasted from javazic + private static class Checksum extends CRC32 { + public void update(int val) { + byte[] b = new byte[4]; + b[0] = (byte)((val >>> 24) & 0xff); + b[1] = (byte)((val >>> 16) & 0xff); + b[2] = (byte)((val >>> 8) & 0xff); + b[3] = (byte)(val & 0xff); + update(b); + } + void update(long val) { + byte[] b = new byte[8]; + b[0] = (byte)((val >>> 56) & 0xff); + b[1] = (byte)((val >>> 48) & 0xff); + b[2] = (byte)((val >>> 40) & 0xff); + b[3] = (byte)((val >>> 32) & 0xff); + b[4] = (byte)((val >>> 24) & 0xff); + b[5] = (byte)((val >>> 16) & 0xff); + b[6] = (byte)((val >>> 8) & 0xff); + b[7] = (byte)(val & 0xff); + update(b); + } + } } diff --git a/jdk/src/share/classes/sun/util/locale/provider/CalendarDataUtility.java b/jdk/src/share/classes/sun/util/locale/provider/CalendarDataUtility.java index 5b11c6cd9ac..656b6958bc6 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/CalendarDataUtility.java +++ b/jdk/src/share/classes/sun/util/locale/provider/CalendarDataUtility.java @@ -66,17 +66,43 @@ public class CalendarDataUtility { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(CalendarNameProvider.class); return pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id), - field, value, style); + field, value, style, false); + } + + public static String retrieveCldrFieldValueName(String id, int field, int value, int style, Locale locale) { + LocaleServiceProviderPool pool = + LocaleServiceProviderPool.getPool(CalendarNameProvider.class); + String name; + name = pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id), + field, value, style, true); + if (name == null) { + name = pool.getLocalizedObject(CalendarFieldValueNameGetter.INSTANCE, locale, normalizeCalendarType(id), + field, value, style, false); + } + return name; } public static Map retrieveFieldValueNames(String id, int field, int style, Locale locale) { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(CalendarNameProvider.class); return pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale, - normalizeCalendarType(id), field, style); + normalizeCalendarType(id), field, style, false); } - private static String normalizeCalendarType(String requestID) { + public static Map retrieveCldrFieldValueNames(String id, int field, int style, Locale locale) { + LocaleServiceProviderPool pool = + LocaleServiceProviderPool.getPool(CalendarNameProvider.class); + Map map; + map = pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale, + normalizeCalendarType(id), field, style, true); + if (map == null) { + map = pool.getLocalizedObject(CalendarFieldValueNamesMapGetter.INSTANCE, locale, + normalizeCalendarType(id), field, style, false); + } + return map; + } + + static String normalizeCalendarType(String requestID) { String type; if (requestID.equals("gregorian") || requestID.equals("iso8601")) { type = "gregory"; @@ -103,10 +129,20 @@ public class CalendarDataUtility { Locale locale, String requestID, // calendarType Object... params) { - assert params.length == 3; + assert params.length == 4; int field = (int) params[0]; int value = (int) params[1]; int style = (int) params[2]; + boolean cldr = (boolean) params[3]; + + // If cldr is true, resources from CLDR have precedence over JRE + // native resources. + if (cldr && calendarNameProvider instanceof CalendarNameProviderImpl) { + String name; + name = ((CalendarNameProviderImpl)calendarNameProvider) + .getCldrDisplayName(requestID, field, value, style, locale); + return name; + } return calendarNameProvider.getDisplayName(requestID, field, value, style, locale); } } @@ -126,9 +162,19 @@ public class CalendarDataUtility { Locale locale, String requestID, // calendarType Object... params) { - assert params.length == 2; + assert params.length == 3; int field = (int) params[0]; int style = (int) params[1]; + boolean cldr = (boolean) params[2]; + + // If cldr is true, resources from CLDR have precedence over JRE + // native resources. + if (cldr && calendarNameProvider instanceof CalendarNameProviderImpl) { + Map map; + map = ((CalendarNameProviderImpl)calendarNameProvider) + .getCldrDisplayNames(requestID, field, style, locale); + return map; + } return calendarNameProvider.getDisplayNames(requestID, field, style, locale); } } diff --git a/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java b/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java index 79cbe0a4d60..afdfd072b8d 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java +++ b/jdk/src/share/classes/sun/util/locale/provider/CalendarNameProviderImpl.java @@ -50,8 +50,16 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av @Override public String getDisplayName(String calendarType, int field, int value, int style, Locale locale) { + return getDisplayNameImpl(calendarType, field, value, style, locale, false); + } + + public String getCldrDisplayName(String calendarType, int field, int value, int style, Locale locale) { + return getDisplayNameImpl(calendarType, field, value, style, locale, true); + } + + public String getDisplayNameImpl(String calendarType, int field, int value, int style, Locale locale, boolean cldr) { String name = null; - String key = getResourceKey(calendarType, field, style); + String key = getResourceKey(calendarType, field, style, cldr); if (key != null) { String[] strings = LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCalendarNames(key); if (strings != null && strings.length > 0) { @@ -79,24 +87,32 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av SHORT_STANDALONE, LONG_FORMAT, LONG_STANDALONE, NARROW_FORMAT, NARROW_STANDALONE }; + @Override public Map getDisplayNames(String calendarType, int field, int style, Locale locale) { Map names; if (style == ALL_STYLES) { - names = getDisplayNamesImpl(calendarType, field, SHORT_FORMAT, locale); + names = getDisplayNamesImpl(calendarType, field, SHORT_FORMAT, locale, false); for (int st : REST_OF_STYLES) { - names.putAll(getDisplayNamesImpl(calendarType, field, st, locale)); + names.putAll(getDisplayNamesImpl(calendarType, field, st, locale, false)); } } else { // specific style - names = getDisplayNamesImpl(calendarType, field, style, locale); + names = getDisplayNamesImpl(calendarType, field, style, locale, false); } return names.isEmpty() ? null : names; } + // NOTE: This method should be used ONLY BY JSR 310 classes. + public Map getCldrDisplayNames(String calendarType, int field, int style, Locale locale) { + Map names; + names = getDisplayNamesImpl(calendarType, field, style, locale, true); + return names.isEmpty() ? null : names; + } + private Map getDisplayNamesImpl(String calendarType, int field, - int style, Locale locale) { - String key = getResourceKey(calendarType, field, style); + int style, Locale locale, boolean cldr) { + String key = getResourceKey(calendarType, field, style, cldr); Map map = new TreeMap<>(LengthBasedComparator.INSTANCE); if (key != null) { String[] strings = LocaleProviderAdapter.forType(type).getLocaleResources(locale).getCalendarNames(key); @@ -204,7 +220,7 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av return false; } - private String getResourceKey(String type, int field, int style) { + private String getResourceKey(String type, int field, int style, boolean cldr) { int baseStyle = getBaseStyle(style); boolean isStandalone = (style != baseStyle); @@ -213,6 +229,10 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av } boolean isNarrow = (baseStyle == NARROW_FORMAT); StringBuilder key = new StringBuilder(); + // If cldr is true, use prefix "cldr.". + if (cldr) { + key.append("cldr."); + } switch (field) { case ERA: if (type != null) { @@ -225,6 +245,11 @@ public class CalendarNameProviderImpl extends CalendarNameProvider implements Av // due to historical reasons. (JRE DateFormatSymbols.getEras returns // abbreviations while other getShort*() return abbreviations.) if (this.type == LocaleProviderAdapter.Type.JRE) { + if (cldr) { + if (baseStyle == LONG) { + key.append("long."); + } + } if (baseStyle == SHORT) { key.append("short."); } diff --git a/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java b/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java index 009cc5b8a63..dafa74e2ab1 100644 --- a/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java @@ -332,23 +332,61 @@ public class LocaleResources { } public String getDateTimePattern(int timeStyle, int dateStyle, Calendar cal) { - String pattern; - if (cal == null) { cal = Calendar.getInstance(locale); } - String calType = cal.getCalendarType(); + return getDateTimePattern(null, timeStyle, dateStyle, cal.getCalendarType()); + } + + /** + * Returns a date-time format pattern + * @param timeStyle style of time; one of FULL, LONG, MEDIUM, SHORT in DateFormat, + * or -1 if not required + * @param dateStyle style of time; one of FULL, LONG, MEDIUM, SHORT in DateFormat, + * or -1 if not required + * @param calType the calendar type for the pattern + * @return the pattern string + */ + public String getCldrDateTimePattern(int timeStyle, int dateStyle, String calType) { + calType = CalendarDataUtility.normalizeCalendarType(calType); + String pattern; + pattern = getDateTimePattern("cldr.", timeStyle, dateStyle, calType); + if (pattern == null) { + pattern = getDateTimePattern(null, timeStyle, dateStyle, calType); + } + return pattern; + } + + private String getDateTimePattern(String prefix, int timeStyle, int dateStyle, String calType) { + String pattern; String timePattern = null; String datePattern = null; + if (timeStyle >= 0) { - timePattern = getDateTimePattern("TimePatterns", timeStyle, calType); + if (prefix != null) { + timePattern = getDateTimePattern(prefix, "TimePatterns", timeStyle, calType); + } + if (timePattern == null) { + timePattern = getDateTimePattern(null, "TimePatterns", timeStyle, calType); + } } if (dateStyle >= 0) { - datePattern = getDateTimePattern("DatePatterns", dateStyle, calType); + if (prefix != null) { + datePattern = getDateTimePattern(prefix, "DatePatterns", dateStyle, calType); + } + if (datePattern == null) { + datePattern = getDateTimePattern(null, "DatePatterns", dateStyle, calType); + } } if (timeStyle >= 0) { if (dateStyle >= 0) { - String dateTimePattern = getDateTimePattern("DateTimePatterns", 0, calType); + String dateTimePattern = null; + if (prefix != null) { + dateTimePattern = getDateTimePattern(prefix, "DateTimePatterns", 0, calType); + } + if (dateTimePattern == null) { + dateTimePattern = getDateTimePattern(null, "DateTimePatterns", 0, calType); + } switch (dateTimePattern) { case "{1} {0}": pattern = datePattern + " " + timePattern; @@ -396,27 +434,40 @@ public class LocaleResources { return localeData.getDateFormatData(locale); } - private String getDateTimePattern(String key, int styleIndex, String calendarType) { - String resourceKey = "gregory".equals(calendarType) ? key : calendarType + "." + key; - String cacheKey = DATE_TIME_PATTERN + resourceKey; - String[] patterns = null; + private String getDateTimePattern(String prefix, String key, int styleIndex, String calendarType) { + StringBuilder sb = new StringBuilder(); + if (prefix != null) { + sb.append(prefix); + } + if (!"gregory".equals(calendarType)) { + sb.append(calendarType).append('.'); + } + sb.append(key); + String resourceKey = sb.toString(); + String cacheKey = sb.insert(0, DATE_TIME_PATTERN).toString(); removeEmptyReferences(); ResourceReference data = cache.get(cacheKey); + Object value = NULLOBJECT; - if (data == null || ((patterns = (String[]) data.get()) == null)) { + if (data == null || ((value = data.get()) == null)) { ResourceBundle r = localeData.getDateFormatData(locale); if (r.containsKey(resourceKey)) { - patterns = r.getStringArray(resourceKey); + value = r.getStringArray(resourceKey); } else { assert !resourceKey.equals(key); - patterns = r.getStringArray(key); + if (r.containsKey(key)) { + value = r.getStringArray(key); + } } cache.put(cacheKey, - new ResourceReference(cacheKey, (Object) patterns, referenceQueue)); + new ResourceReference(cacheKey, value, referenceQueue)); } - - return patterns[styleIndex]; + if (value == NULLOBJECT) { + assert prefix != null; + return null; + } + return ((String[])value)[styleIndex]; } private static class ResourceReference extends SoftReference { diff --git a/jdk/test/java/sql/JavatimeTest.java b/jdk/test/java/sql/JavatimeTest.java new file mode 100644 index 00000000000..3ff70d007d1 --- /dev/null +++ b/jdk/test/java/sql/JavatimeTest.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2013, 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 8007520 + *@summary Test those bridge methods to/from java.time date/time classes + */ + +import java.util.Random; +import java.sql.Date; +import java.sql.Time; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +public class JavatimeTest { + + static final int NANOS_PER_SECOND = 1000000000; + + public static void main(String[] args) throws Throwable { + int N = 10000; + long t1970 = new java.util.Date(70, 0, 01).getTime(); + Random r = new Random(); + for (int i = 0; i < N; i++) { + int days = r.nextInt(50) * 365 + r.nextInt(365); + long secs = t1970 + days * 86400 + r.nextInt(86400); + int nanos = r.nextInt(NANOS_PER_SECOND); + int nanos_ms = nanos / 1000000 * 1000000; // millis precision + long millis = secs * 1000 + r.nextInt(1000); + + LocalDateTime ldt = LocalDateTime.ofEpochSecond(secs, nanos, ZoneOffset.UTC); + LocalDateTime ldt_ms = LocalDateTime.ofEpochSecond(secs, nanos_ms, ZoneOffset.UTC); + Instant inst = Instant.ofEpochSecond(secs, nanos); + Instant inst_ms = Instant.ofEpochSecond(secs, nanos_ms); + //System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + + /////////// Timestamp //////////////////////////////// + Timestamp ta = new Timestamp(millis); + ta.setNanos(nanos); + if (!isEqual(ta.toLocalDateTime(), ta)) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + print(ta.toLocalDateTime(), ta); + throw new RuntimeException("FAILED: j.s.ts -> ldt"); + } + if (!isEqual(ldt, Timestamp.valueOf(ldt))) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + print(ldt, Timestamp.valueOf(ldt)); + throw new RuntimeException("FAILED: ldt -> j.s.ts"); + } + Instant inst0 = ta.toInstant(); + if (ta.getTime() != inst0.toEpochMilli() || + ta.getNanos() != inst0.getNano() || + !ta.equals(Timestamp.from(inst0))) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + throw new RuntimeException("FAILED: j.s.ts -> instant -> j.s.ts"); + } + inst = Instant.ofEpochSecond(secs, nanos); + Timestamp ta0 = Timestamp.from(inst); + if (ta0.getTime() != inst.toEpochMilli() || + ta0.getNanos() != inst.getNano() || + !inst.equals(ta0.toInstant())) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + throw new RuntimeException("FAILED: instant -> timestamp -> instant"); + } + + ////////// java.sql.Date ///////////////////////////// + // j.s.d/t uses j.u.d.equals() !!!!!!!! + java.sql.Date jsd = new java.sql.Date(millis); + if (!isEqual(jsd.toLocalDate(), jsd)) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + print(jsd.toLocalDate(), jsd); + throw new RuntimeException("FAILED: j.s.d -> ld"); + } + LocalDate ld = ldt.toLocalDate(); + if (!isEqual(ld, java.sql.Date.valueOf(ld))) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + print(ld, java.sql.Date.valueOf(ld)); + throw new RuntimeException("FAILED: ld -> j.s.d"); + } + ////////// java.sql.Time ///////////////////////////// + java.sql.Time jst = new java.sql.Time(millis); + if (!isEqual(jst.toLocalTime(), jst)) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + print(jst.toLocalTime(), jst); + throw new RuntimeException("FAILED: j.s.t -> lt"); + } + // millis precision + LocalTime lt = ldt_ms.toLocalTime(); + if (!isEqual(lt, java.sql.Time.valueOf(lt))) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + print(lt, java.sql.Time.valueOf(lt)); + throw new RuntimeException("FAILED: lt -> j.s.t"); + } + } + System.out.println("Passed!"); + } + + private static boolean isEqual(LocalDateTime ldt, Timestamp ts) { + ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault()); + return zdt.getYear() == ts.getYear() + 1900 && + zdt.getMonthValue() == ts.getMonth() + 1 && + zdt.getDayOfMonth() == ts.getDate() && + zdt.getHour() == ts.getHours() && + zdt.getMinute() == ts.getMinutes() && + zdt.getSecond() == ts.getSeconds() && + zdt.getNano() == ts.getNanos(); + } + + private static void print(LocalDateTime ldt, Timestamp ts) { + ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault()); + System.out.printf("ldt:ts %d/%d, %d/%d, %d/%d, %d/%d, %d/%d, %d/%d, nano:[%d/%d]%n", + zdt.getYear(), ts.getYear() + 1900, + zdt.getMonthValue(), ts.getMonth() + 1, + zdt.getDayOfMonth(), ts.getDate(), + zdt.getHour(), ts.getHours(), + zdt.getMinute(), ts.getMinutes(), + zdt.getSecond(), ts.getSeconds(), + zdt.getNano(), ts.getNanos()); + } + + private static boolean isEqual(LocalDate ld, java.sql.Date d) { + return ld.getYear() == d.getYear() + 1900 && + ld.getMonthValue() == d.getMonth() + 1 && + ld.getDayOfMonth() == d.getDate(); + } + + private static void print(LocalDate ld, java.sql.Date d) { + System.out.printf("%d/%d, %d/%d, %d/%d%n", + ld.getYear(), d.getYear() + 1900, + ld.getMonthValue(), d.getMonth() + 1, + ld.getDayOfMonth(), d.getDate()); + } + + private static boolean isEqual(LocalTime lt, java.sql.Time t) { + return lt.getHour() == t.getHours() && + lt.getMinute() == t.getMinutes() && + lt.getSecond() == t.getSeconds(); + } + + private static void print(LocalTime lt, java.sql.Time t) { + System.out.printf("%d/%d, %d/%d, %d/%d%n", + lt.getHour(), t.getHours(), + lt.getMinute(), t.getMinutes(), + lt.getSecond(), t.getSeconds()); + } +} diff --git a/jdk/test/java/time/META-INF/services/java.time.chrono.Chronology b/jdk/test/java/time/META-INF/services/java.time.chrono.Chronology new file mode 100644 index 00000000000..d30ab01b8a1 --- /dev/null +++ b/jdk/test/java/time/META-INF/services/java.time.chrono.Chronology @@ -0,0 +1 @@ +tck.java.time.chrono.CopticChronology diff --git a/jdk/test/java/time/META-INF/services/java.time.temporal.Chrono b/jdk/test/java/time/META-INF/services/java.time.temporal.Chrono deleted file mode 100644 index 918ad84d621..00000000000 --- a/jdk/test/java/time/META-INF/services/java.time.temporal.Chrono +++ /dev/null @@ -1 +0,0 @@ -tck.java.time.calendar.CopticChrono diff --git a/jdk/test/java/time/tck/java/time/AbstractTCKTest.java b/jdk/test/java/time/tck/java/time/AbstractTCKTest.java index ce20d6b9386..ff7fc02aa1f 100644 --- a/jdk/test/java/time/tck/java/time/AbstractTCKTest.java +++ b/jdk/test/java/time/tck/java/time/AbstractTCKTest.java @@ -57,6 +57,7 @@ package tck.java.time; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -89,6 +90,12 @@ public abstract class AbstractTCKTest { assertEquals(deserializedObject, object); } + protected static void assertSerializableSame(Object object) throws IOException, ClassNotFoundException { + assertEquals(object instanceof Serializable, true); + Object deserializedObject = writeThenRead(object); + assertSame(deserializedObject, object); + } + private static Object writeThenRead(Object object) throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (ObjectOutputStream oos = new ObjectOutputStream(baos) ) { diff --git a/jdk/test/java/time/tck/java/time/MockSimplePeriod.java b/jdk/test/java/time/tck/java/time/MockSimplePeriod.java new file mode 100644 index 00000000000..7b008341592 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/MockSimplePeriod.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time; + +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.FOREVER; +import static java.time.temporal.ChronoUnit.SECONDS; + +import java.time.DateTimeException; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalUnit; +import java.util.List; +import java.util.Objects; + +/** + * Mock period of time measured using a single unit, such as {@code 3 Days}. + */ +public final class MockSimplePeriod + implements TemporalAmount, Comparable { + + /** + * A constant for a period of zero, measured in days. + */ + public static final MockSimplePeriod ZERO_DAYS = new MockSimplePeriod(0, DAYS); + /** + * A constant for a period of zero, measured in seconds. + */ + public static final MockSimplePeriod ZERO_SECONDS = new MockSimplePeriod(0, SECONDS); + + /** + * The amount of the period. + */ + private final long amount; + /** + * The unit the period is measured in. + */ + private final TemporalUnit unit; + + /** + * Obtains a {@code MockSimplePeriod} from an amount and unit. + *

    + * The parameters represent the two parts of a phrase like '6 Days'. + * + * @param amount the amount of the period, measured in terms of the unit, positive or negative + * @param unit the unit that the period is measured in, must not be the 'Forever' unit, not null + * @return the {@code MockSimplePeriod} instance, not null + * @throws java.time.DateTimeException if the period unit is {@link java.time.temporal.ChronoUnit#FOREVER}. + */ + public static MockSimplePeriod of(long amount, TemporalUnit unit) { + return new MockSimplePeriod(amount, unit); + } + + private MockSimplePeriod(long amount, TemporalUnit unit) { + Objects.requireNonNull(unit, "unit"); + if (unit == FOREVER) { + throw new DateTimeException("Cannot create a period of the Forever unit"); + } + this.amount = amount; + this.unit = unit; + } + + @Override + public long get(TemporalUnit unit) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getUnits() { + throw new UnsupportedOperationException("Not supported yet."); + } + + //----------------------------------------------------------------------- + public long getAmount() { + return amount; + } + + public TemporalUnit getUnit() { + return unit; + } + + //------------------------------------------------------------------------- + @Override + public Temporal addTo(Temporal temporal) { + return temporal.plus(amount, unit); + } + + @Override + public Temporal subtractFrom(Temporal temporal) { + return temporal.minus(amount, unit); + } + + //----------------------------------------------------------------------- + @Override + public int compareTo(MockSimplePeriod otherPeriod) { + if (unit.equals(otherPeriod.getUnit()) == false) { + throw new IllegalArgumentException("Units cannot be compared: " + unit + " and " + otherPeriod.getUnit()); + } + return Long.compare(amount, otherPeriod.amount); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof MockSimplePeriod) { + MockSimplePeriod other = (MockSimplePeriod) obj; + return this.amount == other.amount && + this.unit.equals(other.unit); + } + return false; + } + + @Override + public int hashCode() { + return unit.hashCode() ^ (int) (amount ^ (amount >>> 32)); + } + + @Override + public String toString() { + return amount + " " + unit.getName(); + } + +} diff --git a/jdk/test/java/time/tck/java/time/TCKClock.java b/jdk/test/java/time/tck/java/time/TCKClock.java index e4a870e3796..82e47f7f681 100644 --- a/jdk/test/java/time/tck/java/time/TCKClock.java +++ b/jdk/test/java/time/tck/java/time/TCKClock.java @@ -83,6 +83,10 @@ public class TCKClock { return millis; } @Override + public Instant instant() { + return Instant.ofEpochMilli(millis()); + } + @Override public ZoneId getZone() { return zone; } diff --git a/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java b/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java index 20e66a2ed96..13cc7b4093d 100644 --- a/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java +++ b/jdk/test/java/time/tck/java/time/TCKClock_Fixed.java @@ -154,13 +154,4 @@ public class TCKClock_Fixed extends AbstractTCKTest { Clock d = Clock.fixed(INSTANT.minusNanos(1), ZoneOffset.UTC); assertEquals(a.hashCode() == d.hashCode(), false); } - - //----------------------------------------------------------------------- - public void test_toString() { - // spec requires "full state" in toString() - Clock test = Clock.fixed(INSTANT, PARIS); - assertEquals(test.toString().contains("Europe/Paris"), true); - assertEquals(test.toString().contains("2008-06-30T09:30:10.000000500Z"), true); - } - } diff --git a/jdk/test/java/time/tck/java/time/TCKClock_Offset.java b/jdk/test/java/time/tck/java/time/TCKClock_Offset.java index b628c0ce4eb..3bab2acd52f 100644 --- a/jdk/test/java/time/tck/java/time/TCKClock_Offset.java +++ b/jdk/test/java/time/tck/java/time/TCKClock_Offset.java @@ -91,8 +91,8 @@ public class TCKClock_Offset extends AbstractTCKTest { //----------------------------------------------------------------------- public void test_offset_ClockDuration() { Clock test = Clock.offset(Clock.fixed(INSTANT, PARIS), OFFSET); - System.out.println(test.instant()); - System.out.println(INSTANT.plus(OFFSET)); + //System.out.println(test.instant()); + //System.out.println(INSTANT.plus(OFFSET)); assertEquals(test.instant(), INSTANT.plus(OFFSET)); assertEquals(test.getZone(), PARIS); } @@ -165,12 +165,4 @@ public class TCKClock_Offset extends AbstractTCKTest { assertEquals(a.hashCode() == d.hashCode(), false); } - //----------------------------------------------------------------------- - public void test_toString() { - // spec requires "full state" in toString() - Clock test = Clock.offset(Clock.system(PARIS), OFFSET); - assertEquals(test.toString().contains("Europe/Paris"), true); - assertEquals(test.toString().contains("PT2S"), true); - } - } diff --git a/jdk/test/java/time/tck/java/time/TCKClock_System.java b/jdk/test/java/time/tck/java/time/TCKClock_System.java index 8152a502ffa..b5440b2bfd5 100644 --- a/jdk/test/java/time/tck/java/time/TCKClock_System.java +++ b/jdk/test/java/time/tck/java/time/TCKClock_System.java @@ -197,11 +197,4 @@ public class TCKClock_System extends AbstractTCKTest { assertEquals(a.hashCode() == c.hashCode(), false); } - //----------------------------------------------------------------------- - public void test_toString() { - // spec requires "full state" in toString() - Clock test = Clock.system(PARIS); - assertEquals(test.toString().contains("Europe/Paris"), true); - } - } diff --git a/jdk/test/java/time/tck/java/time/TCKClock_Tick.java b/jdk/test/java/time/tck/java/time/TCKClock_Tick.java index 3022d77b747..b245d143ccb 100644 --- a/jdk/test/java/time/tck/java/time/TCKClock_Tick.java +++ b/jdk/test/java/time/tck/java/time/TCKClock_Tick.java @@ -248,13 +248,4 @@ public class TCKClock_Tick extends AbstractTCKTest { Clock d = Clock.tick(Clock.system(PARIS), Duration.ofMillis(499)); assertEquals(a.hashCode() == d.hashCode(), false); } - - //----------------------------------------------------------------------- - public void test_toString() { - // spec requires "full state" in toString() - Clock test = Clock.tick(Clock.system(PARIS), AMOUNT); - assertEquals(test.toString().contains("Europe/Paris"), true); - assertEquals(test.toString().contains("PT2S"), true); - } - } diff --git a/jdk/test/java/time/tck/java/time/TCKDayOfWeek.java b/jdk/test/java/time/tck/java/time/TCKDayOfWeek.java index a2460898039..196c0402a99 100644 --- a/jdk/test/java/time/tck/java/time/TCKDayOfWeek.java +++ b/jdk/test/java/time/tck/java/time/TCKDayOfWeek.java @@ -66,25 +66,24 @@ import static java.time.temporal.ChronoField.DAY_OF_WEEK; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertSame; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; - import java.time.DateTimeException; import java.time.DayOfWeek; import java.time.LocalDate; import java.time.LocalTime; -import java.time.Month; +import java.time.chrono.IsoChronology; import java.time.format.TextStyle; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; -import java.time.temporal.ISOChrono; import java.time.temporal.JulianFields; import java.time.temporal.Queries; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQuery; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; @@ -177,34 +176,27 @@ public class TCKDayOfWeek extends AbstractDateTimeTest { //----------------------------------------------------------------------- // query(TemporalQuery) //----------------------------------------------------------------------- - @Test - public void test_query_chrono() { - assertEquals(DayOfWeek.FRIDAY.query(Queries.chrono()), null); - assertEquals(Queries.chrono().queryFrom(DayOfWeek.FRIDAY), null); + @DataProvider(name="query") + Object[][] data_query() { + return new Object[][] { + {DayOfWeek.FRIDAY, Queries.chronology(), null}, + {DayOfWeek.FRIDAY, Queries.zoneId(), null}, + {DayOfWeek.FRIDAY, Queries.precision(), ChronoUnit.DAYS}, + {DayOfWeek.FRIDAY, Queries.zone(), null}, + {DayOfWeek.FRIDAY, Queries.offset(), null}, + {DayOfWeek.FRIDAY, Queries.localDate(), null}, + {DayOfWeek.FRIDAY, Queries.localTime(), null}, + }; } - @Test - public void test_query_zoneId() { - assertEquals(DayOfWeek.FRIDAY.query(Queries.zoneId()), null); - assertEquals(Queries.zoneId().queryFrom(DayOfWeek.FRIDAY), null); + @Test(dataProvider="query") + public void test_query(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(temporal.query(query), expected); } - @Test - public void test_query_precision() { - assertEquals(DayOfWeek.FRIDAY.query(Queries.precision()), ChronoUnit.DAYS); - assertEquals(Queries.precision().queryFrom(DayOfWeek.FRIDAY), ChronoUnit.DAYS); - } - - @Test - public void test_query_offset() { - assertEquals(DayOfWeek.FRIDAY.query(Queries.offset()), null); - assertEquals(Queries.offset().queryFrom(DayOfWeek.FRIDAY), null); - } - - @Test - public void test_query_zone() { - assertEquals(DayOfWeek.FRIDAY.query(Queries.zone()), null); - assertEquals(Queries.zone().queryFrom(DayOfWeek.FRIDAY), null); + @Test(dataProvider="query") + public void test_queryFrom(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(query.queryFrom(temporal), expected); } @Test(expectedExceptions=NullPointerException.class) @@ -217,17 +209,17 @@ public class TCKDayOfWeek extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_getText() { - assertEquals(DayOfWeek.MONDAY.getText(TextStyle.SHORT, Locale.US), "Mon"); + assertEquals(DayOfWeek.MONDAY.getDisplayName(TextStyle.SHORT, Locale.US), "Mon"); } @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) public void test_getText_nullStyle() { - DayOfWeek.MONDAY.getText(null, Locale.US); + DayOfWeek.MONDAY.getDisplayName(null, Locale.US); } @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) public void test_getText_nullLocale() { - DayOfWeek.MONDAY.getText(TextStyle.FULL, null); + DayOfWeek.MONDAY.getDisplayName(TextStyle.FULL, null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKDuration.java b/jdk/test/java/time/tck/java/time/TCKDuration.java index aeba804291d..797b54b1f31 100644 --- a/jdk/test/java/time/tck/java/time/TCKDuration.java +++ b/jdk/test/java/time/tck/java/time/TCKDuration.java @@ -69,6 +69,7 @@ import static java.time.temporal.ChronoUnit.NANOS; import static java.time.temporal.ChronoUnit.SECONDS; import static java.time.temporal.ChronoUnit.WEEKS; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import java.io.ByteArrayInputStream; @@ -76,12 +77,17 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; - import java.time.DateTimeException; import java.time.Duration; import java.time.Instant; +import java.time.LocalTime; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; import java.time.temporal.TemporalUnit; +import java.util.List; +import java.util.Locale; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -436,8 +442,8 @@ public class TCKDuration extends AbstractTCKTest { //----------------------------------------------------------------------- // between() //----------------------------------------------------------------------- - @DataProvider(name="DurationBetween") - Object[][] provider_factory_between_Instant_Instant() { + @DataProvider(name="durationBetweenInstant") + Object[][] data_durationBetweenInstant() { return new Object[][] { {0, 0, 0, 0, 0, 0}, {3, 0, 7, 0, 4, 0}, @@ -447,8 +453,8 @@ public class TCKDuration extends AbstractTCKTest { }; } - @Test(dataProvider="DurationBetween", groups={"tck"}) - public void factory_between_Instant_Instant(long secs1, int nanos1, long secs2, int nanos2, long expectedSeconds, int expectedNanoOfSecond) { + @Test(dataProvider="durationBetweenInstant") + public void factory_between_TemporalTemporal_Instant(long secs1, int nanos1, long secs2, int nanos2, long expectedSeconds, int expectedNanoOfSecond) { Instant start = Instant.ofEpochSecond(secs1, nanos1); Instant end = Instant.ofEpochSecond(secs2, nanos2); Duration t = Duration.between(start, end); @@ -456,14 +462,36 @@ public class TCKDuration extends AbstractTCKTest { assertEquals(t.getNano(), expectedNanoOfSecond); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void factory_between_Instant_Instant_startNull() { + @DataProvider(name="durationBetweenLocalTime") + Object[][] data_durationBetweenLocalTime() { + return new Object[][] { + {LocalTime.of(11, 0, 30), LocalTime.of(11, 0, 45), 15L, 0}, + {LocalTime.of(11, 0, 30), LocalTime.of(11, 0, 25), -5L, 0}, + }; + } + + @Test(dataProvider="durationBetweenLocalTime") + public void factory_between_TemporalTemporal_LT(LocalTime start, LocalTime end, long expectedSeconds, int expectedNanoOfSecond) { + Duration t = Duration.between(start, end); + assertEquals(t.getSeconds(), expectedSeconds); + assertEquals(t.getNano(), expectedNanoOfSecond); + } + + @Test(expectedExceptions=DateTimeException.class) + public void factory_between_TemporalTemporal_mixedTypes() { + Instant start = Instant.ofEpochSecond(1); + ZonedDateTime end = Instant.ofEpochSecond(4).atZone(ZoneOffset.UTC); + Duration.between(start, end); + } + + @Test(expectedExceptions=NullPointerException.class) + public void factory_between__TemporalTemporal_startNull() { Instant end = Instant.ofEpochSecond(1); Duration.between(null, end); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void factory_between_Instant_Instant_endNull() { + @Test(expectedExceptions=NullPointerException.class) + public void factory_between__TemporalTemporal_endNull() { Instant start = Instant.ofEpochSecond(1); Duration.between(start, null); } @@ -471,140 +499,257 @@ public class TCKDuration extends AbstractTCKTest { //----------------------------------------------------------------------- // parse(String) //----------------------------------------------------------------------- - @DataProvider(name="Parse") - Object[][] provider_factory_parse() { + @DataProvider(name="parseSuccess") + Object[][] data_parseSuccess() { return new Object[][] { - {"PT0S", 0, 0}, - {"pT0S", 0, 0}, - {"Pt0S", 0, 0}, - {"PT0s", 0, 0}, + {"PT0S", 0, 0}, + {"PT1S", 1, 0}, + {"PT12S", 12, 0}, + {"PT123456789S", 123456789, 0}, + {"PT" + Long.MAX_VALUE + "S", Long.MAX_VALUE, 0}, - {"PT1S", 1, 0}, - {"PT12S", 12, 0}, - {"PT123456789S", 123456789, 0}, - {"PT" + Long.MAX_VALUE + "S", Long.MAX_VALUE, 0}, + {"PT+1S", 1, 0}, + {"PT+12S", 12, 0}, + {"PT+123456789S", 123456789, 0}, + {"PT+" + Long.MAX_VALUE + "S", Long.MAX_VALUE, 0}, - {"PT-1S", -1, 0}, - {"PT-12S", -12, 0}, - {"PT-123456789S", -123456789, 0}, - {"PT" + Long.MIN_VALUE + "S", Long.MIN_VALUE, 0}, + {"PT-1S", -1, 0}, + {"PT-12S", -12, 0}, + {"PT-123456789S", -123456789, 0}, + {"PT" + Long.MIN_VALUE + "S", Long.MIN_VALUE, 0}, - {"PT1.1S", 1, 100000000}, - {"PT1.12S", 1, 120000000}, - {"PT1.123S", 1, 123000000}, - {"PT1.1234S", 1, 123400000}, - {"PT1.12345S", 1, 123450000}, - {"PT1.123456S", 1, 123456000}, - {"PT1.1234567S", 1, 123456700}, - {"PT1.12345678S", 1, 123456780}, - {"PT1.123456789S", 1, 123456789}, + {"PT1.1S", 1, 100000000}, + {"PT1.12S", 1, 120000000}, + {"PT1.123S", 1, 123000000}, + {"PT1.1234S", 1, 123400000}, + {"PT1.12345S", 1, 123450000}, + {"PT1.123456S", 1, 123456000}, + {"PT1.1234567S", 1, 123456700}, + {"PT1.12345678S", 1, 123456780}, + {"PT1.123456789S", 1, 123456789}, - {"PT-1.1S", -2, 1000000000 - 100000000}, - {"PT-1.12S", -2, 1000000000 - 120000000}, - {"PT-1.123S", -2, 1000000000 - 123000000}, - {"PT-1.1234S", -2, 1000000000 - 123400000}, - {"PT-1.12345S", -2, 1000000000 - 123450000}, - {"PT-1.123456S", -2, 1000000000 - 123456000}, - {"PT-1.1234567S", -2, 1000000000 - 123456700}, - {"PT-1.12345678S", -2, 1000000000 - 123456780}, - {"PT-1.123456789S", -2, 1000000000 - 123456789}, + {"PT-1.1S", -2, 1000000000 - 100000000}, + {"PT-1.12S", -2, 1000000000 - 120000000}, + {"PT-1.123S", -2, 1000000000 - 123000000}, + {"PT-1.1234S", -2, 1000000000 - 123400000}, + {"PT-1.12345S", -2, 1000000000 - 123450000}, + {"PT-1.123456S", -2, 1000000000 - 123456000}, + {"PT-1.1234567S", -2, 1000000000 - 123456700}, + {"PT-1.12345678S", -2, 1000000000 - 123456780}, + {"PT-1.123456789S", -2, 1000000000 - 123456789}, - {"PT" + Long.MAX_VALUE + ".123456789S", Long.MAX_VALUE, 123456789}, - {"PT" + Long.MIN_VALUE + ".000000000S", Long.MIN_VALUE, 0}, + {"PT" + Long.MAX_VALUE + ".123456789S", Long.MAX_VALUE, 123456789}, + {"PT" + Long.MIN_VALUE + ".000000000S", Long.MIN_VALUE, 0}, + + {"PT01S", 1, 0}, + {"PT001S", 1, 0}, + {"PT000S", 0, 0}, + {"PT+01S", 1, 0}, + {"PT-01S", -1, 0}, + + {"PT1.S", 1, 0}, + {"PT+1.S", 1, 0}, + {"PT-1.S", -1, 0}, + + {"P0D", 0, 0}, + {"P0DT0H", 0, 0}, + {"P0DT0M", 0, 0}, + {"P0DT0S", 0, 0}, + {"P0DT0H0S", 0, 0}, + {"P0DT0M0S", 0, 0}, + {"P0DT0H0M0S", 0, 0}, + + {"P1D", 86400, 0}, + {"P1DT0H", 86400, 0}, + {"P1DT0M", 86400, 0}, + {"P1DT0S", 86400, 0}, + {"P1DT0H0S", 86400, 0}, + {"P1DT0M0S", 86400, 0}, + {"P1DT0H0M0S", 86400, 0}, + + {"P3D", 86400 * 3, 0}, + {"P3DT2H", 86400 * 3 + 3600 * 2, 0}, + {"P3DT2M", 86400 * 3 + 60 * 2, 0}, + {"P3DT2S", 86400 * 3 + 2, 0}, + {"P3DT2H1S", 86400 * 3 + 3600 * 2 + 1, 0}, + {"P3DT2M1S", 86400 * 3 + 60 * 2 + 1, 0}, + {"P3DT2H1M1S", 86400 * 3 + 3600 * 2 + 60 + 1, 0}, + + {"P-3D", -86400 * 3, 0}, + {"P-3DT2H", -86400 * 3 + 3600 * 2, 0}, + {"P-3DT2M", -86400 * 3 + 60 * 2, 0}, + {"P-3DT2S", -86400 * 3 + 2, 0}, + {"P-3DT2H1S", -86400 * 3 + 3600 * 2 + 1, 0}, + {"P-3DT2M1S", -86400 * 3 + 60 * 2 + 1, 0}, + {"P-3DT2H1M1S", -86400 * 3 + 3600 * 2 + 60 + 1, 0}, + + {"P-3DT-2H", -86400 * 3 - 3600 * 2, 0}, + {"P-3DT-2M", -86400 * 3 - 60 * 2, 0}, + {"P-3DT-2S", -86400 * 3 - 2, 0}, + {"P-3DT-2H1S", -86400 * 3 - 3600 * 2 + 1, 0}, + {"P-3DT-2M1S", -86400 * 3 - 60 * 2 + 1, 0}, + {"P-3DT-2H1M1S", -86400 * 3 - 3600 * 2 + 60 + 1, 0}, + + {"PT0H", 0, 0}, + {"PT0H0M", 0, 0}, + {"PT0H0S", 0, 0}, + {"PT0H0M0S", 0, 0}, + + {"PT1H", 3600, 0}, + {"PT3H", 3600 * 3, 0}, + {"PT-1H", -3600, 0}, + {"PT-3H", -3600 * 3, 0}, + + {"PT2H5M", 3600 * 2 + 60 * 5, 0}, + {"PT2H5S", 3600 * 2 + 5, 0}, + {"PT2H5M8S", 3600 * 2 + 60 * 5 + 8, 0}, + {"PT-2H5M", -3600 * 2 + 60 * 5, 0}, + {"PT-2H5S", -3600 * 2 + 5, 0}, + {"PT-2H5M8S", -3600 * 2 + 60 * 5 + 8, 0}, + {"PT-2H-5M", -3600 * 2 - 60 * 5, 0}, + {"PT-2H-5S", -3600 * 2 - 5, 0}, + {"PT-2H-5M8S", -3600 * 2 - 60 * 5 + 8, 0}, + {"PT-2H-5M-8S", -3600 * 2 - 60 * 5 - 8, 0}, + + {"PT0M", 0, 0}, + {"PT1M", 60, 0}, + {"PT3M", 60 * 3, 0}, + {"PT-1M", -60, 0}, + {"PT-3M", -60 * 3, 0}, + {"P0DT3M", 60 * 3, 0}, + {"P0DT-3M", -60 * 3, 0}, }; } - @Test(dataProvider="Parse", groups={"tck"}) + @Test(dataProvider="parseSuccess") public void factory_parse(String text, long expectedSeconds, int expectedNanoOfSecond) { - Duration t = Duration.parse(text); - assertEquals(t.getSeconds(), expectedSeconds); - assertEquals(t.getNano(), expectedNanoOfSecond); + Duration test = Duration.parse(text); + assertEquals(test.getSeconds(), expectedSeconds); + assertEquals(test.getNano(), expectedNanoOfSecond); } - @Test(dataProvider="Parse", groups={"tck"}) + @Test(dataProvider="parseSuccess") + public void factory_parse_plus(String text, long expectedSeconds, int expectedNanoOfSecond) { + Duration test = Duration.parse("+" + text); + assertEquals(test.getSeconds(), expectedSeconds); + assertEquals(test.getNano(), expectedNanoOfSecond); + } + + @Test(dataProvider="parseSuccess") + public void factory_parse_minus(String text, long expectedSeconds, int expectedNanoOfSecond) { + Duration test; + try { + test = Duration.parse("-" + text); + } catch (DateTimeParseException ex) { + assertEquals(expectedSeconds == Long.MIN_VALUE, true); + return; + } + // not inside try/catch or it breaks test + assertEquals(test, Duration.ofSeconds(expectedSeconds, expectedNanoOfSecond).negated()); + } + + @Test(dataProvider="parseSuccess") public void factory_parse_comma(String text, long expectedSeconds, int expectedNanoOfSecond) { text = text.replace('.', ','); - Duration t = Duration.parse(text); - assertEquals(t.getSeconds(), expectedSeconds); - assertEquals(t.getNano(), expectedNanoOfSecond); + Duration test = Duration.parse(text); + assertEquals(test.getSeconds(), expectedSeconds); + assertEquals(test.getNano(), expectedNanoOfSecond); } - @DataProvider(name="ParseFailures") - Object[][] provider_factory_parseFailures() { + @Test(dataProvider="parseSuccess") + public void factory_parse_lowerCase(String text, long expectedSeconds, int expectedNanoOfSecond) { + Duration test = Duration.parse(text.toLowerCase(Locale.ENGLISH)); + assertEquals(test.getSeconds(), expectedSeconds); + assertEquals(test.getNano(), expectedNanoOfSecond); + } + + @DataProvider(name="parseFailure") + Object[][] data_parseFailure() { return new Object[][] { - {""}, - {"PTS"}, - {"AT0S"}, - {"PA0S"}, - {"PT0A"}, + {""}, + {"ABCDEF"}, + {" PT0S"}, + {"PT0S "}, - {"PT+S"}, - {"PT-S"}, - {"PT.S"}, - {"PTAS"}, + {"PTS"}, + {"AT0S"}, + {"PA0S"}, + {"PT0A"}, - {"PT+0S"}, - {"PT+00S"}, - {"PT+000S"}, - {"PT-0S"}, - {"PT-00S"}, - {"PT-000S"}, - {"PT+1S"}, - {"PT-.S"}, - {"PT+.S"}, + {"P0Y"}, + {"P1Y"}, + {"P-2Y"}, + {"P0M"}, + {"P1M"}, + {"P-2M"}, + {"P3Y2D"}, + {"P3M2D"}, + {"P3W"}, + {"P-3W"}, + {"P2YT30S"}, + {"P2MT30S"}, - {"PT1ABC2S"}, - {"PT1.1ABC2S"}, + {"P1DT"}, - {"PT123456789123456789123456789S"}, - {"PT0.1234567891S"}, - {"PT1.S"}, - {"PT.1S"}, + {"PT+S"}, + {"PT-S"}, + {"PT.S"}, + {"PTAS"}, - {"PT2.-3"}, - {"PT-2.-3"}, - {"PT2.+3"}, - {"PT-2.+3"}, + {"PT-.S"}, + {"PT+.S"}, + + {"PT1ABC2S"}, + {"PT1.1ABC2S"}, + + {"PT123456789123456789123456789S"}, + {"PT0.1234567891S"}, + + {"PT2.-3"}, + {"PT-2.-3"}, + {"PT2.+3"}, + {"PT-2.+3"}, }; } - @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class, groups={"tck"}) + @Test(dataProvider="parseFailure", expectedExceptions=DateTimeParseException.class) public void factory_parseFailures(String text) { Duration.parse(text); } - @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class, groups={"tck"}) + @Test(dataProvider="parseFailure", expectedExceptions=DateTimeParseException.class) public void factory_parseFailures_comma(String text) { text = text.replace('.', ','); Duration.parse(text); } - @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + @Test(expectedExceptions=DateTimeParseException.class) public void factory_parse_tooBig() { Duration.parse("PT" + Long.MAX_VALUE + "1S"); } - @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + @Test(expectedExceptions=DateTimeParseException.class) public void factory_parse_tooBig_decimal() { Duration.parse("PT" + Long.MAX_VALUE + "1.1S"); } - @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + @Test(expectedExceptions=DateTimeParseException.class) public void factory_parse_tooSmall() { Duration.parse("PT" + Long.MIN_VALUE + "1S"); } - @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) + @Test(expectedExceptions=DateTimeParseException.class) public void factory_parse_tooSmall_decimal() { Duration.parse("PT" + Long.MIN_VALUE + ".1S"); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void factory_parse_nullText() { - Duration.parse((String) null); + Duration.parse(null); } - @Test(groups={"tck"}) + //----------------------------------------------------------------------- + @Test public void test_deserialization() throws Exception { Duration orginal = Duration.ofSeconds(2); ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -620,7 +765,7 @@ public class TCKDuration extends AbstractTCKTest { //----------------------------------------------------------------------- // isZero(), isPositive(), isPositiveOrZero(), isNegative(), isNegativeOrZero() //----------------------------------------------------------------------- - @Test(groups={"tck"}) + @Test public void test_isZero() { assertEquals(Duration.ofNanos(0).isZero(), true); assertEquals(Duration.ofSeconds(0).isZero(), true); @@ -632,19 +777,7 @@ public class TCKDuration extends AbstractTCKTest { assertEquals(Duration.ofSeconds(-1, -1).isZero(), false); } - @Test(groups={"tck"}) - public void test_isPositive() { - assertEquals(Duration.ofNanos(0).isPositive(), false); - assertEquals(Duration.ofSeconds(0).isPositive(), false); - assertEquals(Duration.ofNanos(1).isPositive(), true); - assertEquals(Duration.ofSeconds(1).isPositive(), true); - assertEquals(Duration.ofSeconds(1, 1).isPositive(), true); - assertEquals(Duration.ofNanos(-1).isPositive(), false); - assertEquals(Duration.ofSeconds(-1).isPositive(), false); - assertEquals(Duration.ofSeconds(-1, -1).isPositive(), false); - } - - @Test(groups={"tck"}) + @Test public void test_isNegative() { assertEquals(Duration.ofNanos(0).isNegative(), false); assertEquals(Duration.ofSeconds(0).isNegative(), false); @@ -1989,18 +2122,12 @@ public class TCKDuration extends AbstractTCKTest { Duration b = durations[j]; if (i < j) { assertEquals(a.compareTo(b)< 0, true, a + " <=> " + b); - assertEquals(a.isLessThan(b), true, a + " <=> " + b); - assertEquals(a.isGreaterThan(b), false, a + " <=> " + b); assertEquals(a.equals(b), false, a + " <=> " + b); } else if (i > j) { assertEquals(a.compareTo(b) > 0, true, a + " <=> " + b); - assertEquals(a.isLessThan(b), false, a + " <=> " + b); - assertEquals(a.isGreaterThan(b), true, a + " <=> " + b); assertEquals(a.equals(b), false, a + " <=> " + b); } else { assertEquals(a.compareTo(b), 0, a + " <=> " + b); - assertEquals(a.isLessThan(b), false, a + " <=> " + b); - assertEquals(a.isGreaterThan(b), false, a + " <=> " + b); assertEquals(a.equals(b), true, a + " <=> " + b); } } @@ -2013,18 +2140,6 @@ public class TCKDuration extends AbstractTCKTest { a.compareTo(null); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_isLessThan_ObjectNull() { - Duration a = Duration.ofSeconds(0L, 0); - a.isLessThan(null); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_isGreaterThan_ObjectNull() { - Duration a = Duration.ofSeconds(0L, 0); - a.isGreaterThan(null); - } - @Test(expectedExceptions=ClassCastException.class, groups={"tck"}) @SuppressWarnings({ "unchecked", "rawtypes" }) public void compareToNonDuration() { @@ -2096,7 +2211,7 @@ public class TCKDuration extends AbstractTCKTest { //----------------------------------------------------------------------- // toString() //----------------------------------------------------------------------- - @DataProvider(name="ToString") + @DataProvider(name="toString") Object[][] provider_toString() { return new Object[][] { {0, 0, "PT0S"}, @@ -2118,18 +2233,72 @@ public class TCKDuration extends AbstractTCKTest { {0, 123456780, "PT0.12345678S"}, {0, 123456789, "PT0.123456789S"}, {1, 0, "PT1S"}, + {59, 0, "PT59S"}, + {60, 0, "PT1M"}, + {61, 0, "PT1M1S"}, + {3599, 0, "PT59M59S"}, + {3600, 0, "PT1H"}, + {3601, 0, "PT1H1S"}, + {3661, 0, "PT1H1M1S"}, + {86399, 0, "PT23H59M59S"}, + {86400, 0, "PT24H"}, + {59, 0, "PT59S"}, + {59, 0, "PT59S"}, {-1, 0, "PT-1S"}, {-1, 1000, "PT-0.999999S"}, {-1, 900000000, "PT-0.1S"}, - {Long.MAX_VALUE, 0, "PT9223372036854775807S"}, - {Long.MIN_VALUE, 0, "PT-9223372036854775808S"}, + {Long.MAX_VALUE, 0, "PT" + (Long.MAX_VALUE / 3600) + "H" + + ((Long.MAX_VALUE % 3600) / 60) + "M" + (Long.MAX_VALUE % 60) + "S"}, + {Long.MIN_VALUE, 0, "PT" + (Long.MIN_VALUE / 3600) + "H" + + ((Long.MIN_VALUE % 3600) / 60) + "M" + (Long.MIN_VALUE % 60) + "S"}, }; } - @Test(dataProvider="ToString", groups={"tck"}) + @Test(dataProvider="toString") public void test_toString(long seconds, int nanos, String expected) { Duration t = Duration.ofSeconds(seconds, nanos); assertEquals(t.toString(), expected); } + //----------------------------------------------------------------------- + @Test(groups="{tck}") + public void test_duration_getUnits() { + Duration duration = Duration.ofSeconds(5000, 1000); + List units = duration.getUnits(); + assertEquals(units.size(), 2, "Period.getUnits length"); + assertTrue(units.contains(ChronoUnit.SECONDS), "Period.getUnits contains ChronoUnit.SECONDS"); + assertTrue(units.contains(ChronoUnit.NANOS), "contains ChronoUnit.NANOS"); + } + + @Test() + public void test_getUnit() { + Duration test = Duration.ofSeconds(2000, 1000); + long seconds = test.get(ChronoUnit.SECONDS); + assertEquals(seconds, 2000, "duration.get(SECONDS)"); + long nanos = test.get(ChronoUnit.NANOS); + assertEquals(nanos, 1000, "duration.get(NANOS)"); + } + + @DataProvider(name="BadTemporalUnit") + Object[][] provider_factory_of_badTemporalUnit() { + return new Object[][] { + {0, MICROS}, + {0, MILLIS}, + {0, MINUTES}, + {0, HOURS}, + {0, HALF_DAYS}, + {0, DAYS}, + {0, ChronoUnit.MONTHS}, + {0, ChronoUnit.YEARS}, + {0, ChronoUnit.DECADES}, + {0, ChronoUnit.CENTURIES}, + {0, ChronoUnit.MILLENNIA}, + }; + } + + @Test(dataProvider="BadTemporalUnit", expectedExceptions=DateTimeException.class) + public void test_bad_getUnit(long amount, TemporalUnit unit) { + Duration t = Duration.of(amount, unit); + long actual = t.get(unit); + } } diff --git a/jdk/test/java/time/tck/java/time/TCKInstant.java b/jdk/test/java/time/tck/java/time/TCKInstant.java index e1f99d925ed..0dd745d88e5 100644 --- a/jdk/test/java/time/tck/java/time/TCKInstant.java +++ b/jdk/test/java/time/tck/java/time/TCKInstant.java @@ -64,30 +64,42 @@ import static java.time.temporal.ChronoField.MICRO_OF_SECOND; import static java.time.temporal.ChronoField.MILLI_OF_SECOND; import static java.time.temporal.ChronoField.NANO_OF_SECOND; import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.HOURS; +import static java.time.temporal.ChronoUnit.MICROS; +import static java.time.temporal.ChronoUnit.MILLIS; +import static java.time.temporal.ChronoUnit.MINUTES; +import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.NANOS; import static java.time.temporal.ChronoUnit.SECONDS; +import static java.time.temporal.ChronoUnit.WEEKS; +import static java.time.temporal.ChronoUnit.YEARS; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; - import java.time.Clock; import java.time.DateTimeException; import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; +import java.time.OffsetDateTime; import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; import java.time.temporal.JulianFields; import java.time.temporal.Queries; +import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalUnit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; @@ -396,34 +408,27 @@ public class TCKInstant extends AbstractDateTimeTest { //----------------------------------------------------------------------- // query(TemporalQuery) //----------------------------------------------------------------------- - @Test - public void test_query_chrono() { - assertEquals(TEST_12345_123456789.query(Queries.chrono()), null); - assertEquals(Queries.chrono().queryFrom(TEST_12345_123456789), null); + @DataProvider(name="query") + Object[][] data_query() { + return new Object[][] { + {TEST_12345_123456789, Queries.chronology(), null}, + {TEST_12345_123456789, Queries.zoneId(), null}, + {TEST_12345_123456789, Queries.precision(), NANOS}, + {TEST_12345_123456789, Queries.zone(), null}, + {TEST_12345_123456789, Queries.offset(), null}, + {TEST_12345_123456789, Queries.localDate(), null}, + {TEST_12345_123456789, Queries.localTime(), null}, + }; } - @Test - public void test_query_zoneId() { - assertEquals(TEST_12345_123456789.query(Queries.zoneId()), null); - assertEquals(Queries.zoneId().queryFrom(TEST_12345_123456789), null); + @Test(dataProvider="query") + public void test_query(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(temporal.query(query), expected); } - @Test - public void test_query_precision() { - assertEquals(TEST_12345_123456789.query(Queries.precision()), NANOS); - assertEquals(Queries.precision().queryFrom(TEST_12345_123456789), NANOS); - } - - @Test - public void test_query_offset() { - assertEquals(TEST_12345_123456789.query(Queries.offset()), null); - assertEquals(Queries.offset().queryFrom(TEST_12345_123456789), null); - } - - @Test - public void test_query_zone() { - assertEquals(TEST_12345_123456789.query(Queries.zone()), null); - assertEquals(Queries.zone().queryFrom(TEST_12345_123456789), null); + @Test(dataProvider="query") + public void test_queryFrom(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(query.queryFrom(temporal), expected); } @Test(expectedExceptions=NullPointerException.class) @@ -431,6 +436,147 @@ public class TCKInstant extends AbstractDateTimeTest { TEST_12345_123456789.query(null); } + //----------------------------------------------------------------------- + // truncated(TemporalUnit) + //----------------------------------------------------------------------- + TemporalUnit NINETY_MINS = new TemporalUnit() { + @Override + public String getName() { + return "NinetyMins"; + } + @Override + public Duration getDuration() { + return Duration.ofMinutes(90); + } + @Override + public boolean isDurationEstimated() { + return false; + } + @Override + public boolean isSupportedBy(Temporal temporal) { + return false; + } + @Override + public R addTo(R temporal, long amount) { + throw new UnsupportedOperationException(); + } + @Override + public long between(Temporal temporal1, Temporal temporal2) { + throw new UnsupportedOperationException(); + } + }; + + TemporalUnit NINETY_FIVE_MINS = new TemporalUnit() { + @Override + public String getName() { + return "NinetyFiveMins"; + } + @Override + public Duration getDuration() { + return Duration.ofMinutes(95); + } + @Override + public boolean isDurationEstimated() { + return false; + } + @Override + public boolean isSupportedBy(Temporal temporal) { + return false; + } + @Override + public R addTo(R temporal, long amount) { + throw new UnsupportedOperationException(); + } + @Override + public long between(Temporal temporal1, Temporal temporal2) { + throw new UnsupportedOperationException(); + } + }; + + @DataProvider(name="truncatedToValid") + Object[][] data_truncatedToValid() { + return new Object[][] { + {Instant.ofEpochSecond(86400 + 3600 + 60 + 1, 123_456_789), NANOS, Instant.ofEpochSecond(86400 + 3600 + 60 + 1, 123_456_789)}, + {Instant.ofEpochSecond(86400 + 3600 + 60 + 1, 123_456_789), MICROS, Instant.ofEpochSecond(86400 + 3600 + 60 + 1, 123_456_000)}, + {Instant.ofEpochSecond(86400 + 3600 + 60 + 1, 123_456_789), MILLIS, Instant.ofEpochSecond(86400 + 3600 + 60 + 1, 1230_00_000)}, + {Instant.ofEpochSecond(86400 + 3600 + 60 + 1, 123_456_789), SECONDS, Instant.ofEpochSecond(86400 + 3600 + 60 + 1, 0)}, + {Instant.ofEpochSecond(86400 + 3600 + 60 + 1, 123_456_789), MINUTES, Instant.ofEpochSecond(86400 + 3600 + 60, 0)}, + {Instant.ofEpochSecond(86400 + 3600 + 60 + 1, 123_456_789), HOURS, Instant.ofEpochSecond(86400 + 3600, 0)}, + {Instant.ofEpochSecond(86400 + 3600 + 60 + 1, 123_456_789), DAYS, Instant.ofEpochSecond(86400, 0)}, + + {Instant.ofEpochSecond(86400 + 3600 + 60 + 1, 123_456_789), NINETY_MINS, Instant.ofEpochSecond(86400 + 0, 0)}, + {Instant.ofEpochSecond(86400 + 7200 + 60 + 1, 123_456_789), NINETY_MINS, Instant.ofEpochSecond(86400 + 5400, 0)}, + {Instant.ofEpochSecond(86400 + 10800 + 60 + 1, 123_456_789), NINETY_MINS, Instant.ofEpochSecond(86400 + 10800, 0)}, + }; + } + @Test(groups={"tck"}, dataProvider="truncatedToValid") + public void test_truncatedTo_valid(Instant input, TemporalUnit unit, Instant expected) { + assertEquals(input.truncatedTo(unit), expected); + } + + @DataProvider(name="truncatedToInvalid") + Object[][] data_truncatedToInvalid() { + return new Object[][] { + {Instant.ofEpochSecond(1, 123_456_789), NINETY_FIVE_MINS}, + {Instant.ofEpochSecond(1, 123_456_789), WEEKS}, + {Instant.ofEpochSecond(1, 123_456_789), MONTHS}, + {Instant.ofEpochSecond(1, 123_456_789), YEARS}, + }; + } + + @Test(groups={"tck"}, dataProvider="truncatedToInvalid", expectedExceptions=DateTimeException.class) + public void test_truncatedTo_invalid(Instant input, TemporalUnit unit) { + input.truncatedTo(unit); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void test_truncatedTo_null() { + TEST_12345_123456789.truncatedTo(null); + } + + //----------------------------------------------------------------------- + // plus(TemporalAmount) + //----------------------------------------------------------------------- + @DataProvider(name="plusTemporalAmount") + Object[][] data_plusTemporalAmount() { + return new Object[][] { + {DAYS, MockSimplePeriod.of(1, DAYS), 86401, 0}, + {HOURS, MockSimplePeriod.of(2, HOURS), 7201, 0}, + {MINUTES, MockSimplePeriod.of(4, MINUTES), 241, 0}, + {SECONDS, MockSimplePeriod.of(5, SECONDS), 6, 0}, + {NANOS, MockSimplePeriod.of(6, NANOS), 1, 6}, + {DAYS, MockSimplePeriod.of(10, DAYS), 864001, 0}, + {HOURS, MockSimplePeriod.of(11, HOURS), 39601, 0}, + {MINUTES, MockSimplePeriod.of(12, MINUTES), 721, 0}, + {SECONDS, MockSimplePeriod.of(13, SECONDS), 14, 0}, + {NANOS, MockSimplePeriod.of(14, NANOS), 1, 14}, + {SECONDS, Duration.ofSeconds(20, 40), 21, 40}, + {NANOS, Duration.ofSeconds(30, 300), 31, 300}, + }; + } + + @Test(dataProvider="plusTemporalAmount") + public void test_plusTemporalAmount(TemporalUnit unit, TemporalAmount amount, int seconds, int nanos) { + Instant inst = Instant.ofEpochMilli(1000); + Instant actual = inst.plus(amount); + Instant expected = Instant.ofEpochSecond(seconds, nanos); + assertEquals(actual, expected, "plus(TemporalAmount) failed"); + } + + @DataProvider(name="badTemporalAmount") + Object[][] data_badPlusTemporalAmount() { + return new Object[][] { + {MockSimplePeriod.of(2, YEARS)}, + {MockSimplePeriod.of(2, MONTHS)}, + }; + } + + @Test(dataProvider="badTemporalAmount",expectedExceptions=DateTimeException.class) + public void test_badPlusTemporalAmount(TemporalAmount amount) { + Instant inst = Instant.ofEpochMilli(1000); + inst.plus(amount); + } + //----------------------------------------------------------------------- @DataProvider(name="Plus") Object[][] provider_plus() { @@ -1433,6 +1579,50 @@ public class TCKInstant extends AbstractDateTimeTest { i.minusNanos(1); } + //----------------------------------------------------------------------- + // atOffset() + //----------------------------------------------------------------------- + @Test + public void test_atOffset() { + for (int i = 0; i < (24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i); + OffsetDateTime test = instant.atOffset(ZoneOffset.ofHours(1)); + assertEquals(test.getYear(), 1970); + assertEquals(test.getMonthValue(), 1); + assertEquals(test.getDayOfMonth(), 1 + (i >= 23 * 60 * 60 ? 1 : 0)); + assertEquals(test.getHour(), ((i / (60 * 60)) + 1) % 24); + assertEquals(test.getMinute(), (i / 60) % 60); + assertEquals(test.getSecond(), i % 60); + } + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_atOffset_null() { + TEST_12345_123456789.atOffset(null); + } + + //----------------------------------------------------------------------- + // atZone() + //----------------------------------------------------------------------- + @Test + public void test_atZone() { + for (int i = 0; i < (24 * 60 * 60); i++) { + Instant instant = Instant.ofEpochSecond(i); + ZonedDateTime test = instant.atZone(ZoneOffset.ofHours(1)); + assertEquals(test.getYear(), 1970); + assertEquals(test.getMonthValue(), 1); + assertEquals(test.getDayOfMonth(), 1 + (i >= 23 * 60 * 60 ? 1 : 0)); + assertEquals(test.getHour(), ((i / (60 * 60)) + 1) % 24); + assertEquals(test.getMinute(), (i / 60) % 60); + assertEquals(test.getSecond(), i % 60); + } + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_atZone_null() { + TEST_12345_123456789.atZone(null); + } + //----------------------------------------------------------------------- // toEpochMilli() //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKLocalDate.java b/jdk/test/java/time/tck/java/time/TCKLocalDate.java index 721da56d36b..48b69385bd0 100644 --- a/jdk/test/java/time/tck/java/time/TCKLocalDate.java +++ b/jdk/test/java/time/tck/java/time/TCKLocalDate.java @@ -80,11 +80,6 @@ import static org.testng.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import java.time.Clock; import java.time.DateTimeException; import java.time.DayOfWeek; @@ -93,24 +88,29 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Period; +import java.time.Year; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; -import java.time.temporal.ISOChrono; import java.time.temporal.JulianFields; -import java.time.temporal.OffsetDate; import java.time.temporal.Queries; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQuery; import java.time.temporal.TemporalUnit; -import java.time.temporal.Year; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; @@ -595,14 +595,14 @@ public class TCKLocalDate extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void factory_parse_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d"); LocalDate test = LocalDate.parse("2010 12 3", f); assertEquals(test, LocalDate.of(2010, 12, 3)); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void factory_parse_formatter_nullText() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d"); LocalDate.parse((String) null, f); } @@ -637,34 +637,27 @@ public class TCKLocalDate extends AbstractDateTimeTest { //----------------------------------------------------------------------- // query(TemporalQuery) //----------------------------------------------------------------------- - @Test - public void test_query_chrono() { - assertEquals(TEST_2007_07_15.query(Queries.chrono()), ISOChrono.INSTANCE); - assertEquals(Queries.chrono().queryFrom(TEST_2007_07_15), ISOChrono.INSTANCE); + @DataProvider(name="query") + Object[][] data_query() { + return new Object[][] { + {TEST_2007_07_15, Queries.chronology(), IsoChronology.INSTANCE}, + {TEST_2007_07_15, Queries.zoneId(), null}, + {TEST_2007_07_15, Queries.precision(), ChronoUnit.DAYS}, + {TEST_2007_07_15, Queries.zone(), null}, + {TEST_2007_07_15, Queries.offset(), null}, + {TEST_2007_07_15, Queries.localDate(), TEST_2007_07_15}, + {TEST_2007_07_15, Queries.localTime(), null}, + }; } - @Test - public void test_query_zoneId() { - assertEquals(TEST_2007_07_15.query(Queries.zoneId()), null); - assertEquals(Queries.zoneId().queryFrom(TEST_2007_07_15), null); + @Test(dataProvider="query") + public void test_query(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(temporal.query(query), expected); } - @Test - public void test_query_precision() { - assertEquals(TEST_2007_07_15.query(Queries.precision()), ChronoUnit.DAYS); - assertEquals(Queries.precision().queryFrom(TEST_2007_07_15), ChronoUnit.DAYS); - } - - @Test - public void test_query_offset() { - assertEquals(TEST_2007_07_15.query(Queries.offset()), null); - assertEquals(Queries.offset().queryFrom(TEST_2007_07_15), null); - } - - @Test - public void test_query_zone() { - assertEquals(TEST_2007_07_15.query(Queries.zone()), null); - assertEquals(Queries.zone().queryFrom(TEST_2007_07_15), null); + @Test(dataProvider="query") + public void test_queryFrom(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(query.queryFrom(temporal), expected); } @Test(expectedExceptions=NullPointerException.class) @@ -1628,6 +1621,117 @@ public class TCKLocalDate extends AbstractDateTimeTest { LocalDate.of(Year.MIN_VALUE, 1, 1).minusDays(Long.MAX_VALUE); } + //----------------------------------------------------------------------- + // periodUntil(ChronoLocalDate) + //----------------------------------------------------------------------- + @DataProvider(name="periodUntil") + Object[][] data_periodUntil() { + return new Object[][] { + {2010, 1, 1, 2010, 1, 1, 0, 0, 0}, + {2010, 1, 1, 2010, 1, 2, 0, 0, 1}, + {2010, 1, 1, 2010, 1, 31, 0, 0, 30}, + {2010, 1, 1, 2010, 2, 1, 0, 1, 0}, + {2010, 1, 1, 2010, 2, 28, 0, 1, 27}, + {2010, 1, 1, 2010, 3, 1, 0, 2, 0}, + {2010, 1, 1, 2010, 12, 31, 0, 11, 30}, + {2010, 1, 1, 2011, 1, 1, 1, 0, 0}, + {2010, 1, 1, 2011, 12, 31, 1, 11, 30}, + {2010, 1, 1, 2012, 1, 1, 2, 0, 0}, + + {2010, 1, 10, 2010, 1, 1, 0, 0, -9}, + {2010, 1, 10, 2010, 1, 2, 0, 0, -8}, + {2010, 1, 10, 2010, 1, 9, 0, 0, -1}, + {2010, 1, 10, 2010, 1, 10, 0, 0, 0}, + {2010, 1, 10, 2010, 1, 11, 0, 0, 1}, + {2010, 1, 10, 2010, 1, 31, 0, 0, 21}, + {2010, 1, 10, 2010, 2, 1, 0, 0, 22}, + {2010, 1, 10, 2010, 2, 9, 0, 0, 30}, + {2010, 1, 10, 2010, 2, 10, 0, 1, 0}, + {2010, 1, 10, 2010, 2, 28, 0, 1, 18}, + {2010, 1, 10, 2010, 3, 1, 0, 1, 19}, + {2010, 1, 10, 2010, 3, 9, 0, 1, 27}, + {2010, 1, 10, 2010, 3, 10, 0, 2, 0}, + {2010, 1, 10, 2010, 12, 31, 0, 11, 21}, + {2010, 1, 10, 2011, 1, 1, 0, 11, 22}, + {2010, 1, 10, 2011, 1, 9, 0, 11, 30}, + {2010, 1, 10, 2011, 1, 10, 1, 0, 0}, + + {2010, 3, 30, 2011, 5, 1, 1, 1, 1}, + {2010, 4, 30, 2011, 5, 1, 1, 0, 1}, + + {2010, 2, 28, 2012, 2, 27, 1, 11, 30}, + {2010, 2, 28, 2012, 2, 28, 2, 0, 0}, + {2010, 2, 28, 2012, 2, 29, 2, 0, 1}, + + {2012, 2, 28, 2014, 2, 27, 1, 11, 30}, + {2012, 2, 28, 2014, 2, 28, 2, 0, 0}, + {2012, 2, 28, 2014, 3, 1, 2, 0, 1}, + + {2012, 2, 29, 2014, 2, 28, 1, 11, 30}, + {2012, 2, 29, 2014, 3, 1, 2, 0, 1}, + {2012, 2, 29, 2014, 3, 2, 2, 0, 2}, + + {2012, 2, 29, 2016, 2, 28, 3, 11, 30}, + {2012, 2, 29, 2016, 2, 29, 4, 0, 0}, + {2012, 2, 29, 2016, 3, 1, 4, 0, 1}, + + {2010, 1, 1, 2009, 12, 31, 0, 0, -1}, + {2010, 1, 1, 2009, 12, 30, 0, 0, -2}, + {2010, 1, 1, 2009, 12, 2, 0, 0, -30}, + {2010, 1, 1, 2009, 12, 1, 0, -1, 0}, + {2010, 1, 1, 2009, 11, 30, 0, -1, -1}, + {2010, 1, 1, 2009, 11, 2, 0, -1, -29}, + {2010, 1, 1, 2009, 11, 1, 0, -2, 0}, + {2010, 1, 1, 2009, 1, 2, 0, -11, -30}, + {2010, 1, 1, 2009, 1, 1, -1, 0, 0}, + + {2010, 1, 15, 2010, 1, 15, 0, 0, 0}, + {2010, 1, 15, 2010, 1, 14, 0, 0, -1}, + {2010, 1, 15, 2010, 1, 1, 0, 0, -14}, + {2010, 1, 15, 2009, 12, 31, 0, 0, -15}, + {2010, 1, 15, 2009, 12, 16, 0, 0, -30}, + {2010, 1, 15, 2009, 12, 15, 0, -1, 0}, + {2010, 1, 15, 2009, 12, 14, 0, -1, -1}, + + {2010, 2, 28, 2009, 3, 1, 0, -11, -27}, + {2010, 2, 28, 2009, 2, 28, -1, 0, 0}, + {2010, 2, 28, 2009, 2, 27, -1, 0, -1}, + + {2010, 2, 28, 2008, 2, 29, -1, -11, -28}, + {2010, 2, 28, 2008, 2, 28, -2, 0, 0}, + {2010, 2, 28, 2008, 2, 27, -2, 0, -1}, + + {2012, 2, 29, 2009, 3, 1, -2, -11, -28}, + {2012, 2, 29, 2009, 2, 28, -3, 0, -1}, + {2012, 2, 29, 2009, 2, 27, -3, 0, -2}, + + {2012, 2, 29, 2008, 3, 1, -3, -11, -28}, + {2012, 2, 29, 2008, 2, 29, -4, 0, 0}, + {2012, 2, 29, 2008, 2, 28, -4, 0, -1}, + }; + } + + @Test(dataProvider="periodUntil") + public void test_periodUntil_LocalDate(int y1, int m1, int d1, int y2, int m2, int d2, int ye, int me, int de) { + LocalDate start = LocalDate.of(y1, m1, d1); + LocalDate end = LocalDate.of(y2, m2, d2); + Period test = start.periodUntil(end); + assertEquals(test.getYears(), ye); + assertEquals(test.getMonths(), me); + assertEquals(test.getDays(), de); + } + + @Test + public void test_periodUntil_LocalDate_max() { + int years = Math.toIntExact((long) Year.MAX_VALUE - (long) Year.MIN_VALUE); + assertEquals(LocalDate.MIN.periodUntil(LocalDate.MAX), Period.of(years, 11, 30)); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_periodUntil_LocalDate_null() { + TEST_2007_07_15.periodUntil(null); + } + //----------------------------------------------------------------------- // atTime() //----------------------------------------------------------------------- @@ -1770,40 +1874,54 @@ public class TCKLocalDate extends AbstractDateTimeTest { t.atTime(11, 30, 40, 1000000000); } - //----------------------------------------------------------------------- - // atOffset() //----------------------------------------------------------------------- @Test(groups={"tck"}) - public void test_atOffset() { + public void test_atTime_OffsetTime() { LocalDate t = LocalDate.of(2008, 6, 30); - assertEquals(t.atOffset(OFFSET_PTWO), OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO)); + assertEquals(t.atTime(OffsetTime.of(11, 30, 0, 0, OFFSET_PONE)), OffsetDateTime.of(2008, 6, 30, 11, 30, 0, 0, OFFSET_PONE)); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_atOffset_nullZoneOffset() { + public void test_atTime_OffsetTime_null() { LocalDate t = LocalDate.of(2008, 6, 30); - t.atOffset((ZoneOffset) null); + t.atTime((OffsetTime) null); } //----------------------------------------------------------------------- // atStartOfDay() //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_atStartOfDay() { - LocalDate t = LocalDate.of(2008, 6, 30); - assertEquals(t.atStartOfDay(ZONE_PARIS), - ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 0, 0), ZONE_PARIS)); + @DataProvider(name="atStartOfDay") + Object[][] data_atStartOfDay() { + return new Object[][] { + {LocalDate.of(2008, 6, 30), LocalDateTime.of(2008, 6, 30, 0, 0)}, + {LocalDate.of(-12, 6, 30), LocalDateTime.of(-12, 6, 30, 0, 0)}, + }; } - @Test(groups={"tck"}) - public void test_atStartOfDay_dstGap() { - LocalDate t = LocalDate.of(2007, 4, 1); - assertEquals(t.atStartOfDay(ZONE_GAZA), - ZonedDateTime.of(LocalDateTime.of(2007, 4, 1, 1, 0), ZONE_GAZA)); + @Test(dataProvider="atStartOfDay") + public void test_atStartOfDay(LocalDate test, LocalDateTime expected) { + assertEquals(test.atStartOfDay(), expected); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_atStartOfDay_nullTimeZone() { + //----------------------------------------------------------------------- + // atStartOfDay(ZoneId) + //----------------------------------------------------------------------- + @DataProvider(name="atStartOfDayZoneId") + Object[][] data_atStartOfDayZoneId() { + return new Object[][] { + {LocalDate.of(2008, 6, 30), ZONE_PARIS, ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 0, 0), ZONE_PARIS)}, + {LocalDate.of(2008, 6, 30), OFFSET_PONE, ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 0, 0), OFFSET_PONE)}, + {LocalDate.of(2007, 4, 1), ZONE_GAZA, ZonedDateTime.of(LocalDateTime.of(2007, 4, 1, 1, 0), ZONE_GAZA)}, + }; + } + + @Test(dataProvider="atStartOfDayZoneId") + public void test_atStartOfDay_ZoneId(LocalDate test, ZoneId zone, ZonedDateTime expected) { + assertEquals(test.atStartOfDay(zone), expected); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_atStartOfDay_ZoneId_null() { LocalDate t = LocalDate.of(2008, 6, 30); t.atStartOfDay((ZoneId) null); } @@ -2005,7 +2123,7 @@ public class TCKLocalDate extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_toString_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d"); String t = LocalDate.of(2010, 12, 3).toString(f); assertEquals(t, "2010 12 3"); } diff --git a/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java index 1fa08f3c93e..9b95fcd51b7 100644 --- a/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKLocalDateTime.java @@ -88,8 +88,10 @@ import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.NANOS; import static java.time.temporal.ChronoUnit.SECONDS; +import static java.time.temporal.ChronoUnit.YEARS; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertSame; @@ -97,12 +99,6 @@ import static org.testng.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - import java.time.Clock; import java.time.DateTimeException; import java.time.DayOfWeek; @@ -111,33 +107,33 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; -import java.time.Period; +import java.time.OffsetDateTime; +import java.time.Year; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; -import java.time.temporal.ISOChrono; import java.time.temporal.JulianFields; -import java.time.temporal.OffsetDateTime; import java.time.temporal.Queries; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalAdder; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; -import java.time.temporal.TemporalSubtractor; import java.time.temporal.TemporalUnit; -import java.time.temporal.Year; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import test.java.time.MockSimplePeriod; /** * Test LocalDateTime. @@ -280,12 +276,12 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { public void now() { LocalDateTime expected = LocalDateTime.now(Clock.systemDefaultZone()); LocalDateTime test = LocalDateTime.now(); - long diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay()); + long diff = Math.abs(test.toLocalTime().toNanoOfDay() - expected.toLocalTime().toNanoOfDay()); if (diff >= 100000000) { // may be date change expected = LocalDateTime.now(Clock.systemDefaultZone()); test = LocalDateTime.now(); - diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay()); + diff = Math.abs(test.toLocalTime().toNanoOfDay() - expected.toLocalTime().toNanoOfDay()); } assertTrue(diff < 100000000); // less than 0.1 secs } @@ -364,7 +360,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { assertEquals(test.getMonth(), Month.DECEMBER); assertEquals(test.getDayOfMonth(), 31); expected = expected.minusSeconds(1); - assertEquals(test.getTime(), expected); + assertEquals(test.toLocalTime(), expected); } } @@ -915,14 +911,14 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void factory_parse_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d H m s"); LocalDateTime test = LocalDateTime.parse("2010 12 3 11 30 45", f); assertEquals(test, LocalDateTime.of(2010, 12, 3, 11, 30, 45)); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void factory_parse_formatter_nullText() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d H m s"); LocalDateTime.parse((String) null, f); } @@ -971,34 +967,27 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- // query(TemporalQuery) //----------------------------------------------------------------------- - @Test - public void test_query_chrono() { - assertEquals(TEST_2007_07_15_12_30_40_987654321.query(Queries.chrono()), ISOChrono.INSTANCE); - assertEquals(Queries.chrono().queryFrom(TEST_2007_07_15_12_30_40_987654321), ISOChrono.INSTANCE); + @DataProvider(name="query") + Object[][] data_query() { + return new Object[][] { + {TEST_2007_07_15_12_30_40_987654321, Queries.chronology(), IsoChronology.INSTANCE}, + {TEST_2007_07_15_12_30_40_987654321, Queries.zoneId(), null}, + {TEST_2007_07_15_12_30_40_987654321, Queries.precision(), ChronoUnit.NANOS}, + {TEST_2007_07_15_12_30_40_987654321, Queries.zone(), null}, + {TEST_2007_07_15_12_30_40_987654321, Queries.offset(), null}, + {TEST_2007_07_15_12_30_40_987654321, Queries.localDate(), LocalDate.of(2007, 7, 15)}, + {TEST_2007_07_15_12_30_40_987654321, Queries.localTime(), LocalTime.of(12, 30, 40, 987654321)}, + }; } - @Test - public void test_query_zoneId() { - assertEquals(TEST_2007_07_15_12_30_40_987654321.query(Queries.zoneId()), null); - assertEquals(Queries.zoneId().queryFrom(TEST_2007_07_15_12_30_40_987654321), null); + @Test(dataProvider="query") + public void test_query(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(temporal.query(query), expected); } - @Test - public void test_query_precision() { - assertEquals(TEST_2007_07_15_12_30_40_987654321.query(Queries.precision()), NANOS); - assertEquals(Queries.precision().queryFrom(TEST_2007_07_15_12_30_40_987654321), NANOS); - } - - @Test - public void test_query_offset() { - assertEquals(TEST_2007_07_15_12_30_40_987654321.query(Queries.offset()), null); - assertEquals(Queries.offset().queryFrom(TEST_2007_07_15_12_30_40_987654321), null); - } - - @Test - public void test_query_zone() { - assertEquals(TEST_2007_07_15_12_30_40_987654321.query(Queries.zone()), null); - assertEquals(Queries.zone().queryFrom(TEST_2007_07_15_12_30_40_987654321), null); + @Test(dataProvider="query") + public void test_queryFrom(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(query.queryFrom(temporal), expected); } @Test(expectedExceptions=NullPointerException.class) @@ -1065,7 +1054,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_get_times(int h, int m, int s, int ns) { - LocalDateTime a = LocalDateTime.of(TEST_2007_07_15_12_30_40_987654321.getDate(), LocalTime.of(h, m, s, ns)); + LocalDateTime a = LocalDateTime.of(TEST_2007_07_15_12_30_40_987654321.toLocalDate(), LocalTime.of(h, m, s, ns)); assertEquals(a.getHour(), h); assertEquals(a.getMinute(), m); assertEquals(a.getSecond(), s); @@ -1082,7 +1071,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { int length = month.length(false); for (int i = 1; i <= length; i++) { LocalDateTime d = LocalDateTime.of(LocalDate.of(2007, month, i), - TEST_2007_07_15_12_30_40_987654321.getTime()); + TEST_2007_07_15_12_30_40_987654321.toLocalTime()); assertSame(d.getDayOfWeek(), dow); dow = dow.plus(1); } @@ -1297,54 +1286,39 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // plus(adjuster) + // plus(TemporalAmount) //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_plus_adjuster() { - Period p = Period.ofTime(0, 0, 62, 3); - LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(p); - assertEquals(t, LocalDateTime.of(2007, 7, 15, 12, 31, 42, 987654324)); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_plus_adjuster_null() { - TEST_2007_07_15_12_30_40_987654321.plus((TemporalAdder) null); - } - - //----------------------------------------------------------------------- - // plus(Period) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_plus_Period_positiveMonths() { - MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); + @Test + public void test_plus_TemporalAmount_positiveMonths() { + MockSimplePeriod period = MockSimplePeriod.of(7, MONTHS); LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(period); assertEquals(t, LocalDateTime.of(2008, 2, 15, 12, 30, 40, 987654321)); } - @Test(groups={"tck"}) - public void test_plus_Period_negativeDays() { - MockSimplePeriod period = MockSimplePeriod.of(-25, ChronoUnit.DAYS); + @Test + public void test_plus_TemporalAmount_negativeDays() { + MockSimplePeriod period = MockSimplePeriod.of(-25, DAYS); LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plus(period); assertEquals(t, LocalDateTime.of(2007, 6, 20, 12, 30, 40, 987654321)); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_plus_Period_null() { - TEST_2007_07_15_12_30_40_987654321.plus((MockSimplePeriod) null); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_plus_Period_invalidTooLarge() { - MockSimplePeriod period = MockSimplePeriod.of(1, ChronoUnit.YEARS); + @Test(expectedExceptions=DateTimeException.class) + public void test_plus_TemporalAmount_invalidTooLarge() { + MockSimplePeriod period = MockSimplePeriod.of(1, YEARS); LocalDateTime.of(Year.MAX_VALUE, 1, 1, 0, 0).plus(period); } - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_plus_Period_invalidTooSmall() { - MockSimplePeriod period = MockSimplePeriod.of(-1, ChronoUnit.YEARS); + @Test(expectedExceptions=DateTimeException.class) + public void test_plus_TemporalAmount_invalidTooSmall() { + MockSimplePeriod period = MockSimplePeriod.of(-1, YEARS); LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0).plus(period); } + @Test(expectedExceptions=NullPointerException.class) + public void test_plus_TemporalAmount_null() { + TEST_2007_07_15_12_30_40_987654321.plus((TemporalAmount) null); + } + //----------------------------------------------------------------------- // plus(long,TemporalUnit) //----------------------------------------------------------------------- @@ -1697,7 +1671,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_plusHours_one() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); - LocalDate d = t.getDate(); + LocalDate d = t.toLocalDate(); for (int i = 0; i < 50; i++) { t = t.plusHours(1); @@ -1706,7 +1680,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { d = d.plusDays(1); } - assertEquals(t.getDate(), d); + assertEquals(t.toLocalDate(), d); assertEquals(t.getHour(), (i + 1) % 24); } } @@ -1714,7 +1688,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_plusHours_fromZero() { LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); - LocalDate d = base.getDate().minusDays(3); + LocalDate d = base.toLocalDate().minusDays(3); LocalTime t = LocalTime.of(21, 0); for (int i = -50; i < 50; i++) { @@ -1725,15 +1699,15 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { d = d.plusDays(1); } - assertEquals(dt.getDate(), d); - assertEquals(dt.getTime(), t); + assertEquals(dt.toLocalDate(), d); + assertEquals(dt.toLocalTime(), t); } } @Test(groups={"tck"}) public void test_plusHours_fromOne() { LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(1, 0)); - LocalDate d = base.getDate().minusDays(3); + LocalDate d = base.toLocalDate().minusDays(3); LocalTime t = LocalTime.of(22, 0); for (int i = -50; i < 50; i++) { @@ -1745,8 +1719,8 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { d = d.plusDays(1); } - assertEquals(dt.getDate(), d); - assertEquals(dt.getTime(), t); + assertEquals(dt.toLocalDate(), d); + assertEquals(dt.toLocalTime(), t); } } @@ -1756,7 +1730,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_plusMinutes_one() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); - LocalDate d = t.getDate(); + LocalDate d = t.toLocalDate(); int hour = 0; int min = 0; @@ -1769,7 +1743,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { min = 0; } - assertEquals(t.getDate(), d); + assertEquals(t.toLocalDate(), d); assertEquals(t.getHour(), hour); assertEquals(t.getMinute(), min); } @@ -1778,7 +1752,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_plusMinutes_fromZero() { LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); - LocalDate d = base.getDate().minusDays(1); + LocalDate d = base.toLocalDate().minusDays(1); LocalTime t = LocalTime.of(22, 49); for (int i = -70; i < 70; i++) { @@ -1789,15 +1763,15 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { d = d.plusDays(1); } - assertEquals(dt.getDate(), d, String.valueOf(i)); - assertEquals(dt.getTime(), t, String.valueOf(i)); + assertEquals(dt.toLocalDate(), d, String.valueOf(i)); + assertEquals(dt.toLocalTime(), t, String.valueOf(i)); } } @Test(groups={"tck"}) public void test_plusMinutes_noChange_oneDay() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMinutes(24 * 60); - assertEquals(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate().plusDays(1)); + assertEquals(t.toLocalDate(), TEST_2007_07_15_12_30_40_987654321.toLocalDate().plusDays(1)); } //----------------------------------------------------------------------- @@ -1806,7 +1780,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_plusSeconds_one() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); - LocalDate d = t.getDate(); + LocalDate d = t.toLocalDate(); int hour = 0; int min = 0; @@ -1824,7 +1798,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { min = 0; } - assertEquals(t.getDate(), d); + assertEquals(t.toLocalDate(), d); assertEquals(t.getHour(), hour); assertEquals(t.getMinute(), min); assertEquals(t.getSecond(), sec); @@ -1837,7 +1811,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { int delta = 30; int i = -3660; - LocalDate date = TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1); + LocalDate date = TEST_2007_07_15_12_30_40_987654321.toLocalDate().minusDays(1); int hour = 22; int min = 59; int sec = 0; @@ -1883,7 +1857,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); LocalDateTime t = base.plusSeconds(seconds); - assertEquals(date, t.getDate()); + assertEquals(date, t.toLocalDate()); assertEquals(hour, t.getHour()); assertEquals(min, t.getMinute()); assertEquals(sec, t.getSecond()); @@ -1892,7 +1866,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_plusSeconds_noChange_oneDay() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusSeconds(24 * 60 * 60); - assertEquals(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate().plusDays(1)); + assertEquals(t.toLocalDate(), TEST_2007_07_15_12_30_40_987654321.toLocalDate().plusDays(1)); } //----------------------------------------------------------------------- @@ -1901,7 +1875,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_plusNanos_halfABillion() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); - LocalDate d = t.getDate(); + LocalDate d = t.toLocalDate(); int hour = 0; int min = 0; @@ -1924,7 +1898,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { min = 0; } - assertEquals(t.getDate(), d, String.valueOf(i)); + assertEquals(t.toLocalDate(), d, String.valueOf(i)); assertEquals(t.getHour(), hour); assertEquals(t.getMinute(), min); assertEquals(t.getSecond(), sec); @@ -1938,7 +1912,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { long delta = 7500000000L; long i = -3660 * 1000000000L; - LocalDate date = TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1); + LocalDate date = TEST_2007_07_15_12_30_40_987654321.toLocalDate().minusDays(1); int hour = 22; int min = 59; int sec = 0; @@ -1987,7 +1961,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); LocalDateTime t = base.plusNanos(nanoseconds); - assertEquals(date, t.getDate()); + assertEquals(date, t.toLocalDate()); assertEquals(hour, t.getHour()); assertEquals(min, t.getMinute()); assertEquals(sec, t.getSecond()); @@ -1997,58 +1971,43 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_plusNanos_noChange_oneDay() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusNanos(24 * 60 * 60 * 1000000000L); - assertEquals(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate().plusDays(1)); + assertEquals(t.toLocalDate(), TEST_2007_07_15_12_30_40_987654321.toLocalDate().plusDays(1)); } //----------------------------------------------------------------------- - // minus(adjuster) + // minus(TemporalAmount) //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_minus_adjuster() { - Period p = Period.ofTime(0, 0, 62, 3); - LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(p); - assertEquals(t, LocalDateTime.of(2007, 7, 15, 12, 29, 38, 987654318)); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_minus_adjuster_null() { - TEST_2007_07_15_12_30_40_987654321.minus((TemporalSubtractor) null); - } - - //----------------------------------------------------------------------- - // minus(Period) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_minus_Period_positiveMonths() { - MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); + @Test + public void test_minus_TemporalAmount_positiveMonths() { + MockSimplePeriod period = MockSimplePeriod.of(7, MONTHS); LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(period); assertEquals(t, LocalDateTime.of(2006, 12, 15, 12, 30, 40, 987654321)); } - @Test(groups={"tck"}) - public void test_minus_Period_negativeDays() { - MockSimplePeriod period = MockSimplePeriod.of(-25, ChronoUnit.DAYS); + @Test + public void test_minus_TemporalAmount_negativeDays() { + MockSimplePeriod period = MockSimplePeriod.of(-25, DAYS); LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minus(period); assertEquals(t, LocalDateTime.of(2007, 8, 9, 12, 30, 40, 987654321)); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_minus_Period_null() { - TEST_2007_07_15_12_30_40_987654321.minus((MockSimplePeriod) null); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_minus_Period_invalidTooLarge() { - MockSimplePeriod period = MockSimplePeriod.of(-1, ChronoUnit.YEARS); + @Test(expectedExceptions=DateTimeException.class) + public void test_minus_TemporalAmount_invalidTooLarge() { + MockSimplePeriod period = MockSimplePeriod.of(-1, YEARS); LocalDateTime.of(Year.MAX_VALUE, 1, 1, 0, 0).minus(period); } - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_minus_Period_invalidTooSmall() { - MockSimplePeriod period = MockSimplePeriod.of(1, ChronoUnit.YEARS); + @Test(expectedExceptions=DateTimeException.class) + public void test_minus_TemporalAmount_invalidTooSmall() { + MockSimplePeriod period = MockSimplePeriod.of(1, YEARS); LocalDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0).minus(period); } + @Test(expectedExceptions=NullPointerException.class) + public void test_minus_TemporalAmount_null() { + TEST_2007_07_15_12_30_40_987654321.minus((TemporalAmount) null); + } + //----------------------------------------------------------------------- // minus(long,TemporalUnit) //----------------------------------------------------------------------- @@ -2401,7 +2360,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_minusHours_one() { LocalDateTime t =TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); - LocalDate d = t.getDate(); + LocalDate d = t.toLocalDate(); for (int i = 0; i < 50; i++) { t = t.minusHours(1); @@ -2410,7 +2369,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { d = d.minusDays(1); } - assertEquals(t.getDate(), d); + assertEquals(t.toLocalDate(), d); assertEquals(t.getHour(), (((-i + 23) % 24) + 24) % 24); } } @@ -2418,7 +2377,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_minusHours_fromZero() { LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); - LocalDate d = base.getDate().plusDays(2); + LocalDate d = base.toLocalDate().plusDays(2); LocalTime t = LocalTime.of(3, 0); for (int i = -50; i < 50; i++) { @@ -2429,15 +2388,15 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { d = d.minusDays(1); } - assertEquals(dt.getDate(), d, String.valueOf(i)); - assertEquals(dt.getTime(), t); + assertEquals(dt.toLocalDate(), d, String.valueOf(i)); + assertEquals(dt.toLocalTime(), t); } } @Test(groups={"tck"}) public void test_minusHours_fromOne() { LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(1, 0)); - LocalDate d = base.getDate().plusDays(2); + LocalDate d = base.toLocalDate().plusDays(2); LocalTime t = LocalTime.of(4, 0); for (int i = -50; i < 50; i++) { @@ -2449,8 +2408,8 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { d = d.minusDays(1); } - assertEquals(dt.getDate(), d, String.valueOf(i)); - assertEquals(dt.getTime(), t); + assertEquals(dt.toLocalDate(), d, String.valueOf(i)); + assertEquals(dt.toLocalTime(), t); } } @@ -2460,7 +2419,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_minusMinutes_one() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); - LocalDate d = t.getDate().minusDays(1); + LocalDate d = t.toLocalDate().minusDays(1); int hour = 0; int min = 0; @@ -2476,7 +2435,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { hour = 23; } } - assertEquals(t.getDate(), d); + assertEquals(t.toLocalDate(), d); assertEquals(t.getHour(), hour); assertEquals(t.getMinute(), min); } @@ -2485,7 +2444,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_minusMinutes_fromZero() { LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); - LocalDate d = base.getDate().minusDays(1); + LocalDate d = base.toLocalDate().minusDays(1); LocalTime t = LocalTime.of(22, 49); for (int i = 70; i > -70; i--) { @@ -2496,15 +2455,15 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { d = d.plusDays(1); } - assertEquals(dt.getDate(), d); - assertEquals(dt.getTime(), t); + assertEquals(dt.toLocalDate(), d); + assertEquals(dt.toLocalTime(), t); } } @Test(groups={"tck"}) public void test_minusMinutes_noChange_oneDay() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMinutes(24 * 60); - assertEquals(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1)); + assertEquals(t.toLocalDate(), TEST_2007_07_15_12_30_40_987654321.toLocalDate().minusDays(1)); } //----------------------------------------------------------------------- @@ -2513,7 +2472,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_minusSeconds_one() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); - LocalDate d = t.getDate().minusDays(1); + LocalDate d = t.toLocalDate().minusDays(1); int hour = 0; int min = 0; @@ -2536,7 +2495,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { } } - assertEquals(t.getDate(), d); + assertEquals(t.toLocalDate(), d); assertEquals(t.getHour(), hour); assertEquals(t.getMinute(), min); assertEquals(t.getSecond(), sec); @@ -2549,7 +2508,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { int delta = 30; int i = 3660; - LocalDate date = TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1); + LocalDate date = TEST_2007_07_15_12_30_40_987654321.toLocalDate().minusDays(1); int hour = 22; int min = 59; int sec = 0; @@ -2595,7 +2554,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); LocalDateTime t = base.minusSeconds(seconds); - assertEquals(date, t.getDate()); + assertEquals(date, t.toLocalDate()); assertEquals(hour, t.getHour()); assertEquals(min, t.getMinute()); assertEquals(sec, t.getSecond()); @@ -2607,7 +2566,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_minusNanos_halfABillion() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); - LocalDate d = t.getDate().minusDays(1); + LocalDate d = t.toLocalDate().minusDays(1); int hour = 0; int min = 0; @@ -2637,7 +2596,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { } } - assertEquals(t.getDate(), d); + assertEquals(t.toLocalDate(), d); assertEquals(t.getHour(), hour); assertEquals(t.getMinute(), min); assertEquals(t.getSecond(), sec); @@ -2651,7 +2610,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { long delta = 7500000000L; long i = 3660 * 1000000000L; - LocalDate date = TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1); + LocalDate date = TEST_2007_07_15_12_30_40_987654321.toLocalDate().minusDays(1); int hour = 22; int min = 59; int sec = 0; @@ -2700,7 +2659,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { LocalDateTime base = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.MIDNIGHT); LocalDateTime t = base.minusNanos(nanoseconds); - assertEquals(date, t.getDate()); + assertEquals(date, t.toLocalDate()); assertEquals(hour, t.getHour()); assertEquals(min, t.getMinute()); assertEquals(sec, t.getSecond()); @@ -3032,7 +2991,7 @@ public class TCKLocalDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_toString_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d H m s"); String t = LocalDateTime.of(2010, 12, 3, 11, 30, 45).toString(f); assertEquals(t, "2010 12 3 11 30 45"); } diff --git a/jdk/test/java/time/tck/java/time/TCKLocalTime.java b/jdk/test/java/time/tck/java/time/TCKLocalTime.java index 1cc5486c7e2..9b4d65f4938 100644 --- a/jdk/test/java/time/tck/java/time/TCKLocalTime.java +++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java @@ -92,42 +92,39 @@ import static org.testng.Assert.fail; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; -import java.io.IOException; +import java.time.Clock; +import java.time.DateTimeException; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetTime; +import java.time.Period; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.time.temporal.JulianFields; +import java.time.temporal.Queries; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQuery; +import java.time.temporal.TemporalUnit; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.Iterator; import java.util.List; -import java.time.Clock; -import java.time.DateTimeException; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.Period; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; -import java.time.format.DateTimeParseException; -import java.time.temporal.ChronoField; -import java.time.temporal.ChronoUnit; -import java.time.temporal.JulianFields; -import java.time.temporal.OffsetTime; -import java.time.temporal.Queries; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalAdder; -import java.time.temporal.TemporalAdjuster; -import java.time.temporal.TemporalField; -import java.time.temporal.TemporalSubtractor; -import java.time.temporal.TemporalUnit; - import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import test.java.time.MockSimplePeriod; /** * Test LocalTime. @@ -504,35 +501,6 @@ public class TCKLocalTime extends AbstractDateTimeTest { LocalTime.ofSecondOfDay(24 * 60 * 60); } - //----------------------------------------------------------------------- - // ofSecondOfDay(long, int) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_ofSecondOfDay_long_int() { - LocalTime localTime = LocalTime.ofSecondOfDay(2 * 60 * 60 + 17 * 60 + 23, 987); - check(localTime, 2, 17, 23, 987); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void factory_ofSecondOfDay_long_int_tooLowSecs() { - LocalTime.ofSecondOfDay(-1, 0); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void factory_ofSecondOfDay_long_int_tooHighSecs() { - LocalTime.ofSecondOfDay(24 * 60 * 60, 0); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void factory_ofSecondOfDay_long_int_tooLowNanos() { - LocalTime.ofSecondOfDay(0, -1); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void factory_ofSecondOfDay_long_int_tooHighNanos() { - LocalTime.ofSecondOfDay(0, 1000000000); - } - //----------------------------------------------------------------------- // ofNanoOfDay(long) //----------------------------------------------------------------------- @@ -631,14 +599,14 @@ public class TCKLocalTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void factory_parse_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("H m s"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("H m s"); LocalTime test = LocalTime.parse("14 30 40", f); assertEquals(test, LocalTime.of(14, 30, 40)); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void factory_parse_formatter_nullText() { - DateTimeFormatter f = DateTimeFormatters.pattern("H m s"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("H m s"); LocalTime.parse((String) null, f); } @@ -685,34 +653,27 @@ public class TCKLocalTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- // query(TemporalQuery) //----------------------------------------------------------------------- - @Test - public void test_query_chrono() { - assertEquals(TEST_12_30_40_987654321.query(Queries.chrono()), null); - assertEquals(Queries.chrono().queryFrom(TEST_12_30_40_987654321), null); + @DataProvider(name="query") + Object[][] data_query() { + return new Object[][] { + {TEST_12_30_40_987654321, Queries.chronology(), null}, + {TEST_12_30_40_987654321, Queries.zoneId(), null}, + {TEST_12_30_40_987654321, Queries.precision(), ChronoUnit.NANOS}, + {TEST_12_30_40_987654321, Queries.zone(), null}, + {TEST_12_30_40_987654321, Queries.offset(), null}, + {TEST_12_30_40_987654321, Queries.localDate(), null}, + {TEST_12_30_40_987654321, Queries.localTime(), TEST_12_30_40_987654321}, + }; } - @Test - public void test_query_zoneId() { - assertEquals(TEST_12_30_40_987654321.query(Queries.zoneId()), null); - assertEquals(Queries.zoneId().queryFrom(TEST_12_30_40_987654321), null); + @Test(dataProvider="query") + public void test_query(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(temporal.query(query), expected); } - @Test - public void test_query_precision() { - assertEquals(TEST_12_30_40_987654321.query(Queries.precision()), NANOS); - assertEquals(Queries.precision().queryFrom(TEST_12_30_40_987654321), NANOS); - } - - @Test - public void test_query_offset() { - assertEquals(TEST_12_30_40_987654321.query(Queries.offset()), null); - assertEquals(Queries.offset().queryFrom(TEST_12_30_40_987654321), null); - } - - @Test - public void test_query_zone() { - assertEquals(TEST_12_30_40_987654321.query(Queries.zone()), null); - assertEquals(Queries.zone().queryFrom(TEST_12_30_40_987654321), null); + @Test(dataProvider="query") + public void test_queryFrom(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(query.queryFrom(temporal), expected); } @Test(expectedExceptions=NullPointerException.class) @@ -942,6 +903,60 @@ public class TCKLocalTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- // truncated(TemporalUnit) //----------------------------------------------------------------------- + TemporalUnit NINETY_MINS = new TemporalUnit() { + @Override + public String getName() { + return "NinetyMins"; + } + @Override + public Duration getDuration() { + return Duration.ofMinutes(90); + } + @Override + public boolean isDurationEstimated() { + return false; + } + @Override + public boolean isSupportedBy(Temporal temporal) { + return false; + } + @Override + public R addTo(R temporal, long amount) { + throw new UnsupportedOperationException(); + } + @Override + public long between(Temporal temporal1, Temporal temporal2) { + throw new UnsupportedOperationException(); + } + }; + + TemporalUnit NINETY_FIVE_MINS = new TemporalUnit() { + @Override + public String getName() { + return "NinetyFiveMins"; + } + @Override + public Duration getDuration() { + return Duration.ofMinutes(95); + } + @Override + public boolean isDurationEstimated() { + return false; + } + @Override + public boolean isSupportedBy(Temporal temporal) { + return false; + } + @Override + public R addTo(R temporal, long amount) { + throw new UnsupportedOperationException(); + } + @Override + public long between(Temporal temporal1, Temporal temporal2) { + throw new UnsupportedOperationException(); + } + }; + @DataProvider(name="truncatedToValid") Object[][] data_truncatedToValid() { return new Object[][] { @@ -952,6 +967,10 @@ public class TCKLocalTime extends AbstractDateTimeTest { {LocalTime.of(1, 2, 3, 123_456_789), MINUTES, LocalTime.of(1, 2)}, {LocalTime.of(1, 2, 3, 123_456_789), HOURS, LocalTime.of(1, 0)}, {LocalTime.of(1, 2, 3, 123_456_789), DAYS, LocalTime.MIDNIGHT}, + + {LocalTime.of(1, 1, 1, 123_456_789), NINETY_MINS, LocalTime.of(0, 0)}, + {LocalTime.of(2, 1, 1, 123_456_789), NINETY_MINS, LocalTime.of(1, 30)}, + {LocalTime.of(3, 1, 1, 123_456_789), NINETY_MINS, LocalTime.of(3, 0)}, }; } @@ -963,6 +982,7 @@ public class TCKLocalTime extends AbstractDateTimeTest { @DataProvider(name="truncatedToInvalid") Object[][] data_truncatedToInvalid() { return new Object[][] { + {LocalTime.of(1, 2, 3, 123_456_789), NINETY_FIVE_MINS}, {LocalTime.of(1, 2, 3, 123_456_789), WEEKS}, {LocalTime.of(1, 2, 3, 123_456_789), MONTHS}, {LocalTime.of(1, 2, 3, 123_456_789), YEARS}, @@ -980,45 +1000,45 @@ public class TCKLocalTime extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // plus(PlusAdjuster) + // plus(TemporalAmount) //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_plus_Adjuster_positiveHours() { - TemporalAdder period = MockSimplePeriod.of(7, ChronoUnit.HOURS); + @Test + public void test_plus_TemporalAmount_positiveHours() { + TemporalAmount period = MockSimplePeriod.of(7, ChronoUnit.HOURS); LocalTime t = TEST_12_30_40_987654321.plus(period); assertEquals(t, LocalTime.of(19, 30, 40, 987654321)); } - @Test(groups={"tck"}) - public void test_plus_Adjuster_negativeMinutes() { - TemporalAdder period = MockSimplePeriod.of(-25, ChronoUnit.MINUTES); + @Test + public void test_plus_TemporalAmount_negativeMinutes() { + TemporalAmount period = MockSimplePeriod.of(-25, ChronoUnit.MINUTES); LocalTime t = TEST_12_30_40_987654321.plus(period); assertEquals(t, LocalTime.of(12, 5, 40, 987654321)); } - @Test(groups={"tck"}) - public void test_plus_Adjuster_zero() { - TemporalAdder period = Period.ZERO; + @Test + public void test_plus_TemporalAmount_zero() { + TemporalAmount period = Period.ZERO; LocalTime t = TEST_12_30_40_987654321.plus(period); assertEquals(t, TEST_12_30_40_987654321); } - @Test(groups={"tck"}) - public void test_plus_Adjuster_wrap() { - TemporalAdder p = Period.ofTime(1, 0, 0); + @Test + public void test_plus_TemporalAmount_wrap() { + TemporalAmount p = MockSimplePeriod.of(1, HOURS); LocalTime t = LocalTime.of(23, 30).plus(p); assertEquals(t, LocalTime.of(0, 30)); } - @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) - public void test_plus_Adjuster_dateNotAllowed() { - TemporalAdder period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); + @Test(expectedExceptions=DateTimeException.class) + public void test_plus_TemporalAmount_dateNotAllowed() { + TemporalAmount period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); TEST_12_30_40_987654321.plus(period); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_plus_Adjuster_null() { - TEST_12_30_40_987654321.plus((TemporalAdder) null); + @Test(expectedExceptions=NullPointerException.class) + public void test_plus_TemporalAmount_null() { + TEST_12_30_40_987654321.plus((TemporalAmount) null); } //----------------------------------------------------------------------- @@ -1067,41 +1087,6 @@ public class TCKLocalTime extends AbstractDateTimeTest { TEST_12_30_40_987654321.plus(1, (TemporalUnit) null); } - //----------------------------------------------------------------------- - // plus(adjuster) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_plus_adjuster() { - Period p = Period.ofTime(0, 0, 62, 3); - LocalTime t = TEST_12_30_40_987654321.plus(p); - assertEquals(t, LocalTime.of(12, 31, 42, 987654324)); - } - - @Test(groups={"tck"}) - public void test_plus_adjuster_big() { - Period p = Period.ofTime(0, 0, 0, Long.MAX_VALUE); - LocalTime t = TEST_12_30_40_987654321.plus(p); - assertEquals(t, TEST_12_30_40_987654321.plusNanos(Long.MAX_VALUE)); - } - - @Test(groups={"tck"}) - public void test_plus_adjuster_zero_equal() { - LocalTime t = TEST_12_30_40_987654321.plus(Period.ZERO); - assertEquals(t, TEST_12_30_40_987654321); - } - - @Test(groups={"tck"}) - public void test_plus_adjuster_wrap() { - Period p = Period.ofTime(1, 0, 0); - LocalTime t = LocalTime.of(23, 30).plus(p); - assertEquals(t, LocalTime.of(0, 30)); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_plus_adjuster_null() { - TEST_12_30_40_987654321.plus((TemporalAdder) null); - } - //----------------------------------------------------------------------- // plusHours() //----------------------------------------------------------------------- @@ -1449,59 +1434,45 @@ public class TCKLocalTime extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // minus(MinusAdjuster) + // minus(TemporalAmount) //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_minus_Adjuster() { - TemporalSubtractor p = Period.ofTime(0, 0, 62, 3); - LocalTime t = TEST_12_30_40_987654321.minus(p); - assertEquals(t, LocalTime.of(12, 29, 38, 987654318)); - } - - @Test(groups={"tck"}) - public void test_minus_Adjuster_positiveHours() { - TemporalSubtractor period = MockSimplePeriod.of(7, ChronoUnit.HOURS); + @Test + public void test_minus_TemporalAmount_positiveHours() { + TemporalAmount period = MockSimplePeriod.of(7, ChronoUnit.HOURS); LocalTime t = TEST_12_30_40_987654321.minus(period); assertEquals(t, LocalTime.of(5, 30, 40, 987654321)); } - @Test(groups={"tck"}) - public void test_minus_Adjuster_negativeMinutes() { - TemporalSubtractor period = MockSimplePeriod.of(-25, ChronoUnit.MINUTES); + @Test + public void test_minus_TemporalAmount_negativeMinutes() { + TemporalAmount period = MockSimplePeriod.of(-25, ChronoUnit.MINUTES); LocalTime t = TEST_12_30_40_987654321.minus(period); assertEquals(t, LocalTime.of(12, 55, 40, 987654321)); } - @Test(groups={"tck"}) - public void test_minus_Adjuster_big1() { - TemporalSubtractor p = Period.ofTime(0, 0, 0, Long.MAX_VALUE); - LocalTime t = TEST_12_30_40_987654321.minus(p); - assertEquals(t, TEST_12_30_40_987654321.minusNanos(Long.MAX_VALUE)); - } - - @Test(groups={"tck"}) - public void test_minus_Adjuster_zero() { - TemporalSubtractor p = Period.ZERO; - LocalTime t = TEST_12_30_40_987654321.minus(p); + @Test + public void test_minus_TemporalAmount_zero() { + TemporalAmount period = Period.ZERO; + LocalTime t = TEST_12_30_40_987654321.minus(period); assertEquals(t, TEST_12_30_40_987654321); } - @Test(groups={"tck"}) - public void test_minus_Adjuster_wrap() { - TemporalSubtractor p = Period.ofTime(1, 0, 0); + @Test + public void test_minus_TemporalAmount_wrap() { + TemporalAmount p = MockSimplePeriod.of(1, HOURS); LocalTime t = LocalTime.of(0, 30).minus(p); assertEquals(t, LocalTime.of(23, 30)); } - @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) - public void test_minus_Adjuster_dateNotAllowed() { - TemporalSubtractor period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); + @Test(expectedExceptions=DateTimeException.class) + public void test_minus_TemporalAmount_dateNotAllowed() { + TemporalAmount period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); TEST_12_30_40_987654321.minus(period); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_minus_Adjuster_null() { - TEST_12_30_40_987654321.minus((TemporalSubtractor) null); + @Test(expectedExceptions=NullPointerException.class) + public void test_minus_TemporalAmount_null() { + TEST_12_30_40_987654321.minus((TemporalAmount) null); } //----------------------------------------------------------------------- @@ -2213,7 +2184,7 @@ public class TCKLocalTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_toString_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("H m s"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("H m s"); String t = LocalTime.of(11, 30, 45).toString(f); assertEquals(t, "11 30 45"); } diff --git a/jdk/test/java/time/tck/java/time/TCKMonth.java b/jdk/test/java/time/tck/java/time/TCKMonth.java index 6f6170d06f8..c5160c1c286 100644 --- a/jdk/test/java/time/tck/java/time/TCKMonth.java +++ b/jdk/test/java/time/tck/java/time/TCKMonth.java @@ -62,23 +62,23 @@ package tck.java.time; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static org.testng.Assert.assertEquals; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; - import java.time.DateTimeException; import java.time.LocalDate; import java.time.LocalTime; import java.time.Month; +import java.time.chrono.IsoChronology; import java.time.format.TextStyle; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; -import java.time.temporal.ISOChrono; import java.time.temporal.JulianFields; import java.time.temporal.Queries; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQuery; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -167,34 +167,27 @@ public class TCKMonth extends AbstractDateTimeTest { //----------------------------------------------------------------------- // query(TemporalQuery) //----------------------------------------------------------------------- - @Test - public void test_query_chrono() { - assertEquals(Month.JUNE.query(Queries.chrono()), ISOChrono.INSTANCE); - assertEquals(Queries.chrono().queryFrom(Month.JUNE), ISOChrono.INSTANCE); + @DataProvider(name="query") + Object[][] data_query() { + return new Object[][] { + {Month.JUNE, Queries.chronology(), IsoChronology.INSTANCE}, + {Month.JUNE, Queries.zoneId(), null}, + {Month.JUNE, Queries.precision(), ChronoUnit.MONTHS}, + {Month.JUNE, Queries.zone(), null}, + {Month.JUNE, Queries.offset(), null}, + {Month.JUNE, Queries.localDate(), null}, + {Month.JUNE, Queries.localTime(), null}, + }; } - @Test - public void test_query_zoneId() { - assertEquals(Month.JUNE.query(Queries.zoneId()), null); - assertEquals(Queries.zoneId().queryFrom(Month.JUNE), null); + @Test(dataProvider="query") + public void test_query(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(temporal.query(query), expected); } - @Test - public void test_query_precision() { - assertEquals(Month.JUNE.query(Queries.precision()), ChronoUnit.MONTHS); - assertEquals(Queries.precision().queryFrom(Month.JUNE), ChronoUnit.MONTHS); - } - - @Test - public void test_query_offset() { - assertEquals(Month.JUNE.query(Queries.offset()), null); - assertEquals(Queries.offset().queryFrom(Month.JUNE), null); - } - - @Test - public void test_query_zone() { - assertEquals(Month.JUNE.query(Queries.zone()), null); - assertEquals(Queries.zone().queryFrom(Month.JUNE), null); + @Test(dataProvider="query") + public void test_queryFrom(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(query.queryFrom(temporal), expected); } @Test(expectedExceptions=NullPointerException.class) @@ -207,17 +200,17 @@ public class TCKMonth extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_getText() { - assertEquals(Month.JANUARY.getText(TextStyle.SHORT, Locale.US), "Jan"); + assertEquals(Month.JANUARY.getDisplayName(TextStyle.SHORT, Locale.US), "Jan"); } @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) public void test_getText_nullStyle() { - Month.JANUARY.getText(null, Locale.US); + Month.JANUARY.getDisplayName(null, Locale.US); } @Test(expectedExceptions = NullPointerException.class, groups={"tck"}) public void test_getText_nullLocale() { - Month.JANUARY.getText(TextStyle.FULL, null); + Month.JANUARY.getDisplayName(TextStyle.FULL, null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKMonthDay.java b/jdk/test/java/time/tck/java/time/TCKMonthDay.java similarity index 93% rename from jdk/test/java/time/tck/java/time/temporal/TCKMonthDay.java rename to jdk/test/java/time/tck/java/time/TCKMonthDay.java index 774777cab03..1a80e8ce303 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TCKMonthDay.java +++ b/jdk/test/java/time/tck/java/time/TCKMonthDay.java @@ -57,7 +57,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.temporal; +package tck.java.time; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; @@ -68,12 +68,6 @@ import static org.testng.Assert.fail; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import java.time.Clock; import java.time.DateTimeException; import java.time.Instant; @@ -81,22 +75,28 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; +import java.time.MonthDay; +import java.time.YearMonth; import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; import java.time.temporal.JulianFields; -import java.time.temporal.MonthDay; +import java.time.temporal.Queries; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; -import java.time.temporal.YearMonth; +import java.time.temporal.TemporalQuery; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import tck.java.time.AbstractDateTimeTest; /** * Test MonthDay. @@ -147,7 +147,7 @@ public class TCKMonthDay extends AbstractDateTimeTest { public void test_serialization_format() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(6); + dos.writeByte(13); // java.time.temporal.Ser.MONTH_DAY_TYPE dos.writeByte(9); dos.writeByte(16); } @@ -372,14 +372,14 @@ public class TCKMonthDay extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void factory_parse_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("M d"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("M d"); MonthDay test = MonthDay.parse("12 3", f); assertEquals(test, MonthDay.of(12, 3)); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void factory_parse_formatter_nullText() { - DateTimeFormatter f = DateTimeFormatters.pattern("M d"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("M d"); MonthDay.parse((String) null, f); } @@ -403,6 +403,37 @@ public class TCKMonthDay extends AbstractDateTimeTest { assertEquals(TEST_07_15.getLong(ChronoField.MONTH_OF_YEAR), 7); } + //----------------------------------------------------------------------- + // query(TemporalQuery) + //----------------------------------------------------------------------- + @DataProvider(name="query") + Object[][] data_query() { + return new Object[][] { + {TEST_07_15, Queries.chronology(), IsoChronology.INSTANCE}, + {TEST_07_15, Queries.zoneId(), null}, + {TEST_07_15, Queries.precision(), null}, + {TEST_07_15, Queries.zone(), null}, + {TEST_07_15, Queries.offset(), null}, + {TEST_07_15, Queries.localDate(), null}, + {TEST_07_15, Queries.localTime(), null}, + }; + } + + @Test(dataProvider="query") + public void test_query(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(temporal.query(query), expected); + } + + @Test(dataProvider="query") + public void test_queryFrom(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(query.queryFrom(temporal), expected); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_query_null() { + TEST_07_15.query(null); + } + //----------------------------------------------------------------------- // get*() //----------------------------------------------------------------------- @@ -419,10 +450,11 @@ public class TCKMonthDay extends AbstractDateTimeTest { }; } - @Test(dataProvider="sampleDates", groups={"tck"}) + @Test(dataProvider="sampleDates") public void test_get(int m, int d) { MonthDay a = MonthDay.of(m, d); assertEquals(a.getMonth(), Month.of(m)); + assertEquals(a.getMonthValue(), m); assertEquals(a.getDayOfMonth(), d); } @@ -743,7 +775,7 @@ public class TCKMonthDay extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_toString_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("M d"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("M d"); String t = MonthDay.of(12, 3).toString(f); assertEquals(t, "12 3"); } diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKOffsetDateTime.java b/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java similarity index 77% rename from jdk/test/java/time/tck/java/time/temporal/TCKOffsetDateTime.java rename to jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java index 01d72a4a661..ee0832e7ff0 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TCKOffsetDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKOffsetDateTime.java @@ -57,7 +57,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.temporal; +package tck.java.time; import static java.time.Month.DECEMBER; import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; @@ -98,13 +98,8 @@ import static org.testng.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; -import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import java.time.Clock; import java.time.DateTimeException; import java.time.Duration; @@ -113,31 +108,31 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Year; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; -import java.time.temporal.ISOChrono; import java.time.temporal.JulianFields; -import java.time.temporal.OffsetDate; -import java.time.temporal.OffsetDateTime; -import java.time.temporal.OffsetTime; import java.time.temporal.Queries; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; -import java.time.temporal.Year; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import tck.java.time.AbstractDateTimeTest; import test.java.time.MockSimplePeriod; /** @@ -225,7 +220,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { public void test_serialization_format() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(3); + dos.writeByte(10); // java.time.Ser.OFFSET_DATE_TIME_TYPE } byte[] bytes = baos.toByteArray(); ByteArrayOutputStream baosDateTime = new ByteArrayOutputStream(); @@ -270,12 +265,12 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { public void now() { OffsetDateTime expected = OffsetDateTime.now(Clock.systemDefaultZone()); OffsetDateTime test = OffsetDateTime.now(); - long diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay()); + long diff = Math.abs(test.toLocalTime().toNanoOfDay() - expected.toLocalTime().toNanoOfDay()); if (diff >= 100000000) { // may be date change expected = OffsetDateTime.now(Clock.systemDefaultZone()); test = OffsetDateTime.now(); - diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay()); + diff = Math.abs(test.toLocalTime().toNanoOfDay() - expected.toLocalTime().toNanoOfDay()); } assertTrue(diff < 100000000); // less than 0.1 secs } @@ -328,14 +323,14 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { assertEquals(test.getMonth(), Month.DECEMBER); assertEquals(test.getDayOfMonth(), 31); expected = expected.minusSeconds(1); - assertEquals(test.getTime(), expected); + assertEquals(test.toLocalTime(), expected); assertEquals(test.getOffset(), ZoneOffset.UTC); } } @Test(groups={"tck"}) public void now_Clock_offsets() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(12, 0), ZoneOffset.UTC); + OffsetDateTime base = OffsetDateTime.of(1970, 1, 1, 12, 0, 0, 0, ZoneOffset.UTC); for (int i = -9; i < 15; i++) { ZoneOffset offset = ZoneOffset.ofHours(i); Clock clock = Clock.fixed(base.toInstant(), offset); @@ -374,49 +369,11 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // dateTime factories - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_of_intMonthIntHM() { - OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, Month.JUNE, 30), - LocalTime.of(11, 30), OFFSET_PONE); - check(test, 2008, 6, 30, 11, 30, 0, 0, OFFSET_PONE); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_of_intMonthIntHMS() { - OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, Month.JUNE, 30), - LocalTime.of(11, 30, 10), OFFSET_PONE); - check(test, 2008, 6, 30, 11, 30, 10, 0, OFFSET_PONE); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_of_intMonthIntHMSN() { - OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, Month.JUNE, 30), - LocalTime.of(11, 30, 10, 500), OFFSET_PONE); - check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_PONE); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_of_intsHM() { - OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PONE); - check(test, 2008, 6, 30, 11, 30, 0, 0, OFFSET_PONE); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_of_intsHMS() { - OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 10), OFFSET_PONE); - check(test, 2008, 6, 30, 11, 30, 10, 0, OFFSET_PONE); - } - + // factories //----------------------------------------------------------------------- @Test(groups={"tck"}) public void factory_of_intsHMSN() { - OffsetDateTime test = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 10, 500), OFFSET_PONE); + OffsetDateTime test = OffsetDateTime.of(2008, 6, 30, 11, 30, 10, 500, OFFSET_PONE); check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_PONE); } @@ -523,14 +480,14 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void factory_parse_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s XXX"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d H m s XXX"); OffsetDateTime test = OffsetDateTime.parse("2010 12 3 11 30 0 +01:00", f); assertEquals(test, OffsetDateTime.of(LocalDate.of(2010, 12, 3), LocalTime.of(11, 30), ZoneOffset.ofHours(1))); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void factory_parse_formatter_nullText() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d H m s"); OffsetDateTime.parse((String) null, f); } @@ -593,7 +550,6 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { assertEquals(a.getSecond(), localDateTime.getSecond()); assertEquals(a.getNano(), localDateTime.getNano()); - assertEquals(a.toOffsetDate(), OffsetDate.of(localDate, offset)); assertEquals(a.toOffsetTime(), OffsetTime.of(localTime, offset)); assertEquals(a.toString(), localDateTime.toString() + offset.toString()); } @@ -643,34 +599,27 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- // query(TemporalQuery) //----------------------------------------------------------------------- - @Test - public void test_query_chrono() { - assertEquals(TEST_2008_6_30_11_30_59_000000500.query(Queries.chrono()), ISOChrono.INSTANCE); - assertEquals(Queries.chrono().queryFrom(TEST_2008_6_30_11_30_59_000000500), ISOChrono.INSTANCE); + @DataProvider(name="query") + Object[][] data_query() { + return new Object[][] { + {TEST_2008_6_30_11_30_59_000000500, Queries.chronology(), IsoChronology.INSTANCE}, + {TEST_2008_6_30_11_30_59_000000500, Queries.zoneId(), null}, + {TEST_2008_6_30_11_30_59_000000500, Queries.precision(), ChronoUnit.NANOS}, + {TEST_2008_6_30_11_30_59_000000500, Queries.zone(), OFFSET_PONE}, + {TEST_2008_6_30_11_30_59_000000500, Queries.offset(), OFFSET_PONE}, + {TEST_2008_6_30_11_30_59_000000500, Queries.localDate(), LocalDate.of(2008, 6, 30)}, + {TEST_2008_6_30_11_30_59_000000500, Queries.localTime(), LocalTime.of(11, 30, 59, 500)}, + }; } - @Test - public void test_query_zoneId() { - assertEquals(TEST_2008_6_30_11_30_59_000000500.query(Queries.zoneId()), null); - assertEquals(Queries.zoneId().queryFrom(TEST_2008_6_30_11_30_59_000000500), null); + @Test(dataProvider="query") + public void test_query(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(temporal.query(query), expected); } - @Test - public void test_query_precision() { - assertEquals(TEST_2008_6_30_11_30_59_000000500.query(Queries.precision()), NANOS); - assertEquals(Queries.precision().queryFrom(TEST_2008_6_30_11_30_59_000000500), NANOS); - } - - @Test - public void test_query_offset() { - assertEquals(TEST_2008_6_30_11_30_59_000000500.query(Queries.offset()), OFFSET_PONE); - assertEquals(Queries.offset().queryFrom(TEST_2008_6_30_11_30_59_000000500), OFFSET_PONE); - } - - @Test - public void test_query_zone() { - assertEquals(TEST_2008_6_30_11_30_59_000000500.query(Queries.zone()), OFFSET_PONE); - assertEquals(Queries.zone().queryFrom(TEST_2008_6_30_11_30_59_000000500), OFFSET_PONE); + @Test(dataProvider="query") + public void test_queryFrom(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(query.queryFrom(temporal), expected); } @Test(expectedExceptions=NullPointerException.class) @@ -711,12 +660,6 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { assertEquals(test, OffsetDateTime.of(LocalDate.of(2012, 9, 3), LocalTime.of(19, 15), OFFSET_PONE)); } - @Test(groups={"tck"}) - public void test_with_adjustment_OffsetDate() { - OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(OffsetDate.of(LocalDate.of(2012, 9, 3), OFFSET_PTWO)); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2012, 9, 3), LocalTime.of(11, 30, 59, 500), OFFSET_PTWO)); - } - @Test(groups={"tck"}) public void test_with_adjustment_OffsetTime() { OffsetDateTime test = TEST_2008_6_30_11_30_59_000000500.with(OffsetTime.of(LocalTime.of(19, 15), OFFSET_PTWO)); @@ -880,7 +823,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { public void test_plus_Period() { MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.plus(period); - assertEquals(t, OffsetDateTime.of(LocalDate.of(2009, 1, 30), LocalTime.of(11, 30, 59, 500), OFFSET_PONE)); + assertEquals(t, OffsetDateTime.of(2009, 1, 30, 11, 30, 59, 500, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -890,7 +833,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { public void test_plus_Duration() { Duration dur = Duration.ofSeconds(62, 3); OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.plus(dur); - assertEquals(t, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 32, 1, 503), OFFSET_PONE)); + assertEquals(t, OffsetDateTime.of(2008, 6, 30, 11, 32, 1, 503, OFFSET_PONE)); } @Test(groups={"tck"}) @@ -909,9 +852,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_plusYears() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.plusYears(1); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2009, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2009, 6, 30, 11, 30, 59, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -919,9 +862,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_plusMonths() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.plusMonths(1); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 7, 30), LocalTime.of(11, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 7, 30, 11, 30, 59, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -929,9 +872,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_plusWeeks() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.plusWeeks(1); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 7, 7), LocalTime.of(11, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 7, 7, 11, 30, 59, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -939,9 +882,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_plusDays() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.plusDays(1); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 7, 1), LocalTime.of(11, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 7, 1, 11, 30, 59, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -949,9 +892,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_plusHours() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.plusHours(13); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 7, 1), LocalTime.of(0, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 7, 1, 0, 30, 59, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -959,9 +902,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_plusMinutes() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.plusMinutes(30); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(12, 0, 59), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 6, 30, 12, 0, 59, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -969,9 +912,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_plusSeconds() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.plusSeconds(1); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 31, 0), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 6, 30, 11, 31, 0, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -979,9 +922,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_plusNanos() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 0), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.plusNanos(1); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 1), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 1, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -991,7 +934,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { public void test_minus_Period() { MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.minus(period); - assertEquals(t, OffsetDateTime.of(LocalDate.of(2007, 11, 30), LocalTime.of(11, 30, 59, 500), OFFSET_PONE)); + assertEquals(t, OffsetDateTime.of(2007, 11, 30, 11, 30, 59, 500, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -1001,7 +944,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { public void test_minus_Duration() { Duration dur = Duration.ofSeconds(62, 3); OffsetDateTime t = TEST_2008_6_30_11_30_59_000000500.minus(dur); - assertEquals(t, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 29, 57, 497), OFFSET_PONE)); + assertEquals(t, OffsetDateTime.of(2008, 6, 30, 11, 29, 57, 497, OFFSET_PONE)); } @Test(groups={"tck"}) @@ -1020,9 +963,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_minusYears() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.minusYears(1); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2007, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2007, 6, 30, 11, 30, 59, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -1030,9 +973,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_minusMonths() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.minusMonths(1); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 5, 30), LocalTime.of(11, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 5, 30, 11, 30, 59, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -1040,9 +983,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_minusWeeks() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.minusWeeks(1); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 23), LocalTime.of(11, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 6, 23, 11, 30, 59, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -1050,9 +993,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_minusDays() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.minusDays(1); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 29), LocalTime.of(11, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 6, 29, 11, 30, 59, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -1060,9 +1003,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_minusHours() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.minusHours(13); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 29), LocalTime.of(22, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 6, 29, 22, 30, 59, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -1070,9 +1013,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_minusMinutes() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.minusMinutes(30); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 0, 59), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 6, 30, 11, 0, 59, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -1080,9 +1023,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_minusSeconds() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.minusSeconds(1); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 58), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 6, 30, 11, 30, 58, 0, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -1090,9 +1033,9 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_minusNanos() { - OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 0), OFFSET_PONE); + OffsetDateTime base = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); OffsetDateTime test = base.minusNanos(1); - assertEquals(test, OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 58, 999999999), OFFSET_PONE)); + assertEquals(test, OffsetDateTime.of(2008, 6, 30, 11, 30, 58, 999999999, OFFSET_PONE)); } //----------------------------------------------------------------------- @@ -1100,14 +1043,14 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_atZone() { - OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_MTWO); + OffsetDateTime t = OffsetDateTime.of(2008, 6, 30, 11, 30, 0, 0, OFFSET_MTWO); assertEquals(t.atZoneSameInstant(ZONE_PARIS), - ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(15, 30)), ZONE_PARIS)); + ZonedDateTime.of(2008, 6, 30, 15, 30, 0, 0, ZONE_PARIS)); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_atZone_nullTimeZone() { - OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PTWO); + OffsetDateTime t = OffsetDateTime.of(2008, 6, 30, 11, 30, 0, 0, OFFSET_PTWO); t.atZoneSameInstant((ZoneId) null); } @@ -1116,37 +1059,37 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_atZoneSimilarLocal() { - OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_MTWO); + OffsetDateTime t = OffsetDateTime.of(2008, 6, 30, 11, 30, 0, 0, OFFSET_MTWO); assertEquals(t.atZoneSimilarLocal(ZONE_PARIS), - ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30)), ZONE_PARIS)); + ZonedDateTime.of(2008, 6, 30, 11, 30, 0, 0, ZONE_PARIS)); } @Test(groups={"tck"}) public void test_atZoneSimilarLocal_dstGap() { - OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2007, 4, 1), LocalTime.of(0, 0), OFFSET_MTWO); + OffsetDateTime t = OffsetDateTime.of(2007, 4, 1, 0, 0, 0, 0, OFFSET_MTWO); assertEquals(t.atZoneSimilarLocal(ZONE_GAZA), - ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2007, 4, 1), LocalTime.of(1, 0)), ZONE_GAZA)); + ZonedDateTime.of(2007, 4, 1, 1, 0, 0, 0, ZONE_GAZA)); } @Test(groups={"tck"}) public void test_atZone_dstOverlapSummer() { - OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2007, 10, 28), LocalTime.of(2, 30), OFFSET_PTWO); - assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).getDateTime(), t.getDateTime()); + OffsetDateTime t = OffsetDateTime.of(2007, 10, 28, 2, 30, 0, 0, OFFSET_PTWO); + assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).toLocalDateTime(), t.toLocalDateTime()); assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).getOffset(), OFFSET_PTWO); assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).getZone(), ZONE_PARIS); } @Test(groups={"tck"}) public void test_atZone_dstOverlapWinter() { - OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2007, 10, 28), LocalTime.of(2, 30), OFFSET_PONE); - assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).getDateTime(), t.getDateTime()); + OffsetDateTime t = OffsetDateTime.of(2007, 10, 28, 2, 30, 0, 0, OFFSET_PONE); + assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).toLocalDateTime(), t.toLocalDateTime()); assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).getOffset(), OFFSET_PONE); assertEquals(t.atZoneSimilarLocal(ZONE_PARIS).getZone(), ZONE_PARIS); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_atZoneSimilarLocal_nullTimeZone() { - OffsetDateTime t = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PTWO); + OffsetDateTime t = OffsetDateTime.of(2008, 6, 30, 11, 30, 0, 0, OFFSET_PTWO); t.atZoneSimilarLocal((ZoneId) null); } @@ -1156,7 +1099,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_toEpochSecond_afterEpoch() { for (int i = 0; i < 100000; i++) { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(0, 0), ZoneOffset.UTC).plusSeconds(i); + OffsetDateTime a = OffsetDateTime.of(1970, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).plusSeconds(i); assertEquals(a.toEpochSecond(), i); } } @@ -1164,7 +1107,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_toEpochSecond_beforeEpoch() { for (int i = 0; i < 100000; i++) { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(1970, 1, 1), LocalTime.of(0, 0), ZoneOffset.UTC).minusSeconds(i); + OffsetDateTime a = OffsetDateTime.of(1970, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).minusSeconds(i); assertEquals(a.toEpochSecond(), -i); } } @@ -1174,8 +1117,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_compareTo_timeMins() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 29, 3), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 2), OFFSET_PONE); // a is before b due to time + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 29, 3, 0, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(2008, 6, 30, 11, 30, 2, 0, OFFSET_PONE); // a is before b due to time assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1185,8 +1128,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_timeSecs() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 29, 2), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 29, 3), OFFSET_PONE); // a is before b due to time + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 29, 2, 0, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(2008, 6, 30, 11, 29, 3, 0, OFFSET_PONE); // a is before b due to time assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1196,8 +1139,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_timeNanos() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 29, 40, 4), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 29, 40, 5), OFFSET_PONE); // a is before b due to time + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 29, 40, 4, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(2008, 6, 30, 11, 29, 40, 5, OFFSET_PONE); // a is before b due to time assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1207,8 +1150,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_offset() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PTWO); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PONE); // a is before b due to offset + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 30, 0, 0, OFFSET_PTWO); + OffsetDateTime b = OffsetDateTime.of(2008, 6, 30, 11, 30, 0, 0, OFFSET_PONE); // a is before b due to offset assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1218,8 +1161,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_offsetNanos() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 40, 6), OFFSET_PTWO); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 40, 5), OFFSET_PONE); // a is before b due to offset + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 30, 40, 6, OFFSET_PTWO); + OffsetDateTime b = OffsetDateTime.of(2008, 6, 30, 11, 30, 40, 5, OFFSET_PONE); // a is before b due to offset assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1229,8 +1172,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_both() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 50), OFFSET_PTWO); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 20), OFFSET_PONE); // a is before b on instant scale + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 50, 0, 0, OFFSET_PTWO); + OffsetDateTime b = OffsetDateTime.of(2008, 6, 30, 11, 20, 0, 0, OFFSET_PONE); // a is before b on instant scale assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1240,8 +1183,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_bothNanos() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 20, 40, 4), OFFSET_PTWO); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(10, 20, 40, 5), OFFSET_PONE); // a is before b on instant scale + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 20, 40, 4, OFFSET_PTWO); + OffsetDateTime b = OffsetDateTime.of(2008, 6, 30, 10, 20, 40, 5, OFFSET_PONE); // a is before b on instant scale assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1251,8 +1194,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_hourDifference() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(10, 0), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 0), OFFSET_PTWO); // a is before b despite being same time-line time + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 10, 0, 0, 0, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(2008, 6, 30, 11, 0, 0, 0, OFFSET_PTWO); // a is before b despite being same time-line time assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1262,8 +1205,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_max() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(Year.MAX_VALUE, 12, 31), LocalTime.of(23, 59), OFFSET_MONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(Year.MAX_VALUE, 12, 31), LocalTime.of(23, 59), OFFSET_MTWO); // a is before b due to offset + OffsetDateTime a = OffsetDateTime.of(Year.MAX_VALUE, 12, 31, 23, 59, 0, 0, OFFSET_MONE); + OffsetDateTime b = OffsetDateTime.of(Year.MAX_VALUE, 12, 31, 23, 59, 0, 0, OFFSET_MTWO); // a is before b due to offset assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1272,8 +1215,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_min() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(Year.MIN_VALUE, 1, 1), LocalTime.of(0, 0), OFFSET_PTWO); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(Year.MIN_VALUE, 1, 1), LocalTime.of(0, 0), OFFSET_PONE); // a is before b due to offset + OffsetDateTime a = OffsetDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0, 0, 0, OFFSET_PTWO); + OffsetDateTime b = OffsetDateTime.of(Year.MIN_VALUE, 1, 1, 0, 0, 0, 0, OFFSET_PONE); // a is before b due to offset assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1282,7 +1225,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_compareTo_null() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); a.compareTo(null); } @@ -1298,8 +1241,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_isBeforeIsAfterIsEqual1() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 58, 3), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 2), OFFSET_PONE); // a is before b due to time + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 30, 58, 3, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 2, OFFSET_PONE); // a is before b due to time assertEquals(a.isBefore(b), true); assertEquals(a.isEqual(b), false); assertEquals(a.isAfter(b), false); @@ -1320,8 +1263,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_isBeforeIsAfterIsEqual2() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 2), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59, 3), OFFSET_PONE); // a is before b due to time + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 2, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 3, OFFSET_PONE); // a is before b due to time assertEquals(a.isBefore(b), true); assertEquals(a.isEqual(b), false); assertEquals(a.isAfter(b), false); @@ -1342,8 +1285,8 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_isBeforeIsAfterIsEqual_instantComparison() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(10, 0), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 0), OFFSET_PTWO); // a is same instant as b + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 10, 0, 0, 0, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(2008, 6, 30, 11, 0, 0, 0, OFFSET_PTWO); // a is same instant as b assertEquals(a.isBefore(b), false); assertEquals(a.isEqual(b), true); assertEquals(a.isAfter(b), false); @@ -1364,19 +1307,19 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_isBefore_null() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); a.isBefore(null); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_isEqual_null() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); a.isEqual(null); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_isAfter_null() { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetDateTime a = OffsetDateTime.of(2008, 6, 30, 11, 30, 59, 0, OFFSET_PONE); a.isAfter(null); } @@ -1385,49 +1328,49 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_true(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE); + OffsetDateTime a = OffsetDateTime.of(y, o, d, h, m, s, n, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(y, o, d, h, m, s, n, OFFSET_PONE); assertEquals(a.equals(b), true); assertEquals(a.hashCode() == b.hashCode(), true); } @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_false_year_differs(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y + 1, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE); + OffsetDateTime a = OffsetDateTime.of(y, o, d, h, m, s, n, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(y + 1, o, d, h, m, s, n, OFFSET_PONE); assertEquals(a.equals(b), false); } @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_false_hour_differs(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) { h = (h == 23 ? 22 : h); - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h + 1, m, s, n), OFFSET_PONE); + OffsetDateTime a = OffsetDateTime.of(y, o, d, h, m, s, n, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(y, o, d, h + 1, m, s, n, OFFSET_PONE); assertEquals(a.equals(b), false); } @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_false_minute_differs(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) { m = (m == 59 ? 58 : m); - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m + 1, s, n), OFFSET_PONE); + OffsetDateTime a = OffsetDateTime.of(y, o, d, h, m, s, n, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(y, o, d, h, m + 1, s, n, OFFSET_PONE); assertEquals(a.equals(b), false); } @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_false_second_differs(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) { s = (s == 59 ? 58 : s); - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s + 1, n), OFFSET_PONE); + OffsetDateTime a = OffsetDateTime.of(y, o, d, h, m, s, n, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(y, o, d, h, m, s + 1, n, OFFSET_PONE); assertEquals(a.equals(b), false); } @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_false_nano_differs(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) { n = (n == 999999999 ? 999999998 : n); - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n + 1), OFFSET_PONE); + OffsetDateTime a = OffsetDateTime.of(y, o, d, h, m, s, n, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(y, o, d, h, m, s, n + 1, OFFSET_PONE); assertEquals(a.equals(b), false); } @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_false_offset_differs(int y, int o, int d, int h, int m, int s, int n, ZoneOffset ignored) { - OffsetDateTime a = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetDateTime b = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), OFFSET_PTWO); + OffsetDateTime a = OffsetDateTime.of(y, o, d, h, m, s, n, OFFSET_PONE); + OffsetDateTime b = OffsetDateTime.of(y, o, d, h, m, s, n, OFFSET_PTWO); assertEquals(a.equals(b), false); } @@ -1465,7 +1408,7 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { @Test(dataProvider="sampleToString", groups={"tck"}) public void test_toString(int y, int o, int d, int h, int m, int s, int n, String offsetId, String expected) { - OffsetDateTime t = OffsetDateTime.of(LocalDate.of(y, o, d), LocalTime.of(h, m, s, n), ZoneOffset.of(offsetId)); + OffsetDateTime t = OffsetDateTime.of(y, o, d, h, m, s, n, ZoneOffset.of(offsetId)); String str = t.toString(); assertEquals(str, expected); } @@ -1475,14 +1418,14 @@ public class TCKOffsetDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_toString_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s"); - String t = OffsetDateTime.of(LocalDate.of(2010, 12, 3), LocalTime.of(11, 30), OFFSET_PONE).toString(f); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d H m s"); + String t = OffsetDateTime.of(2010, 12, 3, 11, 30, 0, 0, OFFSET_PONE).toString(f); assertEquals(t, "2010 12 3 11 30 0"); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_toString_formatter_null() { - OffsetDateTime.of(LocalDate.of(2010, 12, 3), LocalTime.of(11, 30), OFFSET_PONE).toString(null); + OffsetDateTime.of(2010, 12, 3, 11, 30, 0, 0, OFFSET_PONE).toString(null); } } diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKOffsetTime.java b/jdk/test/java/time/tck/java/time/TCKOffsetTime.java similarity index 79% rename from jdk/test/java/time/tck/java/time/temporal/TCKOffsetTime.java rename to jdk/test/java/time/tck/java/time/TCKOffsetTime.java index 374268589ad..83117099be2 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TCKOffsetTime.java +++ b/jdk/test/java/time/tck/java/time/TCKOffsetTime.java @@ -57,7 +57,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.temporal; +package tck.java.time; import static java.time.temporal.ChronoField.AMPM_OF_DAY; import static java.time.temporal.ChronoField.CLOCK_HOUR_OF_AMPM; @@ -84,45 +84,38 @@ import static org.testng.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; -import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import java.time.Clock; import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.OffsetTime; import java.time.Period; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.time.temporal.JulianFields; -import java.time.temporal.OffsetDate; -import java.time.temporal.OffsetDateTime; -import java.time.temporal.OffsetTime; import java.time.temporal.Queries; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalAdder; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; -import java.time.temporal.TemporalSubtractor; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import tck.java.time.AbstractDateTimeTest; import test.java.time.MockSimplePeriod; /** @@ -138,7 +131,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @BeforeMethod(groups={"tck","implementation"}) public void setUp() { - TEST_11_30_59_500_PONE = OffsetTime.of(LocalTime.of(11, 30, 59, 500), OFFSET_PONE); + TEST_11_30_59_500_PONE = OffsetTime.of(11, 30, 59, 500, OFFSET_PONE); } //----------------------------------------------------------------------- @@ -193,7 +186,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { public void test_serialization_format() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(2); + dos.writeByte(9); // java.time.Ser.OFFSET_TIME_TYPE } byte[] bytes = baos.toByteArray(); ByteArrayOutputStream baosTime = new ByteArrayOutputStream(); @@ -211,7 +204,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { dos.writeByte(4); // quarter hours stored: 3600 / 900 } byte[] bytesOffset = baosOffset.toByteArray(); - assertSerializedBySer(OffsetTime.of(LocalTime.of(22, 17, 59, 464_000_000), ZoneOffset.ofHours(1)), bytes, + assertSerializedBySer(OffsetTime.of(22, 17, 59, 464_000_000, ZoneOffset.ofHours(1)), bytes, bytesTime, bytesOffset); } @@ -237,7 +230,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { OffsetTime expected = OffsetTime.now(Clock.systemDefaultZone()); OffsetTime test = OffsetTime.now(); - long diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay()); + long diff = Math.abs(test.toLocalTime().toNanoOfDay() - expected.toLocalTime().toNanoOfDay()); assertTrue(diff < 100000000); // less than 0.1 secs assertEquals(test.getOffset(), nowDT.getOffset()); } @@ -302,7 +295,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { // factories //----------------------------------------------------------------------- private void check(OffsetTime test, int h, int m, int s, int n, ZoneOffset offset) { - assertEquals(test.getTime(), LocalTime.of(h, m, s, n)); + assertEquals(test.toLocalTime(), LocalTime.of(h, m, s, n)); assertEquals(test.getOffset(), offset); assertEquals(test.getHour(), h); @@ -315,24 +308,10 @@ public class TCKOffsetTime extends AbstractDateTimeTest { assertEquals(OffsetTime.of(LocalTime.of(h, m, s, n), offset), test); } - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_intsHM() { - OffsetTime test = OffsetTime.of(LocalTime.of(11, 30), OFFSET_PONE); - check(test, 11, 30, 0, 0, OFFSET_PONE); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_intsHMS() { - OffsetTime test = OffsetTime.of(LocalTime.of(11, 30, 10), OFFSET_PONE); - check(test, 11, 30, 10, 0, OFFSET_PONE); - } - //----------------------------------------------------------------------- @Test(groups={"tck"}) public void factory_intsHMSN() { - OffsetTime test = OffsetTime.of(LocalTime.of(11, 30, 10, 500), OFFSET_PONE); + OffsetTime test = OffsetTime.of(11, 30, 10, 500, OFFSET_PONE); check(test, 11, 30, 10, 500, OFFSET_PONE); } @@ -417,7 +396,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void factory_from_TemporalAccessor_OT() { - assertEquals(OffsetTime.from(OffsetTime.of(LocalTime.of(17, 30), OFFSET_PONE)), OffsetTime.of(LocalTime.of(17, 30), OFFSET_PONE)); + assertEquals(OffsetTime.from(OffsetTime.of(17, 30, 0, 0, OFFSET_PONE)), OffsetTime.of(17, 30, 0, 0, OFFSET_PONE)); } @Test(groups={"tck"}) @@ -487,14 +466,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void factory_parse_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("H m s XXX"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("H m s XXX"); OffsetTime test = OffsetTime.parse("11 30 0 +01:00", f); - assertEquals(test, OffsetTime.of(LocalTime.of(11, 30), ZoneOffset.ofHours(1))); + assertEquals(test, OffsetTime.of(11, 30, 0, 0, ZoneOffset.ofHours(1))); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void factory_parse_formatter_nullText() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d H m s"); OffsetTime.parse((String) null, f); } @@ -522,7 +501,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { Constructor con = OffsetTime.class.getDeclaredConstructor(LocalTime.class, ZoneOffset.class); con.setAccessible(true); try { - con.newInstance(LocalTime.of(11, 30), null); + con.newInstance(LocalTime.of(11, 30, 0, 0), null); } catch (InvocationTargetException ex) { throw ex.getCause(); } @@ -545,7 +524,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { LocalTime localTime = LocalTime.of(h, m, s, n); OffsetTime a = OffsetTime.of(localTime, offset); - assertEquals(a.getTime(), localTime); + assertEquals(a.toLocalTime(), localTime); assertEquals(a.getOffset(), offset); assertEquals(a.toString(), localTime.toString() + offset.toString()); assertEquals(a.getHour(), localTime.getHour()); @@ -559,7 +538,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test public void test_get_TemporalField() { - OffsetTime test = OffsetTime.of(LocalTime.of(12, 30, 40, 987654321), OFFSET_PONE); + OffsetTime test = OffsetTime.of(12, 30, 40, 987654321, OFFSET_PONE); assertEquals(test.get(ChronoField.HOUR_OF_DAY), 12); assertEquals(test.get(ChronoField.MINUTE_OF_HOUR), 30); assertEquals(test.get(ChronoField.SECOND_OF_MINUTE), 40); @@ -572,7 +551,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test public void test_getLong_TemporalField() { - OffsetTime test = OffsetTime.of(LocalTime.of(12, 30, 40, 987654321), OFFSET_PONE); + OffsetTime test = OffsetTime.of(12, 30, 40, 987654321, OFFSET_PONE); assertEquals(test.getLong(ChronoField.HOUR_OF_DAY), 12); assertEquals(test.getLong(ChronoField.MINUTE_OF_HOUR), 30); assertEquals(test.getLong(ChronoField.SECOND_OF_MINUTE), 40); @@ -586,34 +565,27 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- // query(TemporalQuery) //----------------------------------------------------------------------- - @Test - public void test_query_chrono() { - assertEquals(TEST_11_30_59_500_PONE.query(Queries.chrono()), null); - assertEquals(Queries.chrono().queryFrom(TEST_11_30_59_500_PONE), null); + @DataProvider(name="query") + Object[][] data_query() { + return new Object[][] { + {TEST_11_30_59_500_PONE, Queries.chronology(), null}, + {TEST_11_30_59_500_PONE, Queries.zoneId(), null}, + {TEST_11_30_59_500_PONE, Queries.precision(), ChronoUnit.NANOS}, + {TEST_11_30_59_500_PONE, Queries.zone(), OFFSET_PONE}, + {TEST_11_30_59_500_PONE, Queries.offset(), OFFSET_PONE}, + {TEST_11_30_59_500_PONE, Queries.localDate(), null}, + {TEST_11_30_59_500_PONE, Queries.localTime(), LocalTime.of(11, 30, 59, 500)}, + }; } - @Test - public void test_query_zoneId() { - assertEquals(TEST_11_30_59_500_PONE.query(Queries.zoneId()), null); - assertEquals(Queries.zoneId().queryFrom(TEST_11_30_59_500_PONE), null); + @Test(dataProvider="query") + public void test_query(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(temporal.query(query), expected); } - @Test - public void test_query_precision() { - assertEquals(TEST_11_30_59_500_PONE.query(Queries.precision()), NANOS); - assertEquals(Queries.precision().queryFrom(TEST_11_30_59_500_PONE), NANOS); - } - - @Test - public void test_query_offset() { - assertEquals(TEST_11_30_59_500_PONE.query(Queries.offset()), OFFSET_PONE); - assertEquals(Queries.offset().queryFrom(TEST_11_30_59_500_PONE), OFFSET_PONE); - } - - @Test - public void test_query_zone() { - assertEquals(TEST_11_30_59_500_PONE.query(Queries.zone()), OFFSET_PONE); - assertEquals(Queries.zone().queryFrom(TEST_11_30_59_500_PONE), OFFSET_PONE); + @Test(dataProvider="query") + public void test_queryFrom(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(query.queryFrom(temporal), expected); } @Test(expectedExceptions=NullPointerException.class) @@ -626,22 +598,22 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_withOffsetSameLocal() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.withOffsetSameLocal(OFFSET_PTWO); - assertEquals(test.getTime(), base.getTime()); + assertEquals(test.toLocalTime(), base.toLocalTime()); assertEquals(test.getOffset(), OFFSET_PTWO); } @Test(groups={"tck"}) public void test_withOffsetSameLocal_noChange() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.withOffsetSameLocal(OFFSET_PONE); assertEquals(test, base); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_withOffsetSameLocal_null() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); base.withOffsetSameLocal(null); } @@ -650,22 +622,22 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_withOffsetSameInstant() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.withOffsetSameInstant(OFFSET_PTWO); - OffsetTime expected = OffsetTime.of(LocalTime.of(12, 30, 59), OFFSET_PTWO); + OffsetTime expected = OffsetTime.of(12, 30, 59, 0, OFFSET_PTWO); assertEquals(test, expected); } @Test(groups={"tck"}) public void test_withOffsetSameInstant_noChange() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.withOffsetSameInstant(OFFSET_PONE); assertEquals(test, base); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_withOffsetSameInstant_null() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); base.withOffsetSameInstant(null); } @@ -674,7 +646,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_with_adjustment() { - final OffsetTime sample = OffsetTime.of(LocalTime.of(23, 5), OFFSET_PONE); + final OffsetTime sample = OffsetTime.of(23, 5, 0, 0, OFFSET_PONE); TemporalAdjuster adjuster = new TemporalAdjuster() { @Override public Temporal adjustInto(Temporal dateTime) { @@ -687,19 +659,19 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_with_adjustment_LocalTime() { OffsetTime test = TEST_11_30_59_500_PONE.with(LocalTime.of(13, 30)); - assertEquals(test, OffsetTime.of(LocalTime.of(13, 30), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(13, 30, 0, 0, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_with_adjustment_OffsetTime() { - OffsetTime test = TEST_11_30_59_500_PONE.with(OffsetTime.of(LocalTime.of(13, 35), OFFSET_PTWO)); - assertEquals(test, OffsetTime.of(LocalTime.of(13, 35), OFFSET_PTWO)); + OffsetTime test = TEST_11_30_59_500_PONE.with(OffsetTime.of(13, 35, 0, 0, OFFSET_PTWO)); + assertEquals(test, OffsetTime.of(13, 35, 0, 0, OFFSET_PTWO)); } @Test(groups={"tck"}) public void test_with_adjustment_ZoneOffset() { OffsetTime test = TEST_11_30_59_500_PONE.with(OFFSET_PTWO); - assertEquals(test, OffsetTime.of(LocalTime.of(11, 30, 59, 500), OFFSET_PTWO)); + assertEquals(test, OffsetTime.of(11, 30, 59, 500, OFFSET_PTWO)); } @Test(groups={"tck"}) @@ -710,7 +682,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { return dateTime.with(HOUR_OF_DAY, 23); } }); - assertEquals(test, OffsetTime.of(LocalTime.of(23, 30, 59, 500), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(23, 30, 59, 500, OFFSET_PONE)); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) @@ -723,15 +695,15 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_with_TemporalField() { - OffsetTime test = OffsetTime.of(LocalTime.of(12, 30, 40, 987654321), OFFSET_PONE); - assertEquals(test.with(ChronoField.HOUR_OF_DAY, 15), OffsetTime.of(LocalTime.of(15, 30, 40, 987654321), OFFSET_PONE)); - assertEquals(test.with(ChronoField.MINUTE_OF_HOUR, 50), OffsetTime.of(LocalTime.of(12, 50, 40, 987654321), OFFSET_PONE)); - assertEquals(test.with(ChronoField.SECOND_OF_MINUTE, 50), OffsetTime.of(LocalTime.of(12, 30, 50, 987654321), OFFSET_PONE)); - assertEquals(test.with(ChronoField.NANO_OF_SECOND, 12345), OffsetTime.of(LocalTime.of(12, 30, 40, 12345), OFFSET_PONE)); - assertEquals(test.with(ChronoField.HOUR_OF_AMPM, 6), OffsetTime.of(LocalTime.of(18, 30, 40, 987654321), OFFSET_PONE)); - assertEquals(test.with(ChronoField.AMPM_OF_DAY, 0), OffsetTime.of(LocalTime.of(0, 30, 40, 987654321), OFFSET_PONE)); + OffsetTime test = OffsetTime.of(12, 30, 40, 987654321, OFFSET_PONE); + assertEquals(test.with(ChronoField.HOUR_OF_DAY, 15), OffsetTime.of(15, 30, 40, 987654321, OFFSET_PONE)); + assertEquals(test.with(ChronoField.MINUTE_OF_HOUR, 50), OffsetTime.of(12, 50, 40, 987654321, OFFSET_PONE)); + assertEquals(test.with(ChronoField.SECOND_OF_MINUTE, 50), OffsetTime.of(12, 30, 50, 987654321, OFFSET_PONE)); + assertEquals(test.with(ChronoField.NANO_OF_SECOND, 12345), OffsetTime.of(12, 30, 40, 12345, OFFSET_PONE)); + assertEquals(test.with(ChronoField.HOUR_OF_AMPM, 6), OffsetTime.of(18, 30, 40, 987654321, OFFSET_PONE)); + assertEquals(test.with(ChronoField.AMPM_OF_DAY, 0), OffsetTime.of(0, 30, 40, 987654321, OFFSET_PONE)); - assertEquals(test.with(ChronoField.OFFSET_SECONDS, 7205), OffsetTime.of(LocalTime.of(12, 30, 40, 987654321), ZoneOffset.ofHoursMinutesSeconds(2, 0, 5))); + assertEquals(test.with(ChronoField.OFFSET_SECONDS, 7205), OffsetTime.of(12, 30, 40, 987654321, ZoneOffset.ofHoursMinutesSeconds(2, 0, 5))); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"} ) @@ -749,14 +721,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_withHour_normal() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.withHour(15); - assertEquals(test, OffsetTime.of(LocalTime.of(15, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(15, 30, 59, 0, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_withHour_noChange() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.withHour(11); assertEquals(test, base); } @@ -766,14 +738,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_withMinute_normal() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.withMinute(15); - assertEquals(test, OffsetTime.of(LocalTime.of(11, 15, 59), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(11, 15, 59, 0, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_withMinute_noChange() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.withMinute(30); assertEquals(test, base); } @@ -783,14 +755,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_withSecond_normal() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.withSecond(15); - assertEquals(test, OffsetTime.of(LocalTime.of(11, 30, 15), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(11, 30, 15, 0, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_withSecond_noChange() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.withSecond(59); assertEquals(test, base); } @@ -800,14 +772,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_withNanoOfSecond_normal() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59, 1), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 1, OFFSET_PONE); OffsetTime test = base.withNano(15); - assertEquals(test, OffsetTime.of(LocalTime.of(11, 30, 59, 15), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(11, 30, 59, 15, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_withNanoOfSecond_noChange() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59, 1), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 1, OFFSET_PONE); OffsetTime test = base.withNano(1); assertEquals(test, base); } @@ -834,7 +806,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { public void test_plus_PlusAdjuster() { MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MINUTES); OffsetTime t = TEST_11_30_59_500_PONE.plus(period); - assertEquals(t, OffsetTime.of(LocalTime.of(11, 37, 59, 500), OFFSET_PONE)); + assertEquals(t, OffsetTime.of(11, 37, 59, 500, OFFSET_PONE)); } @Test(groups={"tck"}) @@ -851,7 +823,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_plus_PlusAdjuster_null() { - TEST_11_30_59_500_PONE.plus((TemporalAdder) null); + TEST_11_30_59_500_PONE.plus((TemporalAmount) null); } //----------------------------------------------------------------------- @@ -859,14 +831,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_plusHours() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.plusHours(13); - assertEquals(test, OffsetTime.of(LocalTime.of(0, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(0, 30, 59, 0, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_plusHours_zero() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.plusHours(0); assertEquals(test, base); } @@ -876,14 +848,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_plusMinutes() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.plusMinutes(30); - assertEquals(test, OffsetTime.of(LocalTime.of(12, 0, 59), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(12, 0, 59, 0, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_plusMinutes_zero() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.plusMinutes(0); assertEquals(test, base); } @@ -893,14 +865,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_plusSeconds() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.plusSeconds(1); - assertEquals(test, OffsetTime.of(LocalTime.of(11, 31, 0), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(11, 31, 0, 0, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_plusSeconds_zero() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.plusSeconds(0); assertEquals(test, base); } @@ -910,14 +882,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_plusNanos() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59, 0), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.plusNanos(1); - assertEquals(test, OffsetTime.of(LocalTime.of(11, 30, 59, 1), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(11, 30, 59, 1, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_plusNanos_zero() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.plusNanos(0); assertEquals(test, base); } @@ -929,7 +901,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { public void test_minus_MinusAdjuster() { MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MINUTES); OffsetTime t = TEST_11_30_59_500_PONE.minus(period); - assertEquals(t, OffsetTime.of(LocalTime.of(11, 23, 59, 500), OFFSET_PONE)); + assertEquals(t, OffsetTime.of(11, 23, 59, 500, OFFSET_PONE)); } @Test(groups={"tck"}) @@ -946,7 +918,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_minus_MinusAdjuster_null() { - TEST_11_30_59_500_PONE.minus((TemporalSubtractor) null); + TEST_11_30_59_500_PONE.minus((TemporalAmount) null); } //----------------------------------------------------------------------- @@ -954,14 +926,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_minusHours() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.minusHours(-13); - assertEquals(test, OffsetTime.of(LocalTime.of(0, 30, 59), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(0, 30, 59, 0, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_minusHours_zero() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.minusHours(0); assertEquals(test, base); } @@ -971,14 +943,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_minusMinutes() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.minusMinutes(50); - assertEquals(test, OffsetTime.of(LocalTime.of(10, 40, 59), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(10, 40, 59, 0, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_minusMinutes_zero() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.minusMinutes(0); assertEquals(test, base); } @@ -988,14 +960,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_minusSeconds() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.minusSeconds(60); - assertEquals(test, OffsetTime.of(LocalTime.of(11, 29, 59), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(11, 29, 59, 0, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_minusSeconds_zero() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.minusSeconds(0); assertEquals(test, base); } @@ -1005,14 +977,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_minusNanos() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59, 0), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.minusNanos(1); - assertEquals(test, OffsetTime.of(LocalTime.of(11, 30, 58, 999999999), OFFSET_PONE)); + assertEquals(test, OffsetTime.of(11, 30, 58, 999999999, OFFSET_PONE)); } @Test(groups={"tck"}) public void test_minusNanos_zero() { - OffsetTime base = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime base = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); OffsetTime test = base.minusNanos(0); assertEquals(test, base); } @@ -1022,8 +994,8 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_compareTo_time() { - OffsetTime a = OffsetTime.of(LocalTime.of(11, 29), OFFSET_PONE); - OffsetTime b = OffsetTime.of(LocalTime.of(11, 30), OFFSET_PONE); // a is before b due to time + OffsetTime a = OffsetTime.of(11, 29, 0, 0, OFFSET_PONE); + OffsetTime b = OffsetTime.of(11, 30, 0, 0, OFFSET_PONE); // a is before b due to time assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1033,8 +1005,8 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_offset() { - OffsetTime a = OffsetTime.of(LocalTime.of(11, 30), OFFSET_PTWO); - OffsetTime b = OffsetTime.of(LocalTime.of(11, 30), OFFSET_PONE); // a is before b due to offset + OffsetTime a = OffsetTime.of(11, 30, 0, 0, OFFSET_PTWO); + OffsetTime b = OffsetTime.of(11, 30, 0, 0, OFFSET_PONE); // a is before b due to offset assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1044,8 +1016,8 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_both() { - OffsetTime a = OffsetTime.of(LocalTime.of(11, 50), OFFSET_PTWO); - OffsetTime b = OffsetTime.of(LocalTime.of(11, 20), OFFSET_PONE); // a is before b on instant scale + OffsetTime a = OffsetTime.of(11, 50, 0, 0, OFFSET_PTWO); + OffsetTime b = OffsetTime.of(11, 20, 0, 0, OFFSET_PONE); // a is before b on instant scale assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1055,8 +1027,8 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_bothNearStartOfDay() { - OffsetTime a = OffsetTime.of(LocalTime.of(0, 10), OFFSET_PONE); - OffsetTime b = OffsetTime.of(LocalTime.of(2, 30), OFFSET_PTWO); // a is before b on instant scale + OffsetTime a = OffsetTime.of(0, 10, 0, 0, OFFSET_PONE); + OffsetTime b = OffsetTime.of(2, 30, 0, 0, OFFSET_PTWO); // a is before b on instant scale assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1066,8 +1038,8 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_hourDifference() { - OffsetTime a = OffsetTime.of(LocalTime.of(10, 0), OFFSET_PONE); - OffsetTime b = OffsetTime.of(LocalTime.of(11, 0), OFFSET_PTWO); // a is before b despite being same time-line time + OffsetTime a = OffsetTime.of(10, 0, 0, 0, OFFSET_PONE); + OffsetTime b = OffsetTime.of(11, 0, 0, 0, OFFSET_PTWO); // a is before b despite being same time-line time assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1077,7 +1049,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_compareTo_null() { - OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime a = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); a.compareTo(null); } @@ -1089,7 +1061,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { } private Instant convertInstant(OffsetTime ot) { - return DATE.atTime(ot.getTime()).toInstant(ot.getOffset()); + return DATE.atTime(ot.toLocalTime()).toInstant(ot.getOffset()); } //----------------------------------------------------------------------- @@ -1097,8 +1069,8 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_isBeforeIsAfterIsEqual1() { - OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 58), OFFSET_PONE); - OffsetTime b = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); // a is before b due to time + OffsetTime a = OffsetTime.of(11, 30, 58, 0, OFFSET_PONE); + OffsetTime b = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); // a is before b due to time assertEquals(a.isBefore(b), true); assertEquals(a.isEqual(b), false); assertEquals(a.isAfter(b), false); @@ -1119,8 +1091,8 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_isBeforeIsAfterIsEqual1nanos() { - OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59, 3), OFFSET_PONE); - OffsetTime b = OffsetTime.of(LocalTime.of(11, 30, 59, 4), OFFSET_PONE); // a is before b due to time + OffsetTime a = OffsetTime.of(11, 30, 59, 3, OFFSET_PONE); + OffsetTime b = OffsetTime.of(11, 30, 59, 4, OFFSET_PONE); // a is before b due to time assertEquals(a.isBefore(b), true); assertEquals(a.isEqual(b), false); assertEquals(a.isAfter(b), false); @@ -1141,8 +1113,8 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_isBeforeIsAfterIsEqual2() { - OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PTWO); - OffsetTime b = OffsetTime.of(LocalTime.of(11, 30, 58), OFFSET_PONE); // a is before b due to offset + OffsetTime a = OffsetTime.of(11, 30, 59, 0, OFFSET_PTWO); + OffsetTime b = OffsetTime.of(11, 30, 58, 0, OFFSET_PONE); // a is before b due to offset assertEquals(a.isBefore(b), true); assertEquals(a.isEqual(b), false); assertEquals(a.isAfter(b), false); @@ -1163,8 +1135,8 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_isBeforeIsAfterIsEqual2nanos() { - OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59, 4), ZoneOffset.ofTotalSeconds(OFFSET_PONE.getTotalSeconds() + 1)); - OffsetTime b = OffsetTime.of(LocalTime.of(11, 30, 59, 3), OFFSET_PONE); // a is before b due to offset + OffsetTime a = OffsetTime.of(11, 30, 59, 4, ZoneOffset.ofTotalSeconds(OFFSET_PONE.getTotalSeconds() + 1)); + OffsetTime b = OffsetTime.of(11, 30, 59, 3, OFFSET_PONE); // a is before b due to offset assertEquals(a.isBefore(b), true); assertEquals(a.isEqual(b), false); assertEquals(a.isAfter(b), false); @@ -1185,8 +1157,8 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_isBeforeIsAfterIsEqual_instantComparison() { - OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PTWO); - OffsetTime b = OffsetTime.of(LocalTime.of(10, 30, 59), OFFSET_PONE); // a is same instant as b + OffsetTime a = OffsetTime.of(11, 30, 59, 0, OFFSET_PTWO); + OffsetTime b = OffsetTime.of(10, 30, 59, 0, OFFSET_PONE); // a is same instant as b assertEquals(a.isBefore(b), false); assertEquals(a.isEqual(b), true); assertEquals(a.isAfter(b), false); @@ -1207,19 +1179,19 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_isBefore_null() { - OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime a = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); a.isBefore(null); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_isAfter_null() { - OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime a = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); a.isAfter(null); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_isEqual_null() { - OffsetTime a = OffsetTime.of(LocalTime.of(11, 30, 59), OFFSET_PONE); + OffsetTime a = OffsetTime.of(11, 30, 59, 0, OFFSET_PONE); a.isEqual(null); } @@ -1228,43 +1200,43 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_true(int h, int m, int s, int n, ZoneOffset ignored) { - OffsetTime a = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetTime b = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE); + OffsetTime a = OffsetTime.of(h, m, s, n, OFFSET_PONE); + OffsetTime b = OffsetTime.of(h, m, s, n, OFFSET_PONE); assertEquals(a.equals(b), true); assertEquals(a.hashCode() == b.hashCode(), true); } @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_false_hour_differs(int h, int m, int s, int n, ZoneOffset ignored) { h = (h == 23 ? 22 : h); - OffsetTime a = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetTime b = OffsetTime.of(LocalTime.of(h + 1, m, s, n), OFFSET_PONE); + OffsetTime a = OffsetTime.of(h, m, s, n, OFFSET_PONE); + OffsetTime b = OffsetTime.of(h + 1, m, s, n, OFFSET_PONE); assertEquals(a.equals(b), false); } @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_false_minute_differs(int h, int m, int s, int n, ZoneOffset ignored) { m = (m == 59 ? 58 : m); - OffsetTime a = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetTime b = OffsetTime.of(LocalTime.of(h, m + 1, s, n), OFFSET_PONE); + OffsetTime a = OffsetTime.of(h, m, s, n, OFFSET_PONE); + OffsetTime b = OffsetTime.of(h, m + 1, s, n, OFFSET_PONE); assertEquals(a.equals(b), false); } @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_false_second_differs(int h, int m, int s, int n, ZoneOffset ignored) { s = (s == 59 ? 58 : s); - OffsetTime a = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetTime b = OffsetTime.of(LocalTime.of(h, m, s + 1, n), OFFSET_PONE); + OffsetTime a = OffsetTime.of(h, m, s, n, OFFSET_PONE); + OffsetTime b = OffsetTime.of(h, m, s + 1, n, OFFSET_PONE); assertEquals(a.equals(b), false); } @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_false_nano_differs(int h, int m, int s, int n, ZoneOffset ignored) { n = (n == 999999999 ? 999999998 : n); - OffsetTime a = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetTime b = OffsetTime.of(LocalTime.of(h, m, s, n + 1), OFFSET_PONE); + OffsetTime a = OffsetTime.of(h, m, s, n, OFFSET_PONE); + OffsetTime b = OffsetTime.of(h, m, s, n + 1, OFFSET_PONE); assertEquals(a.equals(b), false); } @Test(dataProvider="sampleTimes", groups={"tck"}) public void test_equals_false_offset_differs(int h, int m, int s, int n, ZoneOffset ignored) { - OffsetTime a = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PONE); - OffsetTime b = OffsetTime.of(LocalTime.of(h, m, s, n), OFFSET_PTWO); + OffsetTime a = OffsetTime.of(h, m, s, n, OFFSET_PONE); + OffsetTime b = OffsetTime.of(h, m, s, n, OFFSET_PTWO); assertEquals(a.equals(b), false); } @@ -1302,7 +1274,7 @@ public class TCKOffsetTime extends AbstractDateTimeTest { @Test(dataProvider="sampleToString", groups={"tck"}) public void test_toString(int h, int m, int s, int n, String offsetId, String expected) { - OffsetTime t = OffsetTime.of(LocalTime.of(h, m, s, n), ZoneOffset.of(offsetId)); + OffsetTime t = OffsetTime.of(h, m, s, n, ZoneOffset.of(offsetId)); String str = t.toString(); assertEquals(str, expected); } @@ -1312,14 +1284,14 @@ public class TCKOffsetTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_toString_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("H m s"); - String t = OffsetTime.of(LocalTime.of(11, 30), OFFSET_PONE).toString(f); + DateTimeFormatter f = DateTimeFormatter.ofPattern("H m s"); + String t = OffsetTime.of(11, 30, 0, 0, OFFSET_PONE).toString(f); assertEquals(t, "11 30 0"); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_toString_formatter_null() { - OffsetTime.of(LocalTime.of(11, 30), OFFSET_PONE).toString(null); + OffsetTime.of(11, 30, 0, 0, OFFSET_PONE).toString(null); } } diff --git a/jdk/test/java/time/tck/java/time/TCKPeriod.java b/jdk/test/java/time/tck/java/time/TCKPeriod.java new file mode 100644 index 00000000000..7399b50054e --- /dev/null +++ b/jdk/test/java/time/tck/java/time/TCKPeriod.java @@ -0,0 +1,906 @@ +/* + * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time; + +import static org.testng.Assert.assertEquals; + +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.Period; +import java.time.format.DateTimeParseException; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalUnit; +import java.util.List; +import java.util.Locale; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test Period. + */ +@Test +public class TCKPeriod extends AbstractTCKTest { + + //----------------------------------------------------------------------- + @Test + public void test_serialization() throws Exception { + assertSerializable(Period.ZERO); + assertSerializable(Period.ofDays(1)); + assertSerializable(Period.of(1, 2, 3)); + } + + //----------------------------------------------------------------------- + // ofYears(int) + //----------------------------------------------------------------------- + @Test + public void factory_ofYears_int() { + assertPeriod(Period.ofYears(0), 0, 0, 0); + assertPeriod(Period.ofYears(1), 1, 0, 0); + assertPeriod(Period.ofYears(234), 234, 0, 0); + assertPeriod(Period.ofYears(-100), -100, 0, 0); + assertPeriod(Period.ofYears(Integer.MAX_VALUE), Integer.MAX_VALUE, 0, 0); + assertPeriod(Period.ofYears(Integer.MIN_VALUE), Integer.MIN_VALUE, 0, 0); + } + + //----------------------------------------------------------------------- + // ofMonths(int) + //----------------------------------------------------------------------- + @Test + public void factory_ofMonths_int() { + assertPeriod(Period.ofMonths(0), 0, 0, 0); + assertPeriod(Period.ofMonths(1), 0, 1, 0); + assertPeriod(Period.ofMonths(234), 0, 234, 0); + assertPeriod(Period.ofMonths(-100), 0, -100, 0); + assertPeriod(Period.ofMonths(Integer.MAX_VALUE), 0, Integer.MAX_VALUE, 0); + assertPeriod(Period.ofMonths(Integer.MIN_VALUE), 0, Integer.MIN_VALUE, 0); + } + + //----------------------------------------------------------------------- + // ofDays(int) + //----------------------------------------------------------------------- + @Test + public void factory_ofDay_int() { + assertPeriod(Period.ofDays(0), 0, 0, 0); + assertPeriod(Period.ofDays(1), 0, 0, 1); + assertPeriod(Period.ofDays(234), 0, 0, 234); + assertPeriod(Period.ofDays(-100), 0, 0, -100); + assertPeriod(Period.ofDays(Integer.MAX_VALUE), 0, 0, Integer.MAX_VALUE); + assertPeriod(Period.ofDays(Integer.MIN_VALUE), 0, 0, Integer.MIN_VALUE); + } + + //----------------------------------------------------------------------- + // of(int3) + //----------------------------------------------------------------------- + @Test + public void factory_of_ints() { + assertPeriod(Period.of(1, 2, 3), 1, 2, 3); + assertPeriod(Period.of(0, 2, 3), 0, 2, 3); + assertPeriod(Period.of(1, 0, 0), 1, 0, 0); + assertPeriod(Period.of(0, 0, 0), 0, 0, 0); + assertPeriod(Period.of(-1, -2, -3), -1, -2, -3); + } + + //----------------------------------------------------------------------- + // parse(String) + //----------------------------------------------------------------------- + @DataProvider(name="parseSuccess") + Object[][] data_factory_parseSuccess() { + return new Object[][] { + {"P1Y", Period.ofYears(1)}, + {"P12Y", Period.ofYears(12)}, + {"P987654321Y", Period.ofYears(987654321)}, + {"P+1Y", Period.ofYears(1)}, + {"P+12Y", Period.ofYears(12)}, + {"P+987654321Y", Period.ofYears(987654321)}, + {"P+0Y", Period.ofYears(0)}, + {"P0Y", Period.ofYears(0)}, + {"P-0Y", Period.ofYears(0)}, + {"P-25Y", Period.ofYears(-25)}, + {"P-987654321Y", Period.ofYears(-987654321)}, + {"P" + Integer.MAX_VALUE + "Y", Period.ofYears(Integer.MAX_VALUE)}, + {"P" + Integer.MIN_VALUE + "Y", Period.ofYears(Integer.MIN_VALUE)}, + + {"P1M", Period.ofMonths(1)}, + {"P12M", Period.ofMonths(12)}, + {"P987654321M", Period.ofMonths(987654321)}, + {"P+1M", Period.ofMonths(1)}, + {"P+12M", Period.ofMonths(12)}, + {"P+987654321M", Period.ofMonths(987654321)}, + {"P+0M", Period.ofMonths(0)}, + {"P0M", Period.ofMonths(0)}, + {"P-0M", Period.ofMonths(0)}, + {"P-25M", Period.ofMonths(-25)}, + {"P-987654321M", Period.ofMonths(-987654321)}, + {"P" + Integer.MAX_VALUE + "M", Period.ofMonths(Integer.MAX_VALUE)}, + {"P" + Integer.MIN_VALUE + "M", Period.ofMonths(Integer.MIN_VALUE)}, + + {"P1D", Period.ofDays(1)}, + {"P12D", Period.ofDays(12)}, + {"P987654321D", Period.ofDays(987654321)}, + {"P+1D", Period.ofDays(1)}, + {"P+12D", Period.ofDays(12)}, + {"P+987654321D", Period.ofDays(987654321)}, + {"P+0D", Period.ofDays(0)}, + {"P0D", Period.ofDays(0)}, + {"P-0D", Period.ofDays(0)}, + {"P-25D", Period.ofDays(-25)}, + {"P-987654321D", Period.ofDays(-987654321)}, + {"P" + Integer.MAX_VALUE + "D", Period.ofDays(Integer.MAX_VALUE)}, + {"P" + Integer.MIN_VALUE + "D", Period.ofDays(Integer.MIN_VALUE)}, + + {"P0Y0M0D", Period.of(0, 0, 0)}, + {"P2Y0M0D", Period.of(2, 0, 0)}, + {"P0Y3M0D", Period.of(0, 3, 0)}, + {"P0Y0M4D", Period.of(0, 0, 4)}, + {"P2Y3M25D", Period.of(2, 3, 25)}, + {"P-2Y3M25D", Period.of(-2, 3, 25)}, + {"P2Y-3M25D", Period.of(2, -3, 25)}, + {"P2Y3M-25D", Period.of(2, 3, -25)}, + {"P-2Y-3M-25D", Period.of(-2, -3, -25)}, + }; + } + + @Test(dataProvider="parseSuccess") + public void factory_parse(String text, Period expected) { + Period p = Period.parse(text); + assertEquals(p, expected); + } + + @Test(dataProvider="parseSuccess") + public void factory_parse_plus(String text, Period expected) { + Period p = Period.parse("+" + text); + assertEquals(p, expected); + } + + @Test(dataProvider="parseSuccess") + public void factory_parse_minus(String text, Period expected) { + Period p = null; + try { + p = Period.parse("-" + text); + } catch (DateTimeParseException ex) { + assertEquals(expected.getYears() == Integer.MIN_VALUE || + expected.getMonths() == Integer.MIN_VALUE || + expected.getDays() == Integer.MIN_VALUE, true); + return; + } + // not inside try/catch or it breaks test + assertEquals(p, expected.negated()); + } + + @Test(dataProvider="parseSuccess") + public void factory_parse_lowerCase(String text, Period expected) { + Period p = Period.parse(text.toLowerCase(Locale.ENGLISH)); + assertEquals(p, expected); + } + + @DataProvider(name="parseFailure") + Object[][] data_parseFailure() { + return new Object[][] { + {""}, + {"PTD"}, + {"AT0D"}, + {"PA0D"}, + {"PT0A"}, + + {"PT+D"}, + {"PT-D"}, + {"PT.D"}, + {"PTAD"}, + + {"PT+0D"}, + {"PT-0D"}, + {"PT+1D"}, + {"PT-.D"}, + + {"P1Y1MT1D"}, + {"P1YMD"}, + {"P1Y2Y"}, + {"PT1M+3S"}, + + {"PT1S1"}, + {"PT1S."}, + {"PT1SA"}, + {"PT1M1"}, + {"PT1M."}, + {"PT1MA"}, + + {"P"+ (((long) Integer.MAX_VALUE) + 1) + "Y"}, + {"P"+ (((long) Integer.MAX_VALUE) + 1) + "M"}, + {"P"+ (((long) Integer.MAX_VALUE) + 1) + "D"}, + {"P"+ (((long) Integer.MIN_VALUE) - 1) + "Y"}, + {"P"+ (((long) Integer.MIN_VALUE) - 1) + "M"}, + {"P"+ (((long) Integer.MIN_VALUE) - 1) + "D"}, + + {"Rubbish"}, + }; + } + + @Test(dataProvider="parseFailure", expectedExceptions=DateTimeParseException.class) + public void factory_parseFailures(String text) { + try { + Period.parse(text); + } catch (DateTimeParseException ex) { + assertEquals(ex.getParsedString(), text); + throw ex; + } + } + + @Test(expectedExceptions=NullPointerException.class) + public void factory_parse_null() { + Period.parse(null); + } + + //----------------------------------------------------------------------- + // between(LocalDate,LocalDate) + //----------------------------------------------------------------------- + @DataProvider(name="between") + Object[][] data_between() { + return new Object[][] { + {2010, 1, 1, 2010, 1, 1, 0, 0, 0}, + {2010, 1, 1, 2010, 1, 2, 0, 0, 1}, + {2010, 1, 1, 2010, 1, 31, 0, 0, 30}, + {2010, 1, 1, 2010, 2, 1, 0, 1, 0}, + {2010, 1, 1, 2010, 2, 28, 0, 1, 27}, + {2010, 1, 1, 2010, 3, 1, 0, 2, 0}, + {2010, 1, 1, 2010, 12, 31, 0, 11, 30}, + {2010, 1, 1, 2011, 1, 1, 1, 0, 0}, + {2010, 1, 1, 2011, 12, 31, 1, 11, 30}, + {2010, 1, 1, 2012, 1, 1, 2, 0, 0}, + + {2010, 1, 10, 2010, 1, 1, 0, 0, -9}, + {2010, 1, 10, 2010, 1, 2, 0, 0, -8}, + {2010, 1, 10, 2010, 1, 9, 0, 0, -1}, + {2010, 1, 10, 2010, 1, 10, 0, 0, 0}, + {2010, 1, 10, 2010, 1, 11, 0, 0, 1}, + {2010, 1, 10, 2010, 1, 31, 0, 0, 21}, + {2010, 1, 10, 2010, 2, 1, 0, 0, 22}, + {2010, 1, 10, 2010, 2, 9, 0, 0, 30}, + {2010, 1, 10, 2010, 2, 10, 0, 1, 0}, + {2010, 1, 10, 2010, 2, 28, 0, 1, 18}, + {2010, 1, 10, 2010, 3, 1, 0, 1, 19}, + {2010, 1, 10, 2010, 3, 9, 0, 1, 27}, + {2010, 1, 10, 2010, 3, 10, 0, 2, 0}, + {2010, 1, 10, 2010, 12, 31, 0, 11, 21}, + {2010, 1, 10, 2011, 1, 1, 0, 11, 22}, + {2010, 1, 10, 2011, 1, 9, 0, 11, 30}, + {2010, 1, 10, 2011, 1, 10, 1, 0, 0}, + + {2010, 3, 30, 2011, 5, 1, 1, 1, 1}, + {2010, 4, 30, 2011, 5, 1, 1, 0, 1}, + + {2010, 2, 28, 2012, 2, 27, 1, 11, 30}, + {2010, 2, 28, 2012, 2, 28, 2, 0, 0}, + {2010, 2, 28, 2012, 2, 29, 2, 0, 1}, + + {2012, 2, 28, 2014, 2, 27, 1, 11, 30}, + {2012, 2, 28, 2014, 2, 28, 2, 0, 0}, + {2012, 2, 28, 2014, 3, 1, 2, 0, 1}, + + {2012, 2, 29, 2014, 2, 28, 1, 11, 30}, + {2012, 2, 29, 2014, 3, 1, 2, 0, 1}, + {2012, 2, 29, 2014, 3, 2, 2, 0, 2}, + + {2012, 2, 29, 2016, 2, 28, 3, 11, 30}, + {2012, 2, 29, 2016, 2, 29, 4, 0, 0}, + {2012, 2, 29, 2016, 3, 1, 4, 0, 1}, + + {2010, 1, 1, 2009, 12, 31, 0, 0, -1}, + {2010, 1, 1, 2009, 12, 30, 0, 0, -2}, + {2010, 1, 1, 2009, 12, 2, 0, 0, -30}, + {2010, 1, 1, 2009, 12, 1, 0, -1, 0}, + {2010, 1, 1, 2009, 11, 30, 0, -1, -1}, + {2010, 1, 1, 2009, 11, 2, 0, -1, -29}, + {2010, 1, 1, 2009, 11, 1, 0, -2, 0}, + {2010, 1, 1, 2009, 1, 2, 0, -11, -30}, + {2010, 1, 1, 2009, 1, 1, -1, 0, 0}, + + {2010, 1, 15, 2010, 1, 15, 0, 0, 0}, + {2010, 1, 15, 2010, 1, 14, 0, 0, -1}, + {2010, 1, 15, 2010, 1, 1, 0, 0, -14}, + {2010, 1, 15, 2009, 12, 31, 0, 0, -15}, + {2010, 1, 15, 2009, 12, 16, 0, 0, -30}, + {2010, 1, 15, 2009, 12, 15, 0, -1, 0}, + {2010, 1, 15, 2009, 12, 14, 0, -1, -1}, + + {2010, 2, 28, 2009, 3, 1, 0, -11, -27}, + {2010, 2, 28, 2009, 2, 28, -1, 0, 0}, + {2010, 2, 28, 2009, 2, 27, -1, 0, -1}, + + {2010, 2, 28, 2008, 2, 29, -1, -11, -28}, + {2010, 2, 28, 2008, 2, 28, -2, 0, 0}, + {2010, 2, 28, 2008, 2, 27, -2, 0, -1}, + + {2012, 2, 29, 2009, 3, 1, -2, -11, -28}, + {2012, 2, 29, 2009, 2, 28, -3, 0, -1}, + {2012, 2, 29, 2009, 2, 27, -3, 0, -2}, + + {2012, 2, 29, 2008, 3, 1, -3, -11, -28}, + {2012, 2, 29, 2008, 2, 29, -4, 0, 0}, + {2012, 2, 29, 2008, 2, 28, -4, 0, -1}, + }; + } + + @Test(dataProvider="between") + public void factory_between_LocalDate(int y1, int m1, int d1, int y2, int m2, int d2, int ye, int me, int de) { + LocalDate start = LocalDate.of(y1, m1, d1); + LocalDate end = LocalDate.of(y2, m2, d2); + Period test = Period.between(start, end); + assertPeriod(test, ye, me, de); + //assertEquals(start.plus(test), end); + } + + @Test(expectedExceptions=NullPointerException.class) + public void factory_between_LocalDate_nullFirst() { + Period.between((LocalDate) null, LocalDate.of(2010, 1, 1)); + } + + @Test(expectedExceptions=NullPointerException.class) + public void factory_between_LocalDate_nullSecond() { + Period.between(LocalDate.of(2010, 1, 1), (LocalDate) null); + } + + //----------------------------------------------------------------------- + // isZero() + //----------------------------------------------------------------------- + @Test + public void test_isZero() { + assertEquals(Period.of(0, 0, 0).isZero(), true); + assertEquals(Period.of(1, 2, 3).isZero(), false); + assertEquals(Period.of(1, 0, 0).isZero(), false); + assertEquals(Period.of(0, 2, 0).isZero(), false); + assertEquals(Period.of(0, 0, 3).isZero(), false); + } + + //----------------------------------------------------------------------- + // isNegative() + //----------------------------------------------------------------------- + @Test + public void test_isPositive() { + assertEquals(Period.of(0, 0, 0).isNegative(), false); + assertEquals(Period.of(1, 2, 3).isNegative(), false); + assertEquals(Period.of(1, 0, 0).isNegative(), false); + assertEquals(Period.of(0, 2, 0).isNegative(), false); + assertEquals(Period.of(0, 0, 3).isNegative(), false); + + assertEquals(Period.of(-1, -2, -3).isNegative(), true); + assertEquals(Period.of(-1, -2, 3).isNegative(), true); + assertEquals(Period.of(1, -2, -3).isNegative(), true); + assertEquals(Period.of(-1, 2, -3).isNegative(), true); + assertEquals(Period.of(-1, 2, 3).isNegative(), true); + assertEquals(Period.of(1, -2, 3).isNegative(), true); + assertEquals(Period.of(1, 2, -3).isNegative(), true); + } + + //----------------------------------------------------------------------- + // withYears() + //----------------------------------------------------------------------- + @Test + public void test_withYears() { + assertPeriod(Period.of(1, 2, 3).withYears(1), 1, 2, 3); + assertPeriod(Period.of(1, 2, 3).withYears(10), 10, 2, 3); + assertPeriod(Period.of(1, 2, 3).withYears(-10), -10, 2, 3); + assertPeriod(Period.of(-1, -2, -3).withYears(10), 10, -2, -3); + assertPeriod(Period.of(1, 2, 3).withYears(0), 0, 2, 3); + } + + //----------------------------------------------------------------------- + // withMonths() + //----------------------------------------------------------------------- + @Test + public void test_withMonths() { + assertPeriod(Period.of(1, 2, 3).withMonths(2), 1, 2, 3); + assertPeriod(Period.of(1, 2, 3).withMonths(10), 1, 10, 3); + assertPeriod(Period.of(1, 2, 3).withMonths(-10), 1, -10, 3); + assertPeriod(Period.of(-1, -2, -3).withMonths(10), -1, 10, -3); + assertPeriod(Period.of(1, 2, 3).withMonths(0), 1, 0, 3); + } + + //----------------------------------------------------------------------- + // withDays() + //----------------------------------------------------------------------- + @Test + public void test_withDays() { + assertPeriod(Period.of(1, 2, 3).withDays(3), 1, 2, 3); + assertPeriod(Period.of(1, 2, 3).withDays(10), 1, 2, 10); + assertPeriod(Period.of(1, 2, 3).withDays(-10), 1, 2, -10); + assertPeriod(Period.of(-1, -2, -3).withDays(10), -1, -2, 10); + assertPeriod(Period.of(1, 2, 3).withDays(0), 1, 2, 0); + } + + //----------------------------------------------------------------------- + // plusYears() + //----------------------------------------------------------------------- + @Test + public void test_plusYears() { + assertPeriod(Period.of(1, 2, 3).plusYears(0), 1, 2, 3); + assertPeriod(Period.of(1, 2, 3).plusYears(10), 11, 2, 3); + assertPeriod(Period.of(1, 2, 3).plusYears(-10), -9, 2, 3); + assertPeriod(Period.of(1, 2, 3).plusYears(-1), 0, 2, 3); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_plusYears_overflowTooBig() { + Period test = Period.ofYears(Integer.MAX_VALUE); + test.plusYears(1); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_plusYears_overflowTooSmall() { + Period test = Period.ofYears(Integer.MIN_VALUE); + test.plusYears(-1); + } + + //----------------------------------------------------------------------- + // plusMonths() + //----------------------------------------------------------------------- + @Test + public void test_plusMonths() { + assertPeriod(Period.of(1, 2, 3).plusMonths(0), 1, 2, 3); + assertPeriod(Period.of(1, 2, 3).plusMonths(10), 1, 12, 3); + assertPeriod(Period.of(1, 2, 3).plusMonths(-10), 1, -8, 3); + assertPeriod(Period.of(1, 2, 3).plusMonths(-2), 1, 0, 3); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_plusMonths_overflowTooBig() { + Period test = Period.ofMonths(Integer.MAX_VALUE); + test.plusMonths(1); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_plusMonths_overflowTooSmall() { + Period test = Period.ofMonths(Integer.MIN_VALUE); + test.plusMonths(-1); + } + + //----------------------------------------------------------------------- + // plusDays() + //----------------------------------------------------------------------- + @Test + public void test_plusDays() { + assertPeriod(Period.of(1, 2, 3).plusDays(0), 1, 2, 3); + assertPeriod(Period.of(1, 2, 3).plusDays(10), 1, 2, 13); + assertPeriod(Period.of(1, 2, 3).plusDays(-10), 1, 2, -7); + assertPeriod(Period.of(1, 2, 3).plusDays(-3), 1, 2, 0); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_plusDays_overflowTooBig() { + Period test = Period.ofDays(Integer.MAX_VALUE); + test.plusDays(1); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_plusDays_overflowTooSmall() { + Period test = Period.ofDays(Integer.MIN_VALUE); + test.plusDays(-1); + } + + //----------------------------------------------------------------------- + // multipliedBy() + //----------------------------------------------------------------------- + @Test + public void test_multipliedBy() { + Period test = Period.of(1, 2, 3); + assertPeriod(test.multipliedBy(0), 0, 0, 0); + assertPeriod(test.multipliedBy(1), 1, 2, 3); + assertPeriod(test.multipliedBy(2), 2, 4, 6); + assertPeriod(test.multipliedBy(-3), -3, -6, -9); + } + + @Test + public void test_multipliedBy_zeroBase() { + assertPeriod(Period.ZERO.multipliedBy(2), 0, 0, 0); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_multipliedBy_overflowTooBig() { + Period test = Period.ofYears(Integer.MAX_VALUE / 2 + 1); + test.multipliedBy(2); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_multipliedBy_overflowTooSmall() { + Period test = Period.ofYears(Integer.MIN_VALUE / 2 - 1); + test.multipliedBy(2); + } + + //----------------------------------------------------------------------- + // negated() + //----------------------------------------------------------------------- + @Test + public void test_negated() { + assertPeriod(Period.of(0, 0, 0).negated(), 0 ,0, 0); + assertPeriod(Period.of(1, 2, 3).negated(), -1, -2, -3); + assertPeriod(Period.of(-1, -2, -3).negated(), 1, 2, 3); + assertPeriod(Period.of(-1, 2, -3).negated(), 1, -2, 3); + assertPeriod(Period.of(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE).negated(), + -Integer.MAX_VALUE, -Integer.MAX_VALUE, -Integer.MAX_VALUE); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_negated_overflow_years() { + Period.ofYears(Integer.MIN_VALUE).negated(); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_negated_overflow_months() { + Period.ofMonths(Integer.MIN_VALUE).negated(); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_negated_overflow_days() { + Period.ofDays(Integer.MIN_VALUE).negated(); + } + + //----------------------------------------------------------------------- + // normalized() + //----------------------------------------------------------------------- + @DataProvider(name="normalized") + Object[][] data_normalized() { + return new Object[][] { + {0, 0, 0, 0}, + {1, 0, 1, 0}, + {-1, 0, -1, 0}, + + {1, 1, 1, 1}, + {1, 2, 1, 2}, + {1, 11, 1, 11}, + {1, 12, 2, 0}, + {1, 13, 2, 1}, + {1, 23, 2, 11}, + {1, 24, 3, 0}, + {1, 25, 3, 1}, + + {1, -1, 0, 11}, + {1, -2, 0, 10}, + {1, -11, 0, 1}, + {1, -12, 0, 0}, + {1, -13, 0, -1}, + {1, -23, 0, -11}, + {1, -24, -1, 0}, + {1, -25, -1, -1}, + {1, -35, -1, -11}, + {1, -36, -2, 0}, + {1, -37, -2, -1}, + + {-1, 1, 0, -11}, + {-1, 11, 0, -1}, + {-1, 12, 0, 0}, + {-1, 13, 0, 1}, + {-1, 23, 0, 11}, + {-1, 24, 1, 0}, + {-1, 25, 1, 1}, + + {-1, -1, -1, -1}, + {-1, -11, -1, -11}, + {-1, -12, -2, 0}, + {-1, -13, -2, -1}, + }; + } + + @Test(dataProvider="normalized") + public void test_normalized(int inputYears, int inputMonths, int expectedYears, int expectedMonths) { + assertPeriod(Period.of(inputYears, inputMonths, 0).normalized(), expectedYears, expectedMonths, 0); + } + + @Test(dataProvider="normalized") + public void test_normalized_daysUnaffected(int inputYears, int inputMonths, int expectedYears, int expectedMonths) { + assertPeriod(Period.of(inputYears, inputMonths, 5).normalized(), expectedYears, expectedMonths, 5); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_normalized_min() { + Period base = Period.of(Integer.MIN_VALUE, -12, 0); + base.normalized(); + } + + @Test(expectedExceptions=ArithmeticException.class) + public void test_normalized_max() { + Period base = Period.of(Integer.MAX_VALUE, 12, 0); + base.normalized(); + } + + //----------------------------------------------------------------------- + // addTo() + //----------------------------------------------------------------------- + @DataProvider(name="addTo") + Object[][] data_addTo() { + return new Object[][] { + {pymd(0, 0, 0), date(2012, 6, 30), date(2012, 6, 30)}, + + {pymd(1, 0, 0), date(2012, 6, 10), date(2013, 6, 10)}, + {pymd(0, 1, 0), date(2012, 6, 10), date(2012, 7, 10)}, + {pymd(0, 0, 1), date(2012, 6, 10), date(2012, 6, 11)}, + + {pymd(-1, 0, 0), date(2012, 6, 10), date(2011, 6, 10)}, + {pymd(0, -1, 0), date(2012, 6, 10), date(2012, 5, 10)}, + {pymd(0, 0, -1), date(2012, 6, 10), date(2012, 6, 9)}, + + {pymd(1, 2, 3), date(2012, 6, 27), date(2013, 8, 30)}, + {pymd(1, 2, 3), date(2012, 6, 28), date(2013, 8, 31)}, + {pymd(1, 2, 3), date(2012, 6, 29), date(2013, 9, 1)}, + {pymd(1, 2, 3), date(2012, 6, 30), date(2013, 9, 2)}, + {pymd(1, 2, 3), date(2012, 7, 1), date(2013, 9, 4)}, + + {pymd(1, 0, 0), date(2011, 2, 28), date(2012, 2, 28)}, + {pymd(4, 0, 0), date(2011, 2, 28), date(2015, 2, 28)}, + {pymd(1, 0, 0), date(2012, 2, 29), date(2013, 2, 28)}, + {pymd(4, 0, 0), date(2012, 2, 29), date(2016, 2, 29)}, + + {pymd(1, 1, 0), date(2011, 1, 29), date(2012, 2, 29)}, + {pymd(1, 2, 0), date(2012, 2, 29), date(2013, 4, 29)}, + }; + } + + @Test(dataProvider="addTo") + public void test_addTo(Period period, LocalDate baseDate, LocalDate expected) { + assertEquals(period.addTo(baseDate), expected); + } + + @Test(dataProvider="addTo") + public void test_addTo_usingLocalDatePlus(Period period, LocalDate baseDate, LocalDate expected) { + assertEquals(baseDate.plus(period), expected); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_addTo_nullZero() { + Period.ZERO.addTo(null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_addTo_nullNonZero() { + Period.ofDays(2).addTo(null); + } + + //----------------------------------------------------------------------- + // subtractFrom() + //----------------------------------------------------------------------- + @DataProvider(name="subtractFrom") + Object[][] data_subtractFrom() { + return new Object[][] { + {pymd(0, 0, 0), date(2012, 6, 30), date(2012, 6, 30)}, + + {pymd(1, 0, 0), date(2012, 6, 10), date(2011, 6, 10)}, + {pymd(0, 1, 0), date(2012, 6, 10), date(2012, 5, 10)}, + {pymd(0, 0, 1), date(2012, 6, 10), date(2012, 6, 9)}, + + {pymd(-1, 0, 0), date(2012, 6, 10), date(2013, 6, 10)}, + {pymd(0, -1, 0), date(2012, 6, 10), date(2012, 7, 10)}, + {pymd(0, 0, -1), date(2012, 6, 10), date(2012, 6, 11)}, + + {pymd(1, 2, 3), date(2012, 8, 30), date(2011, 6, 27)}, + {pymd(1, 2, 3), date(2012, 8, 31), date(2011, 6, 27)}, + {pymd(1, 2, 3), date(2012, 9, 1), date(2011, 6, 28)}, + {pymd(1, 2, 3), date(2012, 9, 2), date(2011, 6, 29)}, + {pymd(1, 2, 3), date(2012, 9, 3), date(2011, 6, 30)}, + {pymd(1, 2, 3), date(2012, 9, 4), date(2011, 7, 1)}, + + {pymd(1, 0, 0), date(2011, 2, 28), date(2010, 2, 28)}, + {pymd(4, 0, 0), date(2011, 2, 28), date(2007, 2, 28)}, + {pymd(1, 0, 0), date(2012, 2, 29), date(2011, 2, 28)}, + {pymd(4, 0, 0), date(2012, 2, 29), date(2008, 2, 29)}, + + {pymd(1, 1, 0), date(2013, 3, 29), date(2012, 2, 29)}, + {pymd(1, 2, 0), date(2012, 2, 29), date(2010, 12, 29)}, + }; + } + + @Test(dataProvider="subtractFrom") + public void test_subtractFrom(Period period, LocalDate baseDate, LocalDate expected) { + assertEquals(period.subtractFrom(baseDate), expected); + } + + @Test(dataProvider="subtractFrom") + public void test_subtractFrom_usingLocalDateMinus(Period period, LocalDate baseDate, LocalDate expected) { + assertEquals(baseDate.minus(period), expected); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_subtractFrom_nullZero() { + Period.ZERO.subtractFrom(null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_subtractFrom_nullNonZero() { + Period.ofDays(2).subtractFrom(null); + } + + //----------------------------------------------------------------------- + // get units + //----------------------------------------------------------------------- + @Test + public void test_Period_getUnits() { + Period period = Period.of(2012, 1, 1); + List units = period.getUnits(); + assertEquals(units.size(), 3, "Period.getUnits should return 3 units"); + assertEquals(units.get(0), ChronoUnit.YEARS, "Period.getUnits contains ChronoUnit.YEARS"); + assertEquals(units.get(1), ChronoUnit.MONTHS, "Period.getUnits contains ChronoUnit.MONTHS"); + assertEquals(units.get(2), ChronoUnit.DAYS, "Period.getUnits contains ChronoUnit.DAYS"); + } + + + @DataProvider(name="GoodTemporalUnit") + Object[][] data_goodTemporalUnit() { + return new Object[][] { + {2, ChronoUnit.DAYS}, + {2, ChronoUnit.MONTHS}, + {2, ChronoUnit.YEARS}, + }; + } + + @Test(dataProvider="GoodTemporalUnit") + public void test_good_getUnit(long amount, TemporalUnit unit) { + Period period = Period.of(2, 2, 2); + long actual = period.get(unit); + assertEquals(actual, amount, "Value of unit: " + unit); + } + + @DataProvider(name="BadTemporalUnit") + Object[][] data_badTemporalUnit() { + return new Object[][] { + {ChronoUnit.MICROS}, + {ChronoUnit.MILLIS}, + {ChronoUnit.HALF_DAYS}, + {ChronoUnit.DECADES}, + {ChronoUnit.CENTURIES}, + {ChronoUnit.MILLENNIA}, + }; + } + + @Test(dataProvider="BadTemporalUnit", expectedExceptions=DateTimeException.class) + public void test_bad_getUnit(TemporalUnit unit) { + Period period = Period.of(2, 2, 2); + period.get(unit); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + public void test_equals() { + assertEquals(Period.of(1, 0, 0).equals(Period.ofYears(1)), true); + assertEquals(Period.of(0, 1, 0).equals(Period.ofMonths(1)), true); + assertEquals(Period.of(0, 0, 1).equals(Period.ofDays(1)), true); + assertEquals(Period.of(1, 2, 3).equals(Period.of(1, 2, 3)), true); + + assertEquals(Period.ofYears(1).equals(Period.ofYears(1)), true); + assertEquals(Period.ofYears(1).equals(Period.ofYears(2)), false); + + assertEquals(Period.ofMonths(1).equals(Period.ofMonths(1)), true); + assertEquals(Period.ofMonths(1).equals(Period.ofMonths(2)), false); + + assertEquals(Period.ofDays(1).equals(Period.ofDays(1)), true); + assertEquals(Period.ofDays(1).equals(Period.ofDays(2)), false); + + assertEquals(Period.of(1, 2, 3).equals(Period.of(0, 2, 3)), false); + assertEquals(Period.of(1, 2, 3).equals(Period.of(1, 0, 3)), false); + assertEquals(Period.of(1, 2, 3).equals(Period.of(1, 2, 0)), false); + } + + public void test_equals_self() { + Period test = Period.of(1, 2, 3); + assertEquals(test.equals(test), true); + } + + public void test_equals_null() { + Period test = Period.of(1, 2, 3); + assertEquals(test.equals(null), false); + } + + public void test_equals_otherClass() { + Period test = Period.of(1, 2, 3); + assertEquals(test.equals(""), false); + } + + //----------------------------------------------------------------------- + public void test_hashCode() { + Period test5 = Period.ofDays(5); + Period test6 = Period.ofDays(6); + Period test5M = Period.ofMonths(5); + Period test5Y = Period.ofYears(5); + assertEquals(test5.hashCode() == test5.hashCode(), true); + assertEquals(test5.hashCode() == test6.hashCode(), false); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="toStringAndParse") + Object[][] data_toString() { + return new Object[][] { + {Period.ZERO, "P0D"}, + {Period.ofDays(0), "P0D"}, + {Period.ofYears(1), "P1Y"}, + {Period.ofMonths(1), "P1M"}, + {Period.ofDays(1), "P1D"}, + {Period.of(1, 2, 0), "P1Y2M"}, + {Period.of(0, 2, 3), "P2M3D"}, + {Period.of(1, 2, 3), "P1Y2M3D"}, + }; + } + + @Test(dataProvider="toStringAndParse") + public void test_toString(Period input, String expected) { + assertEquals(input.toString(), expected); + } + + @Test(dataProvider="toStringAndParse") + public void test_parse(Period test, String expected) { + assertEquals(Period.parse(expected), test); + } + + //----------------------------------------------------------------------- + private void assertPeriod(Period test, int y, int m, int d) { + assertEquals(test.getYears(), y, "years"); + assertEquals(test.getMonths(), m, "months"); + assertEquals(test.getDays(), d, "days"); + assertEquals(test.toTotalMonths(), y * 12L + m, "totalMonths"); + } + + private static Period pymd(int y, int m, int d) { + return Period.of(y, m, d); + } + + private static LocalDate date(int y, int m, int d) { + return LocalDate.of(y, m, d); + } + +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKYear.java b/jdk/test/java/time/tck/java/time/TCKYear.java similarity index 89% rename from jdk/test/java/time/tck/java/time/temporal/TCKYear.java rename to jdk/test/java/time/tck/java/time/TCKYear.java index 5464c6b4241..3f0e653f8cf 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TCKYear.java +++ b/jdk/test/java/time/tck/java/time/TCKYear.java @@ -57,7 +57,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.temporal; +package tck.java.time; import static java.time.temporal.ChronoField.ERA; import static java.time.temporal.ChronoField.YEAR; @@ -67,36 +67,36 @@ import static org.testng.Assert.fail; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import java.time.Clock; import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDate; import java.time.LocalTime; import java.time.Month; +import java.time.MonthDay; +import java.time.OffsetDateTime; +import java.time.Year; +import java.time.YearMonth; import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; import java.time.temporal.JulianFields; -import java.time.temporal.MonthDay; -import java.time.temporal.OffsetDateTime; +import java.time.temporal.Queries; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; -import java.time.temporal.Year; -import java.time.temporal.YearMonth; +import java.time.temporal.TemporalQuery; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import tck.java.time.AbstractDateTimeTest; /** * Test Year. @@ -149,7 +149,7 @@ public class TCKYear extends AbstractDateTimeTest { public void test_serialization_format() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(4); + dos.writeByte(11); // java.time.temporal.Ser.YEAR_TYPE dos.writeInt(2012); } byte[] bytes = baos.toByteArray(); @@ -317,14 +317,14 @@ public class TCKYear extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void factory_parse_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y"); Year test = Year.parse("2010", f); assertEquals(test, Year.of(2010)); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void factory_parse_formatter_nullText() { - DateTimeFormatter f = DateTimeFormatters.pattern("y"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y"); Year.parse((String) null, f); } @@ -350,6 +350,37 @@ public class TCKYear extends AbstractDateTimeTest { assertEquals(TEST_2008.getLong(ChronoField.ERA), 1); } + //----------------------------------------------------------------------- + // query(TemporalQuery) + //----------------------------------------------------------------------- + @DataProvider(name="query") + Object[][] data_query() { + return new Object[][] { + {TEST_2008, Queries.chronology(), IsoChronology.INSTANCE}, + {TEST_2008, Queries.zoneId(), null}, + {TEST_2008, Queries.precision(), ChronoUnit.YEARS}, + {TEST_2008, Queries.zone(), null}, + {TEST_2008, Queries.offset(), null}, + {TEST_2008, Queries.localDate(), null}, + {TEST_2008, Queries.localTime(), null}, + }; + } + + @Test(dataProvider="query") + public void test_query(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(temporal.query(query), expected); + } + + @Test(dataProvider="query") + public void test_queryFrom(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(query.queryFrom(temporal), expected); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_query_null() { + TEST_2008.query(null); + } + //----------------------------------------------------------------------- // isLeap() //----------------------------------------------------------------------- @@ -555,45 +586,35 @@ public class TCKYear extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // isValidMonthDay(Month) + // isValidMonthDay(MonthDay) //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_isValidMonthDay_june() { - Year test = Year.of(2007); - MonthDay monthDay = MonthDay.of(6, 30); - assertEquals(test.isValidMonthDay(monthDay), true); + @DataProvider(name="isValidMonthDay") + Object[][] data_isValidMonthDay() { + return new Object[][] { + {Year.of(2007), MonthDay.of(6, 30), true}, + {Year.of(2008), MonthDay.of(2, 28), true}, + {Year.of(2008), MonthDay.of(2, 29), true}, + {Year.of(2009), MonthDay.of(2, 28), true}, + {Year.of(2009), MonthDay.of(2, 29), false}, + {Year.of(2009), null, false}, + }; } - @Test(groups={"tck"}) - public void test_isValidMonthDay_febNonLeap() { - Year test = Year.of(2007); - MonthDay monthDay = MonthDay.of(2, 29); - assertEquals(test.isValidMonthDay(monthDay), false); - } - - @Test(groups={"tck"}) - public void test_isValidMonthDay_febLeap() { - Year test = Year.of(2008); - MonthDay monthDay = MonthDay.of(2, 29); - assertEquals(test.isValidMonthDay(monthDay), true); - } - - @Test(groups={"tck"}) - public void test_isValidMonthDay_null() { - Year test = Year.of(2008); - assertEquals(test.isValidMonthDay(null), false); + @Test(dataProvider="isValidMonthDay") + public void test_isValidMonthDay(Year year, MonthDay monthDay, boolean expected) { + assertEquals(year.isValidMonthDay(monthDay), expected); } //----------------------------------------------------------------------- // atMonth(Month) //----------------------------------------------------------------------- - @Test(groups={"tck"}) + @Test public void test_atMonth() { Year test = Year.of(2008); assertEquals(test.atMonth(Month.JUNE), YearMonth.of(2008, 6)); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_atMonth_nullMonth() { Year test = Year.of(2008); test.atMonth((Month) null); @@ -602,13 +623,13 @@ public class TCKYear extends AbstractDateTimeTest { //----------------------------------------------------------------------- // atMonth(int) //----------------------------------------------------------------------- - @Test(groups={"tck"}) + @Test public void test_atMonth_int() { Year test = Year.of(2008); assertEquals(test.atMonth(6), YearMonth.of(2008, 6)); } - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + @Test(expectedExceptions=DateTimeException.class) public void test_atMonth_int_invalidMonth() { Year test = Year.of(2008); test.atMonth(13); @@ -617,24 +638,26 @@ public class TCKYear extends AbstractDateTimeTest { //----------------------------------------------------------------------- // atMonthDay(Month) //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_atMonthDay() { - Year test = Year.of(2008); - assertEquals(test.atMonthDay(MonthDay.of(6, 30)), LocalDate.of(2008, 6, 30)); + @DataProvider(name="atMonthDay") + Object[][] data_atMonthDay() { + return new Object[][] { + {Year.of(2008), MonthDay.of(6, 30), LocalDate.of(2008, 6, 30)}, + {Year.of(2008), MonthDay.of(2, 29), LocalDate.of(2008, 2, 29)}, + {Year.of(2009), MonthDay.of(2, 29), LocalDate.of(2009, 2, 28)}, + }; } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(dataProvider="atMonthDay") + public void test_atMonthDay(Year year, MonthDay monthDay, LocalDate expected) { + assertEquals(year.atMonthDay(monthDay), expected); + } + + @Test(expectedExceptions=NullPointerException.class) public void test_atMonthDay_nullMonthDay() { Year test = Year.of(2008); test.atMonthDay((MonthDay) null); } - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_atMonthDay_invalidMonthDay() { - Year test = Year.of(2008); - test.atMonthDay(MonthDay.of(6, 31)); - } - //----------------------------------------------------------------------- // atDay(int) //----------------------------------------------------------------------- @@ -768,7 +791,7 @@ public class TCKYear extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_toString_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y"); String t = Year.of(2010).toString(f); assertEquals(t, "2010"); } diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKYearMonth.java b/jdk/test/java/time/tck/java/time/TCKYearMonth.java similarity index 89% rename from jdk/test/java/time/tck/java/time/temporal/TCKYearMonth.java rename to jdk/test/java/time/tck/java/time/TCKYearMonth.java index 25d57f1a22b..3369daccca2 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TCKYearMonth.java +++ b/jdk/test/java/time/tck/java/time/TCKYearMonth.java @@ -57,7 +57,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.temporal; +package tck.java.time; import static java.time.temporal.ChronoField.EPOCH_MONTH; import static java.time.temporal.ChronoField.ERA; @@ -71,12 +71,6 @@ import static org.testng.Assert.fail; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import java.time.Clock; import java.time.DateTimeException; import java.time.Instant; @@ -84,22 +78,29 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; +import java.time.Year; +import java.time.YearMonth; import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; import java.time.temporal.JulianFields; +import java.time.temporal.Queries; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; -import java.time.temporal.Year; -import java.time.temporal.YearMonth; +import java.time.temporal.TemporalQuery; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import tck.java.time.AbstractDateTimeTest; /** * Test YearMonth. @@ -153,7 +154,7 @@ public class TCKYearMonth extends AbstractDateTimeTest { public void test_serialization_format() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(5); + dos.writeByte(12); // java.time.temporal.Ser.YEAR_MONTH_TYPE dos.writeInt(2012); dos.writeByte(9); } @@ -378,14 +379,14 @@ public class TCKYearMonth extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void factory_parse_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M"); YearMonth test = YearMonth.parse("2010 12", f); assertEquals(test, YearMonth.of(2010, 12)); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void factory_parse_formatter_nullText() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M"); YearMonth.parse((String) null, f); } @@ -414,6 +415,37 @@ public class TCKYearMonth extends AbstractDateTimeTest { assertEquals(TEST_2008_06.getLong(ChronoField.EPOCH_MONTH), (2008 - 1970) * 12 + 6 - 1); } + //----------------------------------------------------------------------- + // query(TemporalQuery) + //----------------------------------------------------------------------- + @DataProvider(name="query") + Object[][] data_query() { + return new Object[][] { + {TEST_2008_06, Queries.chronology(), IsoChronology.INSTANCE}, + {TEST_2008_06, Queries.zoneId(), null}, + {TEST_2008_06, Queries.precision(), ChronoUnit.MONTHS}, + {TEST_2008_06, Queries.zone(), null}, + {TEST_2008_06, Queries.offset(), null}, + {TEST_2008_06, Queries.localDate(), null}, + {TEST_2008_06, Queries.localTime(), null}, + }; + } + + @Test(dataProvider="query") + public void test_query(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(temporal.query(query), expected); + } + + @Test(dataProvider="query") + public void test_queryFrom(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(query.queryFrom(temporal), expected); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_query_null() { + TEST_2008_06.query(null); + } + //----------------------------------------------------------------------- // get*() //----------------------------------------------------------------------- @@ -427,6 +459,14 @@ public class TCKYearMonth extends AbstractDateTimeTest { }; } + @Test(dataProvider="sampleDates") + public void test_get(int y, int m) { + YearMonth a = YearMonth.of(y, m); + assertEquals(a.getYear(), y); + assertEquals(a.getMonth(), Month.of(m)); + assertEquals(a.getMonthValue(), m); + } + //----------------------------------------------------------------------- // with(Year) //----------------------------------------------------------------------- @@ -870,16 +910,66 @@ public class TCKYearMonth extends AbstractDateTimeTest { //----------------------------------------------------------------------- // atDay(int) //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_atDay_int() { - YearMonth test = YearMonth.of(2008, 6); - assertEquals(test.atDay(30), LocalDate.of(2008, 6, 30)); + @DataProvider(name="atDay") + Object[][] data_atDay() { + return new Object[][] { + {YearMonth.of(2008, 6), 8, LocalDate.of(2008, 6, 8)}, + + {YearMonth.of(2008, 1), 31, LocalDate.of(2008, 1, 31)}, + {YearMonth.of(2008, 2), 29, LocalDate.of(2008, 2, 29)}, + {YearMonth.of(2008, 3), 31, LocalDate.of(2008, 3, 31)}, + {YearMonth.of(2008, 4), 30, LocalDate.of(2008, 4, 30)}, + + {YearMonth.of(2009, 1), 32, null}, + {YearMonth.of(2009, 1), 0, null}, + {YearMonth.of(2009, 2), 29, null}, + {YearMonth.of(2009, 2), 30, null}, + {YearMonth.of(2009, 2), 31, null}, + {YearMonth.of(2009, 4), 31, null}, + }; } - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_atDay_int_invalidDay() { - YearMonth test = YearMonth.of(2008, 6); - test.atDay(31); + @Test(dataProvider="atDay") + public void test_atDay(YearMonth test, int day, LocalDate expected) { + if (expected != null) { + assertEquals(test.atDay(day), expected); + } else { + try { + test.atDay(day); + fail(); + } catch (DateTimeException ex) { + // expected + } + } + } + + //----------------------------------------------------------------------- + // atEndOfMonth() + //----------------------------------------------------------------------- + @DataProvider(name="atEndOfMonth") + Object[][] data_atEndOfMonth() { + return new Object[][] { + {YearMonth.of(2008, 1), LocalDate.of(2008, 1, 31)}, + {YearMonth.of(2008, 2), LocalDate.of(2008, 2, 29)}, + {YearMonth.of(2008, 3), LocalDate.of(2008, 3, 31)}, + {YearMonth.of(2008, 4), LocalDate.of(2008, 4, 30)}, + {YearMonth.of(2008, 5), LocalDate.of(2008, 5, 31)}, + {YearMonth.of(2008, 6), LocalDate.of(2008, 6, 30)}, + {YearMonth.of(2008, 12), LocalDate.of(2008, 12, 31)}, + + {YearMonth.of(2009, 1), LocalDate.of(2009, 1, 31)}, + {YearMonth.of(2009, 2), LocalDate.of(2009, 2, 28)}, + {YearMonth.of(2009, 3), LocalDate.of(2009, 3, 31)}, + {YearMonth.of(2009, 4), LocalDate.of(2009, 4, 30)}, + {YearMonth.of(2009, 5), LocalDate.of(2009, 5, 31)}, + {YearMonth.of(2009, 6), LocalDate.of(2009, 6, 30)}, + {YearMonth.of(2009, 12), LocalDate.of(2009, 12, 31)}, + }; + } + + @Test(dataProvider="atEndOfMonth") + public void test_atEndOfMonth(YearMonth test, LocalDate expected) { + assertEquals(test.atEndOfMonth(), expected); } //----------------------------------------------------------------------- @@ -1033,7 +1123,7 @@ public class TCKYearMonth extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_toString_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M"); String t = YearMonth.of(2010, 12).toString(f); assertEquals(t, "2010 12"); } diff --git a/jdk/test/java/time/tck/java/time/TCKZoneId.java b/jdk/test/java/time/tck/java/time/TCKZoneId.java index adc2bb6ee2f..bc6944a8854 100644 --- a/jdk/test/java/time/tck/java/time/TCKZoneId.java +++ b/jdk/test/java/time/tck/java/time/TCKZoneId.java @@ -59,11 +59,30 @@ */ package tck.java.time; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; + +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; import java.io.DataOutputStream; - +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamConstants; +import java.lang.reflect.Field; +import java.time.DateTimeException; +import java.time.LocalTime; import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.temporal.Queries; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQuery; +import java.time.zone.ZoneRulesException; +import java.util.HashMap; +import java.util.Map; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** @@ -76,6 +95,7 @@ public class TCKZoneId extends AbstractTCKTest { @Test public void test_serialization() throws Exception { assertSerializable(ZoneId.of("Europe/London")); + assertSerializable(ZoneId.of("America/Chicago")); } @Test @@ -89,4 +109,484 @@ public class TCKZoneId extends AbstractTCKTest { assertSerializedBySer(ZoneId.of("Europe/London"), bytes); } + @Test + public void test_deserialization_lenient_characters() throws Exception { + // an ID can be loaded without validation during deserialization + String id = "QWERTYUIOPASDFGHJKLZXCVBNM~/._+-"; + ZoneId deser = deserialize(id); + // getting the ID and string are OK + assertEquals(deser.getId(), id); + assertEquals(deser.toString(), id); + // getting the rules is not + try { + deser.getRules(); + fail(); + } catch (ZoneRulesException ex) { + // expected + } + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_deserialization_lenient_badCharacters() throws Exception { + // an ID can be loaded without validation during deserialization + // but there is a check to ensure the ID format is valid + deserialize("|!?"); + } + + @Test(dataProvider="offsetBasedValid", expectedExceptions=DateTimeException.class) + public void test_deserialization_lenient_offsetNotAllowed_noPrefix(String input, String resolvedId) throws Exception { + // an ID can be loaded without validation during deserialization + // but there is a check to ensure the ID format is valid + deserialize(input); + } + + @Test(dataProvider="offsetBasedValid", expectedExceptions=DateTimeException.class) + public void test_deserialization_lenient_offsetNotAllowed_prefixUTC(String input, String resolvedId) throws Exception { + // an ID can be loaded without validation during deserialization + // but there is a check to ensure the ID format is valid + deserialize("UTC" + input); + } + + @Test(dataProvider="offsetBasedValid", expectedExceptions=DateTimeException.class) + public void test_deserialization_lenient_offsetNotAllowed_prefixGMT(String input, String resolvedId) throws Exception { + // an ID can be loaded without validation during deserialization + // but there is a check to ensure the ID format is valid + deserialize("GMT" + input); + } + + @Test(dataProvider="offsetBasedValid", expectedExceptions=DateTimeException.class) + public void test_deserialization_lenient_offsetNotAllowed_prefixUT(String input, String resolvedId) throws Exception { + // an ID can be loaded without validation during deserialization + // but there is a check to ensure the ID format is valid + deserialize("UT" + input); + } + + private ZoneId deserialize(String id) throws Exception { + String serClass = ZoneId.class.getPackage().getName() + ".Ser"; + Class serCls = Class.forName(serClass); + Field field = serCls.getDeclaredField("serialVersionUID"); + field.setAccessible(true); + long serVer = (Long) field.get(null); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try (DataOutputStream dos = new DataOutputStream(baos)) { + dos.writeShort(ObjectStreamConstants.STREAM_MAGIC); + dos.writeShort(ObjectStreamConstants.STREAM_VERSION); + dos.writeByte(ObjectStreamConstants.TC_OBJECT); + dos.writeByte(ObjectStreamConstants.TC_CLASSDESC); + dos.writeUTF(serClass); + dos.writeLong(serVer); + dos.writeByte(ObjectStreamConstants.SC_EXTERNALIZABLE | ObjectStreamConstants.SC_BLOCK_DATA); + dos.writeShort(0); // number of fields + dos.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); // end of classdesc + dos.writeByte(ObjectStreamConstants.TC_NULL); // no superclasses + dos.writeByte(ObjectStreamConstants.TC_BLOCKDATA); + dos.writeByte(1 + 2 + id.length()); // length of data (1 byte + 2 bytes UTF length + 32 bytes UTF) + dos.writeByte(7); // ZoneId + dos.writeUTF(id); + dos.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA); // end of blockdata + } + ZoneId deser = null; + try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()))) { + deser = (ZoneId) ois.readObject(); + } + return deser; + } + + //----------------------------------------------------------------------- + // OLD_IDS_PRE_2005 + //----------------------------------------------------------------------- + public void test_constant_OLD_IDS_PRE_2005() { + Map ids = ZoneId.OLD_IDS_PRE_2005; + assertEquals(ids.get("EST"), "America/New_York"); + assertEquals(ids.get("MST"), "America/Denver"); + assertEquals(ids.get("HST"), "Pacific/Honolulu"); + assertEquals(ids.get("ACT"), "Australia/Darwin"); + assertEquals(ids.get("AET"), "Australia/Sydney"); + assertEquals(ids.get("AGT"), "America/Argentina/Buenos_Aires"); + assertEquals(ids.get("ART"), "Africa/Cairo"); + assertEquals(ids.get("AST"), "America/Anchorage"); + assertEquals(ids.get("BET"), "America/Sao_Paulo"); + assertEquals(ids.get("BST"), "Asia/Dhaka"); + assertEquals(ids.get("CAT"), "Africa/Harare"); + assertEquals(ids.get("CNT"), "America/St_Johns"); + assertEquals(ids.get("CST"), "America/Chicago"); + assertEquals(ids.get("CTT"), "Asia/Shanghai"); + assertEquals(ids.get("EAT"), "Africa/Addis_Ababa"); + assertEquals(ids.get("ECT"), "Europe/Paris"); + assertEquals(ids.get("IET"), "America/Indiana/Indianapolis"); + assertEquals(ids.get("IST"), "Asia/Kolkata"); + assertEquals(ids.get("JST"), "Asia/Tokyo"); + assertEquals(ids.get("MIT"), "Pacific/Apia"); + assertEquals(ids.get("NET"), "Asia/Yerevan"); + assertEquals(ids.get("NST"), "Pacific/Auckland"); + assertEquals(ids.get("PLT"), "Asia/Karachi"); + assertEquals(ids.get("PNT"), "America/Phoenix"); + assertEquals(ids.get("PRT"), "America/Puerto_Rico"); + assertEquals(ids.get("PST"), "America/Los_Angeles"); + assertEquals(ids.get("SST"), "Pacific/Guadalcanal"); + assertEquals(ids.get("VST"), "Asia/Ho_Chi_Minh"); + } + + @Test(expectedExceptions=UnsupportedOperationException.class) + public void test_constant_OLD_IDS_PRE_2005_immutable() { + Map ids = ZoneId.OLD_IDS_PRE_2005; + ids.clear(); + } + + //----------------------------------------------------------------------- + // OLD_IDS_POST_2005 + //----------------------------------------------------------------------- + public void test_constant_OLD_IDS_POST_2005() { + Map ids = ZoneId.OLD_IDS_POST_2005; + assertEquals(ids.get("EST"), "-05:00"); + assertEquals(ids.get("MST"), "-07:00"); + assertEquals(ids.get("HST"), "-10:00"); + assertEquals(ids.get("ACT"), "Australia/Darwin"); + assertEquals(ids.get("AET"), "Australia/Sydney"); + assertEquals(ids.get("AGT"), "America/Argentina/Buenos_Aires"); + assertEquals(ids.get("ART"), "Africa/Cairo"); + assertEquals(ids.get("AST"), "America/Anchorage"); + assertEquals(ids.get("BET"), "America/Sao_Paulo"); + assertEquals(ids.get("BST"), "Asia/Dhaka"); + assertEquals(ids.get("CAT"), "Africa/Harare"); + assertEquals(ids.get("CNT"), "America/St_Johns"); + assertEquals(ids.get("CST"), "America/Chicago"); + assertEquals(ids.get("CTT"), "Asia/Shanghai"); + assertEquals(ids.get("EAT"), "Africa/Addis_Ababa"); + assertEquals(ids.get("ECT"), "Europe/Paris"); + assertEquals(ids.get("IET"), "America/Indiana/Indianapolis"); + assertEquals(ids.get("IST"), "Asia/Kolkata"); + assertEquals(ids.get("JST"), "Asia/Tokyo"); + assertEquals(ids.get("MIT"), "Pacific/Apia"); + assertEquals(ids.get("NET"), "Asia/Yerevan"); + assertEquals(ids.get("NST"), "Pacific/Auckland"); + assertEquals(ids.get("PLT"), "Asia/Karachi"); + assertEquals(ids.get("PNT"), "America/Phoenix"); + assertEquals(ids.get("PRT"), "America/Puerto_Rico"); + assertEquals(ids.get("PST"), "America/Los_Angeles"); + assertEquals(ids.get("SST"), "Pacific/Guadalcanal"); + assertEquals(ids.get("VST"), "Asia/Ho_Chi_Minh"); + } + + @Test(expectedExceptions=UnsupportedOperationException.class) + public void test_constant_OLD_IDS_POST_2005_immutable() { + Map ids = ZoneId.OLD_IDS_POST_2005; + ids.clear(); + } + + //----------------------------------------------------------------------- + // mapped factory + //----------------------------------------------------------------------- + @Test + public void test_of_string_Map() { + Map map = new HashMap<>(); + map.put("LONDON", "Europe/London"); + map.put("PARIS", "Europe/Paris"); + ZoneId test = ZoneId.of("LONDON", map); + assertEquals(test.getId(), "Europe/London"); + } + + @Test + public void test_of_string_Map_lookThrough() { + Map map = new HashMap<>(); + map.put("LONDON", "Europe/London"); + map.put("PARIS", "Europe/Paris"); + ZoneId test = ZoneId.of("Europe/Madrid", map); + assertEquals(test.getId(), "Europe/Madrid"); + } + + @Test + public void test_of_string_Map_emptyMap() { + Map map = new HashMap<>(); + ZoneId test = ZoneId.of("Europe/Madrid", map); + assertEquals(test.getId(), "Europe/Madrid"); + } + + @Test(expectedExceptions=DateTimeException.class) + public void test_of_string_Map_badFormat() { + Map map = new HashMap<>(); + ZoneId.of("Not known", map); + } + + @Test(expectedExceptions=ZoneRulesException.class) + public void test_of_string_Map_unknown() { + Map map = new HashMap<>(); + ZoneId.of("Unknown", map); + } + + //----------------------------------------------------------------------- + // regular factory + //----------------------------------------------------------------------- + @DataProvider(name="offsetBasedZero") + Object[][] data_offsetBasedZero() { + return new Object[][] { + {""}, {"0"}, + {"+00"},{"+0000"},{"+00:00"},{"+000000"},{"+00:00:00"}, + {"-00"},{"-0000"},{"-00:00"},{"-000000"},{"-00:00:00"}, + }; + } + + @Test(dataProvider="offsetBasedZero") + public void factory_of_String_offsetBasedZero_noPrefix(String id) { + if (id.length() > 0 && id.equals("0") == false) { + ZoneId test = ZoneId.of(id); + assertEquals(test, ZoneOffset.UTC); + } + } + + @Test(dataProvider="offsetBasedZero") + public void factory_of_String_offsetBasedZero_prefixUTC(String id) { + ZoneId test = ZoneId.of("UTC" + id); + assertEquals(test, ZoneOffset.UTC); + } + + @Test(dataProvider="offsetBasedZero") + public void factory_of_String_offsetBasedZero_prefixGMT(String id) { + ZoneId test = ZoneId.of("GMT" + id); + assertEquals(test, ZoneOffset.UTC); + } + + @Test(dataProvider="offsetBasedZero") + public void factory_of_String_offsetBasedZero_prefixUT(String id) { + ZoneId test = ZoneId.of("UT" + id); + assertEquals(test, ZoneOffset.UTC); + } + + @Test + public void factory_of_String_offsetBasedZero_z() { + ZoneId test = ZoneId.of("Z"); + assertEquals(test, ZoneOffset.UTC); + } + + //----------------------------------------------------------------------- + @DataProvider(name="offsetBasedValid") + Object[][] data_offsetBasedValid() { + return new Object[][] { + {"+0", "Z"}, + {"+5", "+05:00"}, + {"+01", "+01:00"}, + {"+0100", "+01:00"},{"+01:00", "+01:00"}, + {"+010000", "+01:00"},{"+01:00:00", "+01:00"}, + {"+12", "+12:00"}, + {"+1234", "+12:34"},{"+12:34", "+12:34"}, + {"+123456", "+12:34:56"},{"+12:34:56", "+12:34:56"}, + {"-02", "-02:00"}, + {"-5", "-05:00"}, + {"-0200", "-02:00"},{"-02:00", "-02:00"}, + {"-020000", "-02:00"},{"-02:00:00", "-02:00"}, + }; + } + + @Test(dataProvider="offsetBasedValid") + public void factory_of_String_offsetBasedValid_noPrefix(String input, String id) { + ZoneId test = ZoneId.of(input); + assertEquals(test.getId(), id); + assertEquals(test, ZoneOffset.of(id)); + } + + @Test(dataProvider="offsetBasedValid") + public void factory_of_String_offsetBasedValid_prefixUTC(String input, String id) { + ZoneId test = ZoneId.of("UTC" + input); + assertEquals(test.getId(), id); + assertEquals(test, ZoneOffset.of(id)); + } + + @Test(dataProvider="offsetBasedValid") + public void factory_of_String_offsetBasedValid_prefixGMT(String input, String id) { + ZoneId test = ZoneId.of("GMT" + input); + assertEquals(test.getId(), id); + assertEquals(test, ZoneOffset.of(id)); + } + + @Test(dataProvider="offsetBasedValid") + public void factory_of_String_offsetBasedValid_prefixUT(String input, String id) { + ZoneId test = ZoneId.of("UT" + input); + assertEquals(test.getId(), id); + assertEquals(test, ZoneOffset.of(id)); + } + + //----------------------------------------------------------------------- + @DataProvider(name="offsetBasedInvalid") + Object[][] data_offsetBasedInvalid() { + return new Object[][] { + {"A"}, {"B"}, {"C"}, {"D"}, {"E"}, {"F"}, {"G"}, {"H"}, {"I"}, {"J"}, {"K"}, {"L"}, {"M"}, + {"N"}, {"O"}, {"P"}, {"Q"}, {"R"}, {"S"}, {"T"}, {"U"}, {"V"}, {"W"}, {"X"}, {"Y"}, {"Z"}, + {"+0:00"}, {"+00:0"}, {"+0:0"}, + {"+000"}, {"+00000"}, + {"+0:00:00"}, {"+00:0:00"}, {"+00:00:0"}, {"+0:0:0"}, {"+0:0:00"}, {"+00:0:0"}, {"+0:00:0"}, + {"+01_00"}, {"+01;00"}, {"+01@00"}, {"+01:AA"}, + {"+19"}, {"+19:00"}, {"+18:01"}, {"+18:00:01"}, {"+1801"}, {"+180001"}, + {"-0:00"}, {"-00:0"}, {"-0:0"}, + {"-000"}, {"-00000"}, + {"-0:00:00"}, {"-00:0:00"}, {"-00:00:0"}, {"-0:0:0"}, {"-0:0:00"}, {"-00:0:0"}, {"-0:00:0"}, + {"-19"}, {"-19:00"}, {"-18:01"}, {"-18:00:01"}, {"-1801"}, {"-180001"}, + {"-01_00"}, {"-01;00"}, {"-01@00"}, {"-01:AA"}, + {"@01:00"}, + }; + } + + @Test(dataProvider="offsetBasedInvalid", expectedExceptions=DateTimeException.class) + public void factory_of_String_offsetBasedInvalid_noPrefix(String id) { + if (id.equals("Z")) { + throw new DateTimeException("Fake exception: Z alone is valid, not invalid"); + } + ZoneId.of(id); + } + + @Test(dataProvider="offsetBasedInvalid", expectedExceptions=DateTimeException.class) + public void factory_of_String_offsetBasedInvalid_prefixUTC(String id) { + ZoneId.of("UTC" + id); + } + + @Test(dataProvider="offsetBasedInvalid", expectedExceptions=DateTimeException.class) + public void factory_of_String_offsetBasedInvalid_prefixGMT(String id) { + ZoneId.of("GMT" + id); + } + + @Test(dataProvider="offsetBasedInvalid", expectedExceptions=DateTimeException.class) + public void factory_of_String_offsetBasedInvalid_prefixUT(String id) { + if (id.equals("C")) { + throw new DateTimeException("Fake exception: UT + C = UTC, thus it is valid, not invalid"); + } + ZoneId.of("UT" + id); + } + + //----------------------------------------------------------------------- + @DataProvider(name="regionBasedInvalid") + Object[][] data_regionBasedInvalid() { + // \u00ef is a random unicode character + return new Object[][] { + {""}, {":"}, {"#"}, + {"\u00ef"}, {"`"}, {"!"}, {"\""}, {"\u00ef"}, {"$"}, {"^"}, {"&"}, {"*"}, {"("}, {")"}, {"="}, + {"\\"}, {"|"}, {","}, {"<"}, {">"}, {"?"}, {";"}, {"'"}, {"["}, {"]"}, {"{"}, {"}"}, + {"\u00ef:A"}, {"`:A"}, {"!:A"}, {"\":A"}, {"\u00ef:A"}, {"$:A"}, {"^:A"}, {"&:A"}, {"*:A"}, {"(:A"}, {"):A"}, {"=:A"}, {"+:A"}, + {"\\:A"}, {"|:A"}, {",:A"}, {"<:A"}, {">:A"}, {"?:A"}, {";:A"}, {"::A"}, {"':A"}, {"@:A"}, {"~:A"}, {"[:A"}, {"]:A"}, {"{:A"}, {"}:A"}, + {"A:B#\u00ef"}, {"A:B#`"}, {"A:B#!"}, {"A:B#\""}, {"A:B#\u00ef"}, {"A:B#$"}, {"A:B#^"}, {"A:B#&"}, {"A:B#*"}, + {"A:B#("}, {"A:B#)"}, {"A:B#="}, {"A:B#+"}, + {"A:B#\\"}, {"A:B#|"}, {"A:B#,"}, {"A:B#<"}, {"A:B#>"}, {"A:B#?"}, {"A:B#;"}, {"A:B#:"}, + {"A:B#'"}, {"A:B#@"}, {"A:B#~"}, {"A:B#["}, {"A:B#]"}, {"A:B#{"}, {"A:B#}"}, + }; + } + + @Test(dataProvider="regionBasedInvalid", expectedExceptions=DateTimeException.class) + public void factory_of_String_regionBasedInvalid(String id) { + ZoneId.of(id); + } + + //----------------------------------------------------------------------- + @Test + public void factory_of_String_region_EuropeLondon() { + ZoneId test = ZoneId.of("Europe/London"); + assertEquals(test.getId(), "Europe/London"); + assertEquals(test.getRules().isFixedOffset(), false); + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class) + public void factory_of_String_null() { + ZoneId.of(null); + } + + @Test(expectedExceptions=DateTimeException.class) + public void factory_of_String_badFormat() { + ZoneId.of("Unknown rule"); + } + + @Test(expectedExceptions=ZoneRulesException.class) + public void factory_of_String_unknown() { + ZoneId.of("Unknown"); + } + + //----------------------------------------------------------------------- + // from(TemporalAccessor) + //----------------------------------------------------------------------- + @Test + public void factory_from_TemporalAccessor_zoneId() { + TemporalAccessor mock = new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + return false; + } + @Override + public long getLong(TemporalField field) { + throw new DateTimeException("Mock"); + } + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.zoneId()) { + return (R) ZoneId.of("Europe/Paris"); + } + return TemporalAccessor.super.query(query); + } + }; + assertEquals(ZoneId.from(mock), ZoneId.of("Europe/Paris")); + } + + @Test + public void factory_from_TemporalAccessor_offset() { + ZoneOffset offset = ZoneOffset.ofHours(1); + assertEquals(ZoneId.from(offset), offset); + } + + @Test(expectedExceptions=DateTimeException.class) + public void factory_from_TemporalAccessor_invalid_noDerive() { + ZoneId.from(LocalTime.of(12, 30)); + } + + @Test(expectedExceptions=NullPointerException.class) + public void factory_from_TemporalAccessor_null() { + ZoneId.from(null); + } + + //----------------------------------------------------------------------- + // equals() / hashCode() + //----------------------------------------------------------------------- + @Test + public void test_equals() { + ZoneId test1 = ZoneId.of("Europe/London"); + ZoneId test2 = ZoneId.of("Europe/Paris"); + ZoneId test2b = ZoneId.of("Europe/Paris"); + assertEquals(test1.equals(test2), false); + assertEquals(test2.equals(test1), false); + + assertEquals(test1.equals(test1), true); + assertEquals(test2.equals(test2), true); + assertEquals(test2.equals(test2b), true); + + assertEquals(test1.hashCode() == test1.hashCode(), true); + assertEquals(test2.hashCode() == test2.hashCode(), true); + assertEquals(test2.hashCode() == test2b.hashCode(), true); + } + + @Test + public void test_equals_null() { + assertEquals(ZoneId.of("Europe/London").equals(null), false); + } + + @Test + public void test_equals_notEqualWrongType() { + assertEquals(ZoneId.of("Europe/London").equals("Europe/London"), false); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="toString") + Object[][] data_toString() { + return new Object[][] { + {"Europe/London", "Europe/London"}, + {"Europe/Paris", "Europe/Paris"}, + {"Europe/Berlin", "Europe/Berlin"}, + {"UTC", "Z"}, + {"UTC+01:00", "+01:00"}, + }; + } + + @Test(dataProvider="toString") + public void test_toString(String id, String expected) { + ZoneId test = ZoneId.of(id); + assertEquals(test.toString(), expected); + } + } diff --git a/jdk/test/java/time/tck/java/time/TCKZoneOffset.java b/jdk/test/java/time/tck/java/time/TCKZoneOffset.java index 4cfd40d9115..c8fb56bf63b 100644 --- a/jdk/test/java/time/tck/java/time/TCKZoneOffset.java +++ b/jdk/test/java/time/tck/java/time/TCKZoneOffset.java @@ -67,10 +67,6 @@ import static org.testng.Assert.fail; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import java.time.DateTimeException; import java.time.Duration; import java.time.Instant; @@ -81,11 +77,15 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.temporal.ChronoField; import java.time.temporal.JulianFields; -import java.time.temporal.OffsetDate; import java.time.temporal.Queries; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQuery; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** @@ -480,7 +480,6 @@ public class TCKZoneOffset extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_factory_CalendricalObject() { - assertEquals(ZoneOffset.from(OffsetDate.of(LocalDate.of(2012, 5, 2), ZoneOffset.ofHours(6))), ZoneOffset.ofHours(6)); assertEquals(ZoneOffset.from(ZonedDateTime.of(LocalDateTime.of(LocalDate.of(2007, 7, 15), LocalTime.of(17, 30)), ZoneOffset.ofHours(2))), ZoneOffset.ofHours(2)); } @@ -560,44 +559,32 @@ public class TCKZoneOffset extends AbstractDateTimeTest { //----------------------------------------------------------------------- // query(TemporalQuery) //----------------------------------------------------------------------- - @Test - public void test_query_chrono() { - ZoneOffset test = ZoneOffset.ofHoursMinutes(1, 30); - assertEquals(test.query(Queries.chrono()), null); - assertEquals(Queries.chrono().queryFrom(test), null); + @DataProvider(name="query") + Object[][] data_query() { + return new Object[][] { + {ZoneOffset.UTC, Queries.chronology(), null}, + {ZoneOffset.UTC, Queries.zoneId(), null}, + {ZoneOffset.UTC, Queries.precision(), null}, + {ZoneOffset.UTC, Queries.zone(), ZoneOffset.UTC}, + {ZoneOffset.UTC, Queries.offset(), ZoneOffset.UTC}, + {ZoneOffset.UTC, Queries.localDate(), null}, + {ZoneOffset.UTC, Queries.localTime(), null}, + }; } - @Test - public void test_query_zoneId() { - ZoneOffset test = ZoneOffset.ofHoursMinutes(1, 30); - assertEquals(test.query(Queries.zoneId()), null); - assertEquals(Queries.zoneId().queryFrom(test), null); + @Test(dataProvider="query") + public void test_query(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(temporal.query(query), expected); } - @Test - public void test_query_precision() { - ZoneOffset test = ZoneOffset.ofHoursMinutes(1, 30); - assertEquals(test.query(Queries.precision()), null); - assertEquals(Queries.precision().queryFrom(test), null); - } - - @Test - public void test_query_offset() { - ZoneOffset test = ZoneOffset.ofHoursMinutes(1, 30); - assertEquals(test.query(Queries.offset()), test); - assertEquals(Queries.offset().queryFrom(test), test); - } - - @Test - public void test_query_zone() { - ZoneOffset test = ZoneOffset.ofHoursMinutes(1, 30); - assertEquals(test.query(Queries.zone()), test); - assertEquals(Queries.zone().queryFrom(test), test); + @Test(dataProvider="query") + public void test_queryFrom(TemporalAccessor temporal, TemporalQuery query, T expected) { + assertEquals(query.queryFrom(temporal), expected); } @Test(expectedExceptions=NullPointerException.class) public void test_query_null() { - ZoneOffset.ofHoursMinutes(1, 30).query(null); + ZoneOffset.UTC.query(null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java index df18b4f246f..9841fc8e849 100644 --- a/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java +++ b/jdk/test/java/time/tck/java/time/TCKZonedDateTime.java @@ -60,7 +60,6 @@ package tck.java.time; import java.time.*; -import test.java.time.MockSimplePeriod; import static java.time.Month.JANUARY; import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; @@ -111,21 +110,21 @@ import java.util.List; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.time.temporal.Queries; -import java.time.temporal.TemporalSubtractor; -import java.time.temporal.TemporalAdder; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalAdjuster; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalQuery; import java.time.temporal.TemporalField; -import java.time.temporal.ISOChrono; +import java.time.chrono.IsoChronology; import java.time.temporal.JulianFields; import test.java.time.temporal.MockFieldNoValue; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; +import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; -import java.time.temporal.OffsetDateTime; -import java.time.temporal.Year; +import java.time.OffsetDateTime; +import java.time.Year; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; @@ -272,12 +271,12 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { public void now() { ZonedDateTime expected = ZonedDateTime.now(Clock.systemDefaultZone()); ZonedDateTime test = ZonedDateTime.now(); - long diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay()); + long diff = Math.abs(test.toLocalTime().toNanoOfDay() - expected.toLocalTime().toNanoOfDay()); if (diff >= 100000000) { // may be date change expected = ZonedDateTime.now(Clock.systemDefaultZone()); test = ZonedDateTime.now(); - diff = Math.abs(test.getTime().toNanoOfDay() - expected.getTime().toNanoOfDay()); + diff = Math.abs(test.toLocalTime().toNanoOfDay() - expected.toLocalTime().toNanoOfDay()); } assertTrue(diff < 100000000); // less than 0.1 secs } @@ -354,7 +353,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { assertEquals(test.getMonth(), Month.DECEMBER); assertEquals(test.getDayOfMonth(), 31); expected = expected.minusSeconds(1); - assertEquals(test.getTime(), expected); + assertEquals(test.toLocalTime(), expected); assertEquals(test.getOffset(), ZoneOffset.UTC); assertEquals(test.getZone(), ZoneOffset.UTC); } @@ -391,11 +390,45 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { assertEquals(test.getZone(), zone); } + //----------------------------------------------------------------------- + // of(LocalDate, LocalTime, ZoneId) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_LocalDateLocalTime() { + ZonedDateTime test = ZonedDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 10, 500), ZONE_PARIS); + check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_0200, ZONE_PARIS); + } + + @Test(groups={"tck"}) + public void factory_of_LocalDateLocalTime_inGap() { + ZonedDateTime test = ZonedDateTime.of(TEST_PARIS_GAP_2008_03_30_02_30.toLocalDate(), TEST_PARIS_GAP_2008_03_30_02_30.toLocalTime(), ZONE_PARIS); + check(test, 2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS); // one hour later in summer offset + } + + @Test(groups={"tck"}) + public void factory_of_LocalDateLocalTime_inOverlap() { + ZonedDateTime test = ZonedDateTime.of(TEST_PARIS_OVERLAP_2008_10_26_02_30.toLocalDate(), TEST_PARIS_OVERLAP_2008_10_26_02_30.toLocalTime(), ZONE_PARIS); + check(test, 2008, 10, 26, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS); // same time in summer offset + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_LocalDateLocalTime_nullDate() { + ZonedDateTime.of((LocalDate) null, LocalTime.of(11, 30, 10, 500), ZONE_PARIS); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_LocalDateLocalTime_nullTime() { + ZonedDateTime.of(LocalDate.of(2008, 6, 30), (LocalTime) null, ZONE_PARIS); + } + + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + public void factory_of_LocalDateLocalTime_nullZone() { + ZonedDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 10, 500), null); + } + //----------------------------------------------------------------------- // of(LocalDateTime, ZoneId) //----------------------------------------------------------------------- - // TODO: tests of overlap/gap - @Test(groups={"tck"}) public void factory_of_LocalDateTime() { LocalDateTime base = LocalDateTime.of(2008, 6, 30, 11, 30, 10, 500); @@ -403,6 +436,18 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_0200, ZONE_PARIS); } + @Test(groups={"tck"}) + public void factory_of_LocalDateTime_inGap() { + ZonedDateTime test = ZonedDateTime.of(TEST_PARIS_GAP_2008_03_30_02_30, ZONE_PARIS); + check(test, 2008, 3, 30, 3, 30, 0, 0, OFFSET_0200, ZONE_PARIS); // one hour later in summer offset + } + + @Test(groups={"tck"}) + public void factory_of_LocalDateTime_inOverlap() { + ZonedDateTime test = ZonedDateTime.of(TEST_PARIS_OVERLAP_2008_10_26_02_30, ZONE_PARIS); + check(test, 2008, 10, 26, 2, 30, 0, 0, OFFSET_0200, ZONE_PARIS); // same time in summer offset + } + @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void factory_of_LocalDateTime_nullDateTime() { ZonedDateTime.of((LocalDateTime) null, ZONE_PARIS); @@ -414,6 +459,15 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { ZonedDateTime.of(base, null); } + //----------------------------------------------------------------------- + // of(int..., ZoneId) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void factory_of_ints() { + ZonedDateTime test = ZonedDateTime.of(2008, 6, 30, 11, 30, 10, 500, ZONE_PARIS); + check(test, 2008, 6, 30, 11, 30, 10, 500, OFFSET_0200, ZONE_PARIS); + } + //----------------------------------------------------------------------- // ofInstant(Instant, ZoneId) //----------------------------------------------------------------------- @@ -662,11 +716,11 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { assertEquals(ZonedDateTime.from(new TemporalAccessor() { @Override public boolean isSupported(TemporalField field) { - return TEST_DATE_TIME_PARIS.getDateTime().isSupported(field); + return TEST_DATE_TIME_PARIS.toLocalDateTime().isSupported(field); } @Override public long getLong(TemporalField field) { - return TEST_DATE_TIME_PARIS.getDateTime().getLong(field); + return TEST_DATE_TIME_PARIS.toLocalDateTime().getLong(field); } @SuppressWarnings("unchecked") @Override @@ -716,7 +770,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- // parse() //----------------------------------------------------------------------- - @Test(dataProvider="sampleToString", groups={"tck"}) + @Test(dataProvider="sampleToString") public void test_parse(int y, int month, int d, int h, int m, int s, int n, String zoneId, String text) { ZonedDateTime t = ZonedDateTime.parse(text); assertEquals(t.getYear(), y); @@ -729,6 +783,37 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { assertEquals(t.getZone().getId(), zoneId); } + @DataProvider(name="parseAdditional") + Object[][] data_parseAdditional() { + return new Object[][] { + {"2012-06-30T12:30:40Z[GMT]", 2012, 6, 30, 12, 30, 40, 0, "Z"}, + {"2012-06-30T12:30:40Z[UT]", 2012, 6, 30, 12, 30, 40, 0, "Z"}, + {"2012-06-30T12:30:40Z[UTC]", 2012, 6, 30, 12, 30, 40, 0, "Z"}, + {"2012-06-30T12:30:40+01:00[+01:00]", 2012, 6, 30, 12, 30, 40, 0, "+01:00"}, + {"2012-06-30T12:30:40+01:00[GMT+01:00]", 2012, 6, 30, 12, 30, 40, 0, "+01:00"}, + {"2012-06-30T12:30:40+01:00[UT+01:00]", 2012, 6, 30, 12, 30, 40, 0, "+01:00"}, + {"2012-06-30T12:30:40+01:00[UTC+01:00]", 2012, 6, 30, 12, 30, 40, 0, "+01:00"}, + {"2012-06-30T12:30:40-01:00[-01:00]", 2012, 6, 30, 12, 30, 40, 0, "-01:00"}, + {"2012-06-30T12:30:40-01:00[GMT-01:00]", 2012, 6, 30, 12, 30, 40, 0, "-01:00"}, + {"2012-06-30T12:30:40-01:00[UT-01:00]", 2012, 6, 30, 12, 30, 40, 0, "-01:00"}, + {"2012-06-30T12:30:40-01:00[UTC-01:00]", 2012, 6, 30, 12, 30, 40, 0, "-01:00"}, + {"2012-06-30T12:30:40+01:00[Europe/London]", 2012, 6, 30, 12, 30, 40, 0, "Europe/London"}, + }; + } + + @Test(dataProvider="parseAdditional") + public void test_parseAdditional(String text, int y, int month, int d, int h, int m, int s, int n, String zoneId) { + ZonedDateTime t = ZonedDateTime.parse(text); + assertEquals(t.getYear(), y); + assertEquals(t.getMonth().getValue(), month); + assertEquals(t.getDayOfMonth(), d); + assertEquals(t.getHour(), h); + assertEquals(t.getMinute(), m); + assertEquals(t.getSecond(), s); + assertEquals(t.getNano(), n); + assertEquals(t.getZone().getId(), zoneId); + } + @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) public void factory_parse_illegalValue() { ZonedDateTime.parse("2008-06-32T11:15+01:00[Europe/Paris]"); @@ -749,14 +834,14 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void factory_parse_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s I"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d H m s VV"); ZonedDateTime test = ZonedDateTime.parse("2010 12 3 11 30 0 Europe/London", f); assertEquals(test, ZonedDateTime.of(LocalDateTime.of(2010, 12, 3, 11, 30), ZoneId.of("Europe/London"))); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void factory_parse_formatter_nullText() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d H m s"); ZonedDateTime.parse((String) null, f); } @@ -799,9 +884,9 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { assertEquals(a.getSecond(), localTime.getSecond()); assertEquals(a.getNano(), localTime.getNano()); - assertEquals(a.getDate(), localDate); - assertEquals(a.getTime(), localTime); - assertEquals(a.getDateTime(), localDateTime); + assertEquals(a.toLocalDate(), localDate); + assertEquals(a.toLocalTime(), localTime); + assertEquals(a.toLocalDateTime(), localDateTime); if (zone instanceof ZoneOffset) { assertEquals(a.toString(), localDateTime.toString() + offset.toString()); } else { @@ -856,8 +941,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test public void test_query_chrono() { - assertEquals(TEST_DATE_TIME.query(Queries.chrono()), ISOChrono.INSTANCE); - assertEquals(Queries.chrono().queryFrom(TEST_DATE_TIME), ISOChrono.INSTANCE); + assertEquals(TEST_DATE_TIME.query(Queries.chronology()), IsoChronology.INSTANCE); + assertEquals(Queries.chronology().queryFrom(TEST_DATE_TIME), IsoChronology.INSTANCE); } @Test @@ -904,7 +989,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { ZonedDateTime base = ZonedDateTime.ofStrict(TEST_PARIS_OVERLAP_2008_10_26_02_30, OFFSET_0100, ZONE_PARIS); ZonedDateTime test = base.withEarlierOffsetAtOverlap(); assertEquals(test.getOffset(), OFFSET_0200); // offset changed to earlier - assertEquals(test.getDateTime(), base.getDateTime()); // date-time not changed + assertEquals(test.toLocalDateTime(), base.toLocalDateTime()); // date-time not changed } @Test(groups={"tck"}) @@ -929,7 +1014,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { ZonedDateTime base = ZonedDateTime.ofStrict(TEST_PARIS_OVERLAP_2008_10_26_02_30, OFFSET_0200, ZONE_PARIS); ZonedDateTime test = base.withLaterOffsetAtOverlap(); assertEquals(test.getOffset(), OFFSET_0100); // offset changed to later - assertEquals(test.getDateTime(), base.getDateTime()); // date-time not changed + assertEquals(test.toLocalDateTime(), base.toLocalDateTime()); // date-time not changed } @Test(groups={"tck"}) @@ -947,10 +1032,10 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); ZonedDateTime test = base.withZoneSameLocal(ZONE_0200); - assertEquals(test.getDateTime(), base.getDateTime()); + assertEquals(test.toLocalDateTime(), base.toLocalDateTime()); } - @Test(groups={"implementation"}) + @Test(groups={"tck","implementation"}) public void test_withZoneSameLocal_noChange() { LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); ZonedDateTime base = ZonedDateTime.of(ldt, ZONE_0100); @@ -1357,25 +1442,25 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // plus(adjuster) + // plus(TemporalAmount) //----------------------------------------------------------------------- @Test(groups={"tck"}, dataProvider="plusDays") - public void test_plus_adjuster_Period_days(ZonedDateTime base, long amount, ZonedDateTime expected) { - assertEquals(base.plus(Period.of(amount, DAYS)), expected); + public void test_plus_TemporalAmount_Period_days(ZonedDateTime base, int amount, ZonedDateTime expected) { + assertEquals(base.plus(Period.ofDays(amount)), expected); } @Test(groups={"tck"}, dataProvider="plusTime") - public void test_plus_adjuster_Period_hours(ZonedDateTime base, long amount, ZonedDateTime expected) { - assertEquals(base.plus(Period.of(amount, HOURS)), expected); + public void test_plus_TemporalAmount_Period_hours(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.plus(MockSimplePeriod.of(amount, HOURS)), expected); } @Test(groups={"tck"}, dataProvider="plusTime") - public void test_plus_adjuster_Duration_hours(ZonedDateTime base, long amount, ZonedDateTime expected) { + public void test_plus_TemporalAmount_Duration_hours(ZonedDateTime base, long amount, ZonedDateTime expected) { assertEquals(base.plus(Duration.ofHours(amount)), expected); } @Test(groups={"tck"}) - public void test_plus_adjuster() { + public void test_plus_TemporalAmount() { MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); ZonedDateTime t = ZonedDateTime.of(LocalDateTime.of(2008, 6, 1, 12, 30, 59, 500), ZONE_0100); ZonedDateTime expected = ZonedDateTime.of(LocalDateTime.of(2009, 1, 1, 12, 30, 59, 500), ZONE_0100); @@ -1383,7 +1468,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { } @Test(groups={"tck"}) - public void test_plus_adjuster_Duration() { + public void test_plus_TemporalAmount_Duration() { Duration duration = Duration.ofSeconds(4L * 60 * 60 + 5L * 60 + 6L); ZonedDateTime t = ZonedDateTime.of(LocalDateTime.of(2008, 6, 1, 12, 30, 59, 500), ZONE_0100); ZonedDateTime expected = ZonedDateTime.of(LocalDateTime.of(2008, 6, 1, 16, 36, 5, 500), ZONE_0100); @@ -1391,20 +1476,20 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { } @Test(groups={"tck"}) - public void test_plus_adjuster_Period_zero() { + public void test_plus_TemporalAmount_Period_zero() { ZonedDateTime t = TEST_DATE_TIME.plus(MockSimplePeriod.ZERO_DAYS); assertEquals(t, TEST_DATE_TIME); } @Test(groups={"tck"}) - public void test_plus_adjuster_Duration_zero() { + public void test_plus_TemporalAmount_Duration_zero() { ZonedDateTime t = TEST_DATE_TIME.plus(Duration.ZERO); assertEquals(t, TEST_DATE_TIME); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_plus_adjuster_null() { - TEST_DATE_TIME.plus((TemporalAdder) null); + public void test_plus_TemporalAmount_null() { + TEST_DATE_TIME.plus((TemporalAmount) null); } //----------------------------------------------------------------------- @@ -1562,25 +1647,25 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { } //----------------------------------------------------------------------- - // minus(adjuster) + // minus(TemporalAmount) //----------------------------------------------------------------------- @Test(groups={"tck"}, dataProvider="plusDays") - public void test_minus_adjuster_Period_days(ZonedDateTime base, long amount, ZonedDateTime expected) { - assertEquals(base.minus(Period.of(-amount, DAYS)), expected); + public void test_minus_TemporalAmount_Period_days(ZonedDateTime base, int amount, ZonedDateTime expected) { + assertEquals(base.minus(Period.ofDays(-amount)), expected); } @Test(groups={"tck"}, dataProvider="plusTime") - public void test_minus_adjuster_Period_hours(ZonedDateTime base, long amount, ZonedDateTime expected) { - assertEquals(base.minus(Period.of(-amount, HOURS)), expected); + public void test_minus_TemporalAmount_Period_hours(ZonedDateTime base, long amount, ZonedDateTime expected) { + assertEquals(base.minus(MockSimplePeriod.of(-amount, HOURS)), expected); } @Test(groups={"tck"}, dataProvider="plusTime") - public void test_minus_adjuster_Duration_hours(ZonedDateTime base, long amount, ZonedDateTime expected) { + public void test_minus_TemporalAmount_Duration_hours(ZonedDateTime base, long amount, ZonedDateTime expected) { assertEquals(base.minus(Duration.ofHours(-amount)), expected); } @Test(groups={"tck"}) - public void test_minus_adjuster() { + public void test_minus_TemporalAmount() { MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); ZonedDateTime t = ZonedDateTime.of(LocalDateTime.of(2008, 6, 1, 12, 30, 59, 500), ZONE_0100); ZonedDateTime expected = ZonedDateTime.of(LocalDateTime.of(2007, 11, 1, 12, 30, 59, 500), ZONE_0100); @@ -1588,7 +1673,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { } @Test(groups={"tck"}) - public void test_minus_adjuster_Duration() { + public void test_minus_TemporalAmount_Duration() { Duration duration = Duration.ofSeconds(4L * 60 * 60 + 5L * 60 + 6L); ZonedDateTime t = ZonedDateTime.of(LocalDateTime.of(2008, 6, 1, 12, 30, 59, 500), ZONE_0100); ZonedDateTime expected = ZonedDateTime.of(LocalDateTime.of(2008, 6, 1, 8, 25, 53, 500), ZONE_0100); @@ -1596,20 +1681,20 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { } @Test(groups={"tck"}) - public void test_minus_adjuster_Period_zero() { + public void test_minus_TemporalAmount_Period_zero() { ZonedDateTime t = TEST_DATE_TIME.minus(MockSimplePeriod.ZERO_DAYS); assertEquals(t, TEST_DATE_TIME); } @Test(groups={"tck"}) - public void test_minus_adjuster_Duration_zero() { + public void test_minus_TemporalAmount_Duration_zero() { ZonedDateTime t = TEST_DATE_TIME.minus(Duration.ZERO); assertEquals(t, TEST_DATE_TIME); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_minus_adjuster_null() { - TEST_DATE_TIME.minus((TemporalSubtractor) null); + public void test_minus_TemporalAmount_null() { + TEST_DATE_TIME.minus((TemporalAmount) null); } //----------------------------------------------------------------------- @@ -1818,7 +1903,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_toOffsetDateTime() { - assertEquals(TEST_DATE_TIME.toOffsetDateTime(), OffsetDateTime.of(TEST_DATE_TIME.getDateTime(), TEST_DATE_TIME.getOffset())); + assertEquals(TEST_DATE_TIME.toOffsetDateTime(), OffsetDateTime.of(TEST_DATE_TIME.toLocalDateTime(), TEST_DATE_TIME.getOffset())); } //----------------------------------------------------------------------- @@ -1908,8 +1993,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_compareTo_time1() { - ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 39), ZONE_0100); - ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 41), ZONE_0100); // a is before b due to time + ZonedDateTime a = ZonedDateTime.of(2008, 6, 30, 11, 30, 39, 0, ZONE_0100); + ZonedDateTime b = ZonedDateTime.of(2008, 6, 30, 11, 30, 41, 0, ZONE_0100); // a is before b due to time assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1918,8 +2003,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_time2() { - ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 40, 4), ZONE_0100); - ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 40, 5), ZONE_0100); // a is before b due to time + ZonedDateTime a = ZonedDateTime.of(2008, 6, 30, 11, 30, 40, 4, ZONE_0100); + ZonedDateTime b = ZonedDateTime.of(2008, 6, 30, 11, 30, 40, 5, ZONE_0100); // a is before b due to time assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1928,8 +2013,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_offset1() { - ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 41), ZONE_0200); - ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 39), ZONE_0100); // a is before b due to offset + ZonedDateTime a = ZonedDateTime.of(2008, 6, 30, 11, 30, 41, 0, ZONE_0200); + ZonedDateTime b = ZonedDateTime.of(2008, 6, 30, 11, 30, 39, 0, ZONE_0100); // a is before b due to offset assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1938,8 +2023,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_offset2() { - ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 40, 5), ZoneId.of("UTC+01:01")); - ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30, 40, 4), ZONE_0100); // a is before b due to offset + ZonedDateTime a = ZonedDateTime.of(2008, 6, 30, 11, 30, 40, 5, ZoneId.of("UTC+01:01")); + ZonedDateTime b = ZonedDateTime.of(2008, 6, 30, 11, 30, 40, 4, ZONE_0100); // a is before b due to offset assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1948,8 +2033,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_both() { - ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 50), ZONE_0200); - ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 20), ZONE_0100); // a is before b on instant scale + ZonedDateTime a = ZonedDateTime.of(2008, 6, 30, 11, 50, 0, 0, ZONE_0200); + ZonedDateTime b = ZonedDateTime.of(2008, 6, 30, 11, 20, 0, 0, ZONE_0100); // a is before b on instant scale assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1958,8 +2043,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_bothNanos() { - ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 20, 40, 5), ZONE_0200); - ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 10, 20, 40, 6), ZONE_0100); // a is before b on instant scale + ZonedDateTime a = ZonedDateTime.of(2008, 6, 30, 11, 20, 40, 5, ZONE_0200); + ZonedDateTime b = ZonedDateTime.of(2008, 6, 30, 10, 20, 40, 6, ZONE_0100); // a is before b on instant scale assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1968,8 +2053,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { @Test(groups={"tck"}) public void test_compareTo_hourDifference() { - ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 10, 0), ZONE_0100); - ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 0), ZONE_0200); // a is before b despite being same time-line time + ZonedDateTime a = ZonedDateTime.of(2008, 6, 30, 10, 0, 0, 0, ZONE_0100); + ZonedDateTime b = ZonedDateTime.of(2008, 6, 30, 11, 0, 0, 0, ZONE_0200); // a is before b despite being same time-line time assertEquals(a.compareTo(b) < 0, true); assertEquals(b.compareTo(a) > 0, true); assertEquals(a.compareTo(a) == 0, true); @@ -1978,8 +2063,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_compareTo_null() { - LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); - ZonedDateTime a = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime a = ZonedDateTime.of(2008, 6, 30, 23, 30, 59, 0, ZONE_0100); a.compareTo(null); } @@ -1997,8 +2081,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { @Test(dataProvider="IsBefore", groups={"tck"}) public void test_isBefore(int hour1, int minute1, ZoneId zone1, int hour2, int minute2, ZoneId zone2, boolean expected) { - ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, hour1, minute1), zone1); - ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, hour2, minute2), zone2); + ZonedDateTime a = ZonedDateTime.of(2008, 6, 30, hour1, minute1, 0, 0, zone1); + ZonedDateTime b = ZonedDateTime.of(2008, 6, 30, hour2, minute2, 0, 0, zone2); assertEquals(a.isBefore(b), expected); assertEquals(b.isBefore(a), false); assertEquals(a.isBefore(a), false); @@ -2007,8 +2091,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_isBefore_null() { - LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); - ZonedDateTime a = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime a = ZonedDateTime.of(2008, 6, 30, 23, 30, 59, 0, ZONE_0100); a.isBefore(null); } @@ -2026,8 +2109,8 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { @Test(dataProvider="IsAfter", groups={"tck"}) public void test_isAfter(int hour1, int minute1, ZoneId zone1, int hour2, int minute2, ZoneId zone2, boolean expected) { - ZonedDateTime a = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, hour1, minute1), zone1); - ZonedDateTime b = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, hour2, minute2), zone2); + ZonedDateTime a = ZonedDateTime.of(2008, 6, 30, hour1, minute1, 0, 0, zone1); + ZonedDateTime b = ZonedDateTime.of(2008, 6, 30, hour2, minute2, 0, 0, zone2); assertEquals(a.isAfter(b), expected); assertEquals(b.isAfter(a), false); assertEquals(a.isAfter(a), false); @@ -2036,8 +2119,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_isAfter_null() { - LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 23, 30, 59, 0); - ZonedDateTime a = ZonedDateTime.of(ldt, ZONE_0100); + ZonedDateTime a = ZonedDateTime.of(2008, 6, 30, 23, 30, 59, 0, ZONE_0100); a.isAfter(null); } @@ -2134,7 +2216,7 @@ public class TCKZonedDateTime extends AbstractDateTimeTest { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_toString_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d H m s"); + DateTimeFormatter f = DateTimeFormatter.ofPattern("y M d H m s"); String t = ZonedDateTime.of(dateTime(2010, 12, 3, 11, 30), ZONE_PARIS).toString(f); assertEquals(t, "2010 12 3 11 30 0"); } diff --git a/jdk/test/java/time/tck/java/time/temporal/TestChrono.java b/jdk/test/java/time/tck/java/time/TestChronology.java similarity index 76% rename from jdk/test/java/time/tck/java/time/temporal/TestChrono.java rename to jdk/test/java/time/tck/java/time/TestChronology.java index cd30519dd04..b186cd315eb 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TestChrono.java +++ b/jdk/test/java/time/tck/java/time/TestChronology.java @@ -57,7 +57,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.temporal; +package tck.java.time; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -71,36 +71,23 @@ import java.io.ObjectOutputStream; import java.util.Locale; import java.util.Set; -import java.time.temporal.Chrono; +import java.time.chrono.Chronology; import java.time.temporal.ChronoField; -import java.time.calendar.HijrahChrono; -import java.time.calendar.JapaneseChrono; -import java.time.calendar.MinguoChrono; -import java.time.calendar.ThaiBuddhistChrono; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.ISOChrono; +import java.time.chrono.HijrahChronology; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.MinguoChronology; +import java.time.chrono.ThaiBuddhistChronology; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.IsoChronology; -import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** - * Test Chrono class. + * Test Chronology class. */ @Test -public class TestChrono { - - @BeforeMethod(groups="tck") - public void setUp() { - // Ensure each of the classes are initialized (until initialization is fixed) - Chrono c; - c = HijrahChrono.INSTANCE; - c = ISOChrono.INSTANCE; - c = JapaneseChrono.INSTANCE; - c = MinguoChrono.INSTANCE; - c = ThaiBuddhistChrono.INSTANCE; - c.toString(); // avoids variable being marked as unused - } +public class TestChronology { //----------------------------------------------------------------------- // regular data factory for names and descriptions of available calendars @@ -118,7 +105,7 @@ public class TestChrono { @Test(dataProvider = "calendars") public void test_getters(String chronoId, String calendarSystemType, String description) { - Chrono chrono = Chrono.of(chronoId); + Chronology chrono = Chronology.of(chronoId); assertNotNull(chrono, "Required calendar not found by ID: " + chronoId); assertEquals(chrono.getId(), chronoId); assertEquals(chrono.getCalendarType(), calendarSystemType); @@ -126,23 +113,23 @@ public class TestChrono { @Test(dataProvider = "calendars") public void test_required_calendars(String chronoId, String calendarSystemType, String description) { - Chrono chrono = Chrono.of(chronoId); + Chronology chrono = Chronology.of(chronoId); assertNotNull(chrono, "Required calendar not found by ID: " + chronoId); - chrono = Chrono.of(calendarSystemType); + chrono = Chronology.of(calendarSystemType); assertNotNull(chrono, "Required calendar not found by type: " + chronoId); - Set> cals = Chrono.getAvailableChronologies(); + Set cals = Chronology.getAvailableChronologies(); assertTrue(cals.contains(chrono), "Required calendar not found in set of available calendars"); } @Test(groups="tck") public void test_calendar_list() { - Set> chronos = Chrono.getAvailableChronologies(); + Set chronos = Chronology.getAvailableChronologies(); assertNotNull(chronos, "Required list of calendars must be non-null"); - for (Chrono chrono : chronos) { - Chrono lookup = Chrono.of(chrono.getId()); + for (Chronology chrono : chronos) { + Chronology lookup = Chronology.of(chrono.getId()); assertNotNull(lookup, "Required calendar not found: " + chrono); } - assertEquals(chronos.size() >= data_of_calendars().length, true, "Chrono.getAvailableChronologies().size = " + chronos.size() + assertEquals(chronos.size() >= data_of_calendars().length, true, "Chronology.getAvailableChronologies().size = " + chronos.size() + ", expected >= " + data_of_calendars().length); } @@ -151,7 +138,7 @@ public class TestChrono { */ @Test(dataProvider = "calendars", groups="tck") public void test_epoch(String name, String alias, String description) { - Chrono chrono = Chrono.of(name); // a chronology. In practice this is rarely hardcoded + Chronology chrono = Chronology.of(name); // a chronology. In practice this is rarely hardcoded ChronoLocalDate date1 = chrono.dateNow(); long epoch1 = date1.getLong(ChronoField.EPOCH_DAY); ChronoLocalDate date2 = date1.with(ChronoField.EPOCH_DAY, epoch1); @@ -166,41 +153,40 @@ public class TestChrono { @DataProvider(name = "calendarsystemtype") Object[][] data_CalendarType() { return new Object[][] { - {HijrahChrono.INSTANCE, "islamicc"}, - {ISOChrono.INSTANCE, "iso8601"}, - {JapaneseChrono.INSTANCE, "japanese"}, - {MinguoChrono.INSTANCE, "roc"}, - {ThaiBuddhistChrono.INSTANCE, "buddhist"}, + {HijrahChronology.INSTANCE, "islamicc"}, + {IsoChronology.INSTANCE, "iso8601"}, + {JapaneseChronology.INSTANCE, "japanese"}, + {MinguoChronology.INSTANCE, "roc"}, + {ThaiBuddhistChronology.INSTANCE, "buddhist"}, }; } @Test(dataProvider = "calendarsystemtype", groups="tck") - public void test_getCalendarType(Chrono chrono, String calendarType) { + public void test_getCalendarType(Chronology chrono, String calendarType) { assertEquals(chrono.getCalendarType(), calendarType); } @Test(dataProvider = "calendarsystemtype", groups="tck") - public void test_lookupLocale(Chrono chrono, String calendarType) { + public void test_lookupLocale(Chronology chrono, String calendarType) { Locale locale = new Locale.Builder().setLanguage("en").setRegion("CA").setUnicodeLocaleKeyword("ca", calendarType).build(); - assertEquals(Chrono.ofLocale(locale), chrono); + assertEquals(Chronology.ofLocale(locale), chrono); } //----------------------------------------------------------------------- // serialization; serialize and check each calendar system //----------------------------------------------------------------------- - @Test(groups={"implementation"}, dataProvider = "calendarsystemtype") - public > void test_chronoSerializationSingleton(C chrono, String calendarType) throws Exception { - C orginal = chrono; + @Test(groups={"tck","implementation"}, dataProvider = "calendarsystemtype") + public void test_chronoSerializationSingleton(Chronology chrono, String calendarType) throws Exception { + Chronology orginal = chrono; ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(baos); out.writeObject(orginal); out.close(); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bais); - @SuppressWarnings("unchecked") - C ser = (C) in.readObject(); - assertSame(ser, chrono, "Deserialized Chrono is not the singleton serialized"); + Chronology ser = (Chronology) in.readObject(); + assertSame(ser, chrono, "Deserialized Chronology is not the singleton serialized"); } } diff --git a/jdk/test/java/time/tck/java/time/temporal/TestISOChrono.java b/jdk/test/java/time/tck/java/time/TestIsoChronology.java similarity index 70% rename from jdk/test/java/time/tck/java/time/temporal/TestISOChrono.java rename to jdk/test/java/time/tck/java/time/TestIsoChronology.java index 634fab301e5..aa42e4a0ca0 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TestISOChrono.java +++ b/jdk/test/java/time/tck/java/time/TestIsoChronology.java @@ -57,13 +57,13 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.temporal; +package tck.java.time; +import static java.time.chrono.IsoChronology.ERA_BCE; +import static java.time.chrono.IsoChronology.ERA_CE; import static java.time.temporal.ChronoField.ERA; import static java.time.temporal.ChronoField.YEAR; import static java.time.temporal.ChronoField.YEAR_OF_ERA; -import static java.time.temporal.ISOChrono.ERA_BCE; -import static java.time.temporal.ISOChrono.ERA_CE; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; @@ -73,13 +73,13 @@ import java.time.DateTimeException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Month; -import java.time.temporal.Chrono; -import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; import java.time.temporal.Adjusters; -import java.time.calendar.HijrahChrono; -import java.time.temporal.Era; -import java.time.temporal.ISOChrono; +import java.time.temporal.ChronoField; +import java.time.chrono.HijrahChronology; +import java.time.chrono.Chronology; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Era; +import java.time.chrono.IsoChronology; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -89,15 +89,15 @@ import org.testng.annotations.Test; * Test. */ @Test -public class TestISOChrono { +public class TestIsoChronology { //----------------------------------------------------------------------- - // Chrono.ofName("ISO") Lookup by name + // Chronology.ofName("ISO") Lookup by name //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_chrono_byName() { - Chrono c = ISOChrono.INSTANCE; - Chrono test = Chrono.of("ISO"); + Chronology c = IsoChronology.INSTANCE; + Chronology test = Chronology.of("ISO"); Assert.assertNotNull(test, "The ISO calendar could not be found byName"); Assert.assertEquals(test.getId(), "ISO", "ID mismatch"); Assert.assertEquals(test.getCalendarType(), "iso8601", "Type mismatch"); @@ -109,7 +109,7 @@ public class TestISOChrono { //----------------------------------------------------------------------- @Test(groups="tck") public void instanceNotNull() { - assertNotNull(ISOChrono.INSTANCE); + assertNotNull(IsoChronology.INSTANCE); } //----------------------------------------------------------------------- @@ -117,8 +117,8 @@ public class TestISOChrono { //----------------------------------------------------------------------- @Test(groups="tck") public void test_eraOf() { - assertEquals(ISOChrono.INSTANCE.eraOf(0), ERA_BCE); - assertEquals(ISOChrono.INSTANCE.eraOf(1), ERA_CE); + assertEquals(IsoChronology.INSTANCE.eraOf(0), ERA_BCE); + assertEquals(IsoChronology.INSTANCE.eraOf(1), ERA_CE); } //----------------------------------------------------------------------- @@ -127,31 +127,31 @@ public class TestISOChrono { @DataProvider(name="samples") Object[][] data_samples() { return new Object[][] { - {ISOChrono.INSTANCE.date(1, 7, 8), LocalDate.of(1, 7, 8)}, - {ISOChrono.INSTANCE.date(1, 7, 20), LocalDate.of(1, 7, 20)}, - {ISOChrono.INSTANCE.date(1, 7, 21), LocalDate.of(1, 7, 21)}, + {IsoChronology.INSTANCE.date(1, 7, 8), LocalDate.of(1, 7, 8)}, + {IsoChronology.INSTANCE.date(1, 7, 20), LocalDate.of(1, 7, 20)}, + {IsoChronology.INSTANCE.date(1, 7, 21), LocalDate.of(1, 7, 21)}, - {ISOChrono.INSTANCE.date(2, 7, 8), LocalDate.of(2, 7, 8)}, - {ISOChrono.INSTANCE.date(3, 6, 27), LocalDate.of(3, 6, 27)}, - {ISOChrono.INSTANCE.date(3, 5, 23), LocalDate.of(3, 5, 23)}, - {ISOChrono.INSTANCE.date(4, 6, 16), LocalDate.of(4, 6, 16)}, - {ISOChrono.INSTANCE.date(4, 7, 3), LocalDate.of(4, 7, 3)}, - {ISOChrono.INSTANCE.date(4, 7, 4), LocalDate.of(4, 7, 4)}, - {ISOChrono.INSTANCE.date(5, 1, 1), LocalDate.of(5, 1, 1)}, - {ISOChrono.INSTANCE.date(1727, 3, 3), LocalDate.of(1727, 3, 3)}, - {ISOChrono.INSTANCE.date(1728, 10, 28), LocalDate.of(1728, 10, 28)}, - {ISOChrono.INSTANCE.date(2012, 10, 29), LocalDate.of(2012, 10, 29)}, + {IsoChronology.INSTANCE.date(2, 7, 8), LocalDate.of(2, 7, 8)}, + {IsoChronology.INSTANCE.date(3, 6, 27), LocalDate.of(3, 6, 27)}, + {IsoChronology.INSTANCE.date(3, 5, 23), LocalDate.of(3, 5, 23)}, + {IsoChronology.INSTANCE.date(4, 6, 16), LocalDate.of(4, 6, 16)}, + {IsoChronology.INSTANCE.date(4, 7, 3), LocalDate.of(4, 7, 3)}, + {IsoChronology.INSTANCE.date(4, 7, 4), LocalDate.of(4, 7, 4)}, + {IsoChronology.INSTANCE.date(5, 1, 1), LocalDate.of(5, 1, 1)}, + {IsoChronology.INSTANCE.date(1727, 3, 3), LocalDate.of(1727, 3, 3)}, + {IsoChronology.INSTANCE.date(1728, 10, 28), LocalDate.of(1728, 10, 28)}, + {IsoChronology.INSTANCE.date(2012, 10, 29), LocalDate.of(2012, 10, 29)}, }; } @Test(dataProvider="samples", groups={"tck"}) - public void test_toLocalDate(ChronoLocalDate isoDate, LocalDate iso) { + public void test_toLocalDate(LocalDate isoDate, LocalDate iso) { assertEquals(LocalDate.from(isoDate), iso); } @Test(dataProvider="samples", groups={"tck"}) - public void test_fromCalendrical(ChronoLocalDate isoDate, LocalDate iso) { - assertEquals(ISOChrono.INSTANCE.date(iso), isoDate); + public void test_fromCalendrical(LocalDate isoDate, LocalDate iso) { + assertEquals(IsoChronology.INSTANCE.date(iso), isoDate); } @DataProvider(name="badDates") @@ -176,7 +176,7 @@ public class TestISOChrono { @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class) public void test_badDates(int year, int month, int dom) { - ISOChrono.INSTANCE.date(year, month, dom); + IsoChronology.INSTANCE.date(year, month, dom); } @Test(groups="tck") @@ -184,7 +184,7 @@ public class TestISOChrono { int year = 5; int month = 5; int dayOfMonth = 5; - ChronoLocalDate test = ISOChrono.INSTANCE.date(ERA_BCE, year, month, dayOfMonth); + LocalDate test = IsoChronology.INSTANCE.date(ERA_BCE, year, month, dayOfMonth); assertEquals(test.getEra(), ERA_BCE); assertEquals(test.get(ChronoField.YEAR_OF_ERA), year); assertEquals(test.get(ChronoField.MONTH_OF_YEAR), month); @@ -198,7 +198,7 @@ public class TestISOChrono { @SuppressWarnings({ "unchecked", "rawtypes" }) @Test(expectedExceptions=DateTimeException.class, groups="tck") public void test_date_withEra_withWrongEra() { - ISOChrono.INSTANCE.date((Era) HijrahChrono.ERA_AH, 1, 1, 1); + IsoChronology.INSTANCE.date((Era) HijrahChronology.ERA_AH, 1, 1, 1); } //----------------------------------------------------------------------- @@ -206,16 +206,16 @@ public class TestISOChrono { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_adjust1() { - ChronoLocalDate base = ISOChrono.INSTANCE.date(1728, 10, 28); - ChronoLocalDate test = base.with(Adjusters.lastDayOfMonth()); - assertEquals(test, ISOChrono.INSTANCE.date(1728, 10, 31)); + LocalDate base = IsoChronology.INSTANCE.date(1728, 10, 28); + LocalDate test = base.with(Adjusters.lastDayOfMonth()); + assertEquals(test, IsoChronology.INSTANCE.date(1728, 10, 31)); } @Test(groups={"tck"}) public void test_adjust2() { - ChronoLocalDate base = ISOChrono.INSTANCE.date(1728, 12, 2); - ChronoLocalDate test = base.with(Adjusters.lastDayOfMonth()); - assertEquals(test, ISOChrono.INSTANCE.date(1728, 12, 31)); + LocalDate base = IsoChronology.INSTANCE.date(1728, 12, 2); + LocalDate test = base.with(Adjusters.lastDayOfMonth()); + assertEquals(test, IsoChronology.INSTANCE.date(1728, 12, 31)); } //----------------------------------------------------------------------- @@ -223,15 +223,15 @@ public class TestISOChrono { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_adjust_toLocalDate() { - ChronoLocalDate isoDate = ISOChrono.INSTANCE.date(1726, 1, 4); - ChronoLocalDate test = isoDate.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, ISOChrono.INSTANCE.date(2012, 7, 6)); + LocalDate isoDate = IsoChronology.INSTANCE.date(1726, 1, 4); + LocalDate test = isoDate.with(LocalDate.of(2012, 7, 6)); + assertEquals(test, IsoChronology.INSTANCE.date(2012, 7, 6)); } @Test(groups={"tck"}) public void test_adjust_toMonth() { - ChronoLocalDate isoDate = ISOChrono.INSTANCE.date(1726, 1, 4); - assertEquals(ISOChrono.INSTANCE.date(1726, 4, 4), isoDate.with(Month.APRIL)); + LocalDate isoDate = IsoChronology.INSTANCE.date(1726, 1, 4); + assertEquals(IsoChronology.INSTANCE.date(1726, 4, 4), isoDate.with(Month.APRIL)); } //----------------------------------------------------------------------- @@ -239,14 +239,14 @@ public class TestISOChrono { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_LocalDate_adjustToISODate() { - ChronoLocalDate isoDate = ISOChrono.INSTANCE.date(1728, 10, 29); + LocalDate isoDate = IsoChronology.INSTANCE.date(1728, 10, 29); LocalDate test = LocalDate.MIN.with(isoDate); assertEquals(test, LocalDate.of(1728, 10, 29)); } @Test(groups={"tck"}) public void test_LocalDateTime_adjustToISODate() { - ChronoLocalDate isoDate = ISOChrono.INSTANCE.date(1728, 10, 29); + LocalDate isoDate = IsoChronology.INSTANCE.date(1728, 10, 29); LocalDateTime test = LocalDateTime.MIN.with(isoDate); assertEquals(test, LocalDateTime.of(1728, 10, 29, 0, 0)); } @@ -268,7 +268,7 @@ public class TestISOChrono { @Test(dataProvider="leapYears", groups="tck") public void test_isLeapYear(int year, boolean isLeapYear) { - assertEquals(ISOChrono.INSTANCE.isLeapYear(year), isLeapYear); + assertEquals(IsoChronology.INSTANCE.isLeapYear(year), isLeapYear); } //----------------------------------------------------------------------- @@ -276,7 +276,7 @@ public class TestISOChrono { //----------------------------------------------------------------------- @Test(groups="tck") public void test_now() { - assertEquals(LocalDate.from(ISOChrono.INSTANCE.dateNow()), LocalDate.now()); + assertEquals(LocalDate.from(IsoChronology.INSTANCE.dateNow()), LocalDate.now()); } //----------------------------------------------------------------------- @@ -285,16 +285,16 @@ public class TestISOChrono { @DataProvider(name="toString") Object[][] data_toString() { return new Object[][] { - {ISOChrono.INSTANCE.date(1, 1, 1), "0001-01-01"}, - {ISOChrono.INSTANCE.date(1728, 10, 28), "1728-10-28"}, - {ISOChrono.INSTANCE.date(1728, 10, 29), "1728-10-29"}, - {ISOChrono.INSTANCE.date(1727, 12, 5), "1727-12-05"}, - {ISOChrono.INSTANCE.date(1727, 12, 6), "1727-12-06"}, + {IsoChronology.INSTANCE.date(1, 1, 1), "0001-01-01"}, + {IsoChronology.INSTANCE.date(1728, 10, 28), "1728-10-28"}, + {IsoChronology.INSTANCE.date(1728, 10, 29), "1728-10-29"}, + {IsoChronology.INSTANCE.date(1727, 12, 5), "1727-12-05"}, + {IsoChronology.INSTANCE.date(1727, 12, 6), "1727-12-06"}, }; } @Test(dataProvider="toString", groups={"tck"}) - public void test_toString(ChronoLocalDate isoDate, String expected) { + public void test_toString(LocalDate isoDate, String expected) { assertEquals(isoDate.toString(), expected); } @@ -303,12 +303,12 @@ public class TestISOChrono { //----------------------------------------------------------------------- @Test(groups="tck") public void test_equals_true() { - assertTrue(ISOChrono.INSTANCE.equals(ISOChrono.INSTANCE)); + assertTrue(IsoChronology.INSTANCE.equals(IsoChronology.INSTANCE)); } @Test(groups="tck") public void test_equals_false() { - assertFalse(ISOChrono.INSTANCE.equals(HijrahChrono.INSTANCE)); + assertFalse(IsoChronology.INSTANCE.equals(HijrahChronology.INSTANCE)); } } diff --git a/jdk/test/java/time/tck/java/time/calendar/TestJapaneseChrono.java b/jdk/test/java/time/tck/java/time/calendar/TestJapaneseChrono.java deleted file mode 100644 index 614a3ff0b0a..00000000000 --- a/jdk/test/java/time/tck/java/time/calendar/TestJapaneseChrono.java +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -/* - * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of JSR-310 nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tck.java.time.calendar; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; - -import java.util.List; - -import java.time.DateTimeException; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.Month; -import java.time.calendar.JapaneseChrono; -import java.time.temporal.Adjusters; -import java.time.temporal.Chrono; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.Era; -import java.time.temporal.ISOChrono; - -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -/** - * Test. - */ -@Test -public class TestJapaneseChrono { - - //----------------------------------------------------------------------- - // Chrono.ofName("Japanese") Lookup by name - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_chrono_byName() { - Chrono c = JapaneseChrono.INSTANCE; - Chrono test = Chrono.of("Japanese"); - Assert.assertNotNull(test, "The Japanese calendar could not be found byName"); - Assert.assertEquals(test.getId(), "Japanese", "ID mismatch"); - Assert.assertEquals(test.getCalendarType(), "japanese", "Type mismatch"); - Assert.assertEquals(test, c); - } - - //----------------------------------------------------------------------- - // creation, toLocalDate() - //----------------------------------------------------------------------- - @DataProvider(name="samples") - Object[][] data_samples() { - return new Object[][] { - {JapaneseChrono.INSTANCE.date(1, 1, 1), LocalDate.of(1, 1, 1)}, - {JapaneseChrono.INSTANCE.date(1, 1, 2), LocalDate.of(1, 1, 2)}, - {JapaneseChrono.INSTANCE.date(1, 1, 3), LocalDate.of(1, 1, 3)}, - - {JapaneseChrono.INSTANCE.date(2, 1, 1), LocalDate.of(2, 1, 1)}, - {JapaneseChrono.INSTANCE.date(3, 1, 1), LocalDate.of(3, 1, 1)}, - {JapaneseChrono.INSTANCE.date(3, 12, 6), LocalDate.of(3, 12, 6)}, - {JapaneseChrono.INSTANCE.date(4, 1, 1), LocalDate.of(4, 1, 1)}, - {JapaneseChrono.INSTANCE.date(4, 7, 3), LocalDate.of(4, 7, 3)}, - {JapaneseChrono.INSTANCE.date(4, 7, 4), LocalDate.of(4, 7, 4)}, - {JapaneseChrono.INSTANCE.date(5, 1, 1), LocalDate.of(5, 1, 1)}, - {JapaneseChrono.INSTANCE.date(1662, 3, 3), LocalDate.of(1662, 3, 3)}, - {JapaneseChrono.INSTANCE.date(1728, 10, 28), LocalDate.of(1728, 10, 28)}, - {JapaneseChrono.INSTANCE.date(1728, 10, 29), LocalDate.of(1728, 10, 29)}, - }; - } - - @Test(dataProvider="samples", groups={"tck"}) - public void test_toLocalDate(ChronoLocalDate jdate, LocalDate iso) { - assertEquals(LocalDate.from(jdate), iso); - } - - @Test(dataProvider="samples", groups={"tck"}) - public void test_fromCalendrical(ChronoLocalDate jdate, LocalDate iso) { - assertEquals(JapaneseChrono.INSTANCE.date(iso), jdate); - } - - @DataProvider(name="badDates") - Object[][] data_badDates() { - return new Object[][] { - {1728, 0, 0}, - - {1728, -1, 1}, - {1728, 0, 1}, - {1728, 14, 1}, - {1728, 15, 1}, - - {1728, 1, -1}, - {1728, 1, 0}, - {1728, 1, 32}, - - {1728, 12, -1}, - {1728, 12, 0}, - {1728, 12, 32}, - }; - } - - @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class) - public void test_badDates(int year, int month, int dom) { - JapaneseChrono.INSTANCE.date(year, month, dom); - } - - //----------------------------------------------------------------------- - // with(WithAdjuster) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_adjust1() { - ChronoLocalDate base = JapaneseChrono.INSTANCE.date(1728, 10, 29); - ChronoLocalDate test = base.with(Adjusters.lastDayOfMonth()); - assertEquals(test, JapaneseChrono.INSTANCE.date(1728, 10, 31)); - } - - @Test(groups={"tck"}) - public void test_adjust2() { - ChronoLocalDate base = JapaneseChrono.INSTANCE.date(1728, 12, 2); - ChronoLocalDate test = base.with(Adjusters.lastDayOfMonth()); - assertEquals(test, JapaneseChrono.INSTANCE.date(1728, 12, 31)); - } - - //----------------------------------------------------------------------- - // JapaneseDate.with(Local*) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_adjust_toLocalDate() { - ChronoLocalDate jdate = JapaneseChrono.INSTANCE.date(1726, 1, 4); - ChronoLocalDate test = jdate.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, JapaneseChrono.INSTANCE.date(2012, 7, 6)); - } - - @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) - public void test_adjust_toMonth() { - ChronoLocalDate jdate = JapaneseChrono.INSTANCE.date(1726, 1, 4); - jdate.with(Month.APRIL); - } - - //----------------------------------------------------------------------- - // LocalDate.with(JapaneseDate) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_LocalDate_adjustToJapaneseDate() { - ChronoLocalDate jdate = JapaneseChrono.INSTANCE.date(1728, 10, 29); - LocalDate test = LocalDate.MIN.with(jdate); - assertEquals(test, LocalDate.of(1728, 10, 29)); - } - - @Test(groups={"tck"}) - public void test_LocalDateTime_adjustToJapaneseDate() { - ChronoLocalDate jdate = JapaneseChrono.INSTANCE.date(1728, 10, 29); - LocalDateTime test = LocalDateTime.MIN.with(jdate); - assertEquals(test, LocalDateTime.of(1728, 10, 29, 0, 0)); - } - - //----------------------------------------------------------------------- - // Check Japanese Eras - //----------------------------------------------------------------------- - @DataProvider(name="japaneseEras") - Object[][] data_japanseseEras() { - return new Object[][] { - { JapaneseChrono.ERA_SEIREKI, -999, "Seireki"}, - { JapaneseChrono.ERA_MEIJI, -1, "Meiji"}, - { JapaneseChrono.ERA_TAISHO, 0, "Taisho"}, - { JapaneseChrono.ERA_SHOWA, 1, "Showa"}, - { JapaneseChrono.ERA_HEISEI, 2, "Heisei"}, - }; - } - - @Test(groups={"tck"}, dataProvider="japaneseEras") - public void test_Japanese_Eras(Era era, int eraValue, String name) { - assertEquals(era.getValue(), eraValue, "EraValue"); - assertEquals(era.toString(), name, "Era Name"); - assertEquals(era, JapaneseChrono.INSTANCE.eraOf(eraValue), "JapaneseChrono.eraOf()"); - List> eras = JapaneseChrono.INSTANCE.eras(); - assertTrue(eras.contains(era), "Era is not present in JapaneseChrono.INSTANCE.eras()"); - } - - @Test(groups="tck") - public void test_Japanese_badEras() { - int badEras[] = {-1000, -998, -997, -2, 3, 4, 1000}; - for (int badEra : badEras) { - try { - Era era = JapaneseChrono.INSTANCE.eraOf(badEra); - fail("JapaneseChrono.eraOf returned " + era + " + for invalid eraValue " + badEra); - } catch (DateTimeException ex) { - // ignore expected exception - } - } - } - - //----------------------------------------------------------------------- - // toString() - //----------------------------------------------------------------------- - @DataProvider(name="toString") - Object[][] data_toString() { - return new Object[][] { - {JapaneseChrono.INSTANCE.date(0001, 1, 1), "Japanese 0001-01-01"}, - {JapaneseChrono.INSTANCE.date(1728, 10, 28), "Japanese 1728-10-28"}, - {JapaneseChrono.INSTANCE.date(1728, 10, 29), "Japanese 1728-10-29"}, - {JapaneseChrono.INSTANCE.date(1727, 12, 5), "Japanese 1727-12-05"}, - {JapaneseChrono.INSTANCE.date(1727, 12, 6), "Japanese 1727-12-06"}, - {JapaneseChrono.INSTANCE.date(1868, 9, 8), "Japanese Meiji 1-09-08"}, - {JapaneseChrono.INSTANCE.date(1912, 7, 29), "Japanese Meiji 45-07-29"}, - {JapaneseChrono.INSTANCE.date(1912, 7, 30), "Japanese Taisho 1-07-30"}, - {JapaneseChrono.INSTANCE.date(1926, 12, 24), "Japanese Taisho 15-12-24"}, - {JapaneseChrono.INSTANCE.date(1926, 12, 25), "Japanese Showa 1-12-25"}, - {JapaneseChrono.INSTANCE.date(1989, 1, 7), "Japanese Showa 64-01-07"}, - {JapaneseChrono.INSTANCE.date(1989, 1, 8), "Japanese Heisei 1-01-08"}, - {JapaneseChrono.INSTANCE.date(2012, 12, 6), "Japanese Heisei 24-12-06"}, - }; - } - - @Test(dataProvider="toString", groups={"tck"}) - public void test_toString(ChronoLocalDate jdate, String expected) { - assertEquals(jdate.toString(), expected); - } - - //----------------------------------------------------------------------- - // equals() - //----------------------------------------------------------------------- - @Test(groups="tck") - public void test_equals_true() { - assertTrue(JapaneseChrono.INSTANCE.equals(JapaneseChrono.INSTANCE)); - } - - @Test(groups="tck") - public void test_equals_false() { - assertFalse(JapaneseChrono.INSTANCE.equals(ISOChrono.INSTANCE)); - } - -} diff --git a/jdk/test/java/time/tck/java/time/calendar/TestThaiBuddhistChrono.java b/jdk/test/java/time/tck/java/time/calendar/TestThaiBuddhistChrono.java deleted file mode 100644 index 4d20f570be8..00000000000 --- a/jdk/test/java/time/tck/java/time/calendar/TestThaiBuddhistChrono.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -/* - * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of JSR-310 nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tck.java.time.calendar; - -import static java.time.temporal.ChronoField.DAY_OF_MONTH; -import static java.time.temporal.ChronoField.DAY_OF_YEAR; -import static java.time.temporal.ChronoField.MONTH_OF_YEAR; -import static java.time.temporal.ChronoField.YEAR; -import static java.time.temporal.ChronoField.YEAR_OF_ERA; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; - -import java.time.DateTimeException; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.Month; -import java.time.calendar.ThaiBuddhistChrono; -import java.time.temporal.Chrono; -import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.Adjusters; -import java.time.temporal.ValueRange; -import java.time.temporal.ISOChrono; - -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -/** - * Test. - */ -@Test -public class TestThaiBuddhistChrono { - - private static final int YDIFF = 543; - - //----------------------------------------------------------------------- - // Chrono.ofName("ThaiBuddhist") Lookup by name - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_chrono_byName() { - Chrono c = ThaiBuddhistChrono.INSTANCE; - Chrono test = Chrono.of("ThaiBuddhist"); - Assert.assertNotNull(test, "The ThaiBuddhist calendar could not be found byName"); - Assert.assertEquals(test.getId(), "ThaiBuddhist", "ID mismatch"); - Assert.assertEquals(test.getCalendarType(), "buddhist", "Type mismatch"); - Assert.assertEquals(test, c); - } - - //----------------------------------------------------------------------- - // creation, toLocalDate() - //----------------------------------------------------------------------- - @DataProvider(name="samples") - Object[][] data_samples() { - return new Object[][] { - {ThaiBuddhistChrono.INSTANCE.date(1 + YDIFF, 1, 1), LocalDate.of(1, 1, 1)}, - {ThaiBuddhistChrono.INSTANCE.date(1 + YDIFF, 1, 2), LocalDate.of(1, 1, 2)}, - {ThaiBuddhistChrono.INSTANCE.date(1 + YDIFF, 1, 3), LocalDate.of(1, 1, 3)}, - - {ThaiBuddhistChrono.INSTANCE.date(2 + YDIFF, 1, 1), LocalDate.of(2, 1, 1)}, - {ThaiBuddhistChrono.INSTANCE.date(3 + YDIFF, 1, 1), LocalDate.of(3, 1, 1)}, - {ThaiBuddhistChrono.INSTANCE.date(3 + YDIFF, 12, 6), LocalDate.of(3, 12, 6)}, - {ThaiBuddhistChrono.INSTANCE.date(4 + YDIFF, 1, 1), LocalDate.of(4, 1, 1)}, - {ThaiBuddhistChrono.INSTANCE.date(4 + YDIFF, 7, 3), LocalDate.of(4, 7, 3)}, - {ThaiBuddhistChrono.INSTANCE.date(4 + YDIFF, 7, 4), LocalDate.of(4, 7, 4)}, - {ThaiBuddhistChrono.INSTANCE.date(5 + YDIFF, 1, 1), LocalDate.of(5, 1, 1)}, - {ThaiBuddhistChrono.INSTANCE.date(1662 + YDIFF, 3, 3), LocalDate.of(1662, 3, 3)}, - {ThaiBuddhistChrono.INSTANCE.date(1728 + YDIFF, 10, 28), LocalDate.of(1728, 10, 28)}, - {ThaiBuddhistChrono.INSTANCE.date(1728 + YDIFF, 10, 29), LocalDate.of(1728, 10, 29)}, - {ThaiBuddhistChrono.INSTANCE.date(2555, 8, 29), LocalDate.of(2012, 8, 29)}, - }; - } - - @Test(dataProvider="samples", groups={"tck"}) - public void test_toLocalDate(ChronoLocalDate jdate, LocalDate iso) { - assertEquals(LocalDate.from(jdate), iso); - } - - @Test(dataProvider="samples", groups={"tck"}) - public void test_fromCalendrical(ChronoLocalDate jdate, LocalDate iso) { - assertEquals(ThaiBuddhistChrono.INSTANCE.date(iso), jdate); - } - - @DataProvider(name="badDates") - Object[][] data_badDates() { - return new Object[][] { - {1728, 0, 0}, - - {1728, -1, 1}, - {1728, 0, 1}, - {1728, 14, 1}, - {1728, 15, 1}, - - {1728, 1, -1}, - {1728, 1, 0}, - {1728, 1, 32}, - - {1728, 12, -1}, - {1728, 12, 0}, - {1728, 12, 32}, - }; - } - - @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class) - public void test_badDates(int year, int month, int dom) { - ThaiBuddhistChrono.INSTANCE.date(year, month, dom); - } - - //----------------------------------------------------------------------- - // with(WithAdjuster) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_adjust1() { - ChronoLocalDate base = ThaiBuddhistChrono.INSTANCE.date(1728, 10, 29); - ChronoLocalDate test = base.with(Adjusters.lastDayOfMonth()); - assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(1728, 10, 31)); - } - - @Test(groups={"tck"}) - public void test_adjust2() { - ChronoLocalDate base = ThaiBuddhistChrono.INSTANCE.date(1728, 12, 2); - ChronoLocalDate test = base.with(Adjusters.lastDayOfMonth()); - assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(1728, 12, 31)); - } - - //----------------------------------------------------------------------- - // withYear() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_withYear_BE() { - ChronoLocalDate base = ThaiBuddhistChrono.INSTANCE.date(2555, 8, 29); - ChronoLocalDate test = base.with(YEAR, 2554); - assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(2554, 8, 29)); - } - - @Test(groups={"tck"}) - public void test_withYear_BBE() { - ChronoLocalDate base = ThaiBuddhistChrono.INSTANCE.date(-2554, 8, 29); - ChronoLocalDate test = base.with(YEAR_OF_ERA, 2554); - assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(-2553, 8, 29)); - } - - //----------------------------------------------------------------------- - // withEra() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_withEra_BE() { - ChronoLocalDate base = ThaiBuddhistChrono.INSTANCE.date(2555, 8, 29); - ChronoLocalDate test = base.with(ChronoField.ERA, ThaiBuddhistChrono.ERA_BE.getValue()); - assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(2555, 8, 29)); - } - - @Test(groups={"tck"}) - public void test_withEra_BBE() { - ChronoLocalDate base = ThaiBuddhistChrono.INSTANCE.date(-2554, 8, 29); - ChronoLocalDate test = base.with(ChronoField.ERA, ThaiBuddhistChrono.ERA_BEFORE_BE.getValue()); - assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(-2554, 8, 29)); - } - - @Test(groups={"tck"}) - public void test_withEra_swap() { - ChronoLocalDate base = ThaiBuddhistChrono.INSTANCE.date(-2554, 8, 29); - ChronoLocalDate test = base.with(ChronoField.ERA, ThaiBuddhistChrono.ERA_BE.getValue()); - assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(2555, 8, 29)); - } - - //----------------------------------------------------------------------- - // BuddhistDate.with(Local*) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_adjust_toLocalDate() { - ChronoLocalDate jdate = ThaiBuddhistChrono.INSTANCE.date(1726, 1, 4); - ChronoLocalDate test = jdate.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, ThaiBuddhistChrono.INSTANCE.date(2555, 7, 6)); - } - - @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) - public void test_adjust_toMonth() { - ChronoLocalDate jdate = ThaiBuddhistChrono.INSTANCE.date(1726, 1, 4); - jdate.with(Month.APRIL); - } - - //----------------------------------------------------------------------- - // LocalDate.with(BuddhistDate) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_LocalDate_adjustToBuddhistDate() { - ChronoLocalDate jdate = ThaiBuddhistChrono.INSTANCE.date(2555, 10, 29); - LocalDate test = LocalDate.MIN.with(jdate); - assertEquals(test, LocalDate.of(2012, 10, 29)); - } - - @Test(groups={"tck"}) - public void test_LocalDateTime_adjustToBuddhistDate() { - ChronoLocalDate jdate = ThaiBuddhistChrono.INSTANCE.date(2555, 10, 29); - LocalDateTime test = LocalDateTime.MIN.with(jdate); - assertEquals(test, LocalDateTime.of(2012, 10, 29, 0, 0)); - } - - //----------------------------------------------------------------------- - // toString() - //----------------------------------------------------------------------- - @DataProvider(name="toString") - Object[][] data_toString() { - return new Object[][] { - {ThaiBuddhistChrono.INSTANCE.date(544, 1, 1), "ThaiBuddhist BE 544-01-01"}, - {ThaiBuddhistChrono.INSTANCE.date(2271, 10, 28), "ThaiBuddhist BE 2271-10-28"}, - {ThaiBuddhistChrono.INSTANCE.date(2271, 10, 29), "ThaiBuddhist BE 2271-10-29"}, - {ThaiBuddhistChrono.INSTANCE.date(2270, 12, 5), "ThaiBuddhist BE 2270-12-05"}, - {ThaiBuddhistChrono.INSTANCE.date(2270, 12, 6), "ThaiBuddhist BE 2270-12-06"}, - }; - } - - @Test(dataProvider="toString", groups={"tck"}) - public void test_toString(ChronoLocalDate jdate, String expected) { - assertEquals(jdate.toString(), expected); - } - - //----------------------------------------------------------------------- - // chronology range(ChronoField) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_Chrono_range() { - long minYear = LocalDate.MIN.getYear() + YDIFF; - long maxYear = LocalDate.MAX.getYear() + YDIFF; - assertEquals(ThaiBuddhistChrono.INSTANCE.range(YEAR), ValueRange.of(minYear, maxYear)); - assertEquals(ThaiBuddhistChrono.INSTANCE.range(YEAR_OF_ERA), ValueRange.of(1, -minYear + 1, maxYear)); - - assertEquals(ThaiBuddhistChrono.INSTANCE.range(DAY_OF_MONTH), DAY_OF_MONTH.range()); - assertEquals(ThaiBuddhistChrono.INSTANCE.range(DAY_OF_YEAR), DAY_OF_YEAR.range()); - assertEquals(ThaiBuddhistChrono.INSTANCE.range(MONTH_OF_YEAR), MONTH_OF_YEAR.range()); - } - - //----------------------------------------------------------------------- - // equals() - //----------------------------------------------------------------------- - @Test(groups="tck") - public void test_equals_true() { - assertTrue(ThaiBuddhistChrono.INSTANCE.equals(ThaiBuddhistChrono.INSTANCE)); - } - - @Test(groups="tck") - public void test_equals_false() { - assertFalse(ThaiBuddhistChrono.INSTANCE.equals(ISOChrono.INSTANCE)); - } - -} diff --git a/jdk/test/java/time/tck/java/time/calendar/CopticChrono.java b/jdk/test/java/time/tck/java/time/chrono/CopticChronology.java similarity index 87% rename from jdk/test/java/time/tck/java/time/calendar/CopticChrono.java rename to jdk/test/java/time/tck/java/time/chrono/CopticChronology.java index c3dc941e491..5c55d7593cc 100644 --- a/jdk/test/java/time/tck/java/time/calendar/CopticChrono.java +++ b/jdk/test/java/time/tck/java/time/chrono/CopticChronology.java @@ -54,7 +54,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.calendar; +package tck.java.time.chrono; import static java.time.temporal.ChronoField.EPOCH_DAY; @@ -67,9 +67,9 @@ import java.time.DateTimeException; import java.time.temporal.ChronoField; import java.time.temporal.TemporalAccessor; import java.time.temporal.ValueRange; -import java.time.temporal.Chrono; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.Era; +import java.time.chrono.Chronology; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Era; /** * The Coptic calendar system. @@ -96,22 +96,22 @@ import java.time.temporal.Era; *

    Implementation notes

    * This class is immutable and thread-safe. */ -public final class CopticChrono extends Chrono implements Serializable { +public final class CopticChronology extends Chronology implements Serializable { /** * Singleton instance of the Coptic chronology. */ - public static final CopticChrono INSTANCE = new CopticChrono(); + public static final CopticChronology INSTANCE = new CopticChronology(); /** * The singleton instance for the era BEFORE_AM. * This has the numeric value of {@code 0}. */ - public static final Era ERA_BEFORE_AM = CopticEra.BEFORE_AM; + public static final Era ERA_BEFORE_AM = CopticEra.BEFORE_AM; /** * The singleton instance for the era AM - 'Era of the Martyrs'. * This has the numeric value of {@code 1}. */ - public static final Era ERA_AM = CopticEra.AM; + public static final Era ERA_AM = CopticEra.AM; /** * Serialization version. @@ -137,7 +137,7 @@ public final class CopticChrono extends Chrono implements Serializ /** * Public Constructor to be instantiated by the ServiceLoader */ - public CopticChrono() { + public CopticChronology() { } /** @@ -153,8 +153,8 @@ public final class CopticChrono extends Chrono implements Serializ /** * Gets the ID of the chronology - 'Coptic'. *

    - * The ID uniquely identifies the {@code Chrono}. - * It can be used to lookup the {@code Chrono} using {@link #of(String)}. + * The ID uniquely identifies the {@code Chronology}. + * It can be used to lookup the {@code Chronology} using {@link #of(String)}. * * @return the chronology ID - 'Coptic' * @see #getCalendarType() @@ -169,7 +169,7 @@ public final class CopticChrono extends Chrono implements Serializ *

    * The calendar type is an identifier defined by the * Unicode Locale Data Markup Language (LDML) specification. - * It can be used to lookup the {@code Chrono} using {@link #of(String)}. + * It can be used to lookup the {@code Chronology} using {@link #of(String)}. * It can also be used as part of a locale, accessible via * {@link Locale#getUnicodeLocaleType(String)} with the key 'ca'. * @@ -183,17 +183,17 @@ public final class CopticChrono extends Chrono implements Serializ //----------------------------------------------------------------------- @Override - public ChronoLocalDate date(int prolepticYear, int month, int dayOfMonth) { + public CopticDate date(int prolepticYear, int month, int dayOfMonth) { return new CopticDate(prolepticYear, month, dayOfMonth); } @Override - public ChronoLocalDate dateYearDay(int prolepticYear, int dayOfYear) { + public CopticDate dateYearDay(int prolepticYear, int dayOfYear) { return new CopticDate(prolepticYear, (dayOfYear - 1) / 30 + 1, (dayOfYear - 1) % 30 + 1); } @Override - public ChronoLocalDate date(TemporalAccessor dateTime) { + public CopticDate date(TemporalAccessor dateTime) { if (dateTime instanceof CopticDate) { return (CopticDate) dateTime; } @@ -217,7 +217,7 @@ public final class CopticChrono extends Chrono implements Serializ } @Override - public int prolepticYear(Era era, int yearOfEra) { + public int prolepticYear(Era era, int yearOfEra) { if (era instanceof CopticEra == false) { throw new DateTimeException("Era must be CopticEra"); } @@ -225,13 +225,13 @@ public final class CopticChrono extends Chrono implements Serializ } @Override - public Era eraOf(int eraValue) { + public Era eraOf(int eraValue) { return CopticEra.of(eraValue); } @Override - public List> eras() { - return Arrays.>asList(CopticEra.values()); + public List eras() { + return Arrays.asList(CopticEra.values()); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/tck/java/time/calendar/CopticDate.java b/jdk/test/java/time/tck/java/time/chrono/CopticDate.java similarity index 87% rename from jdk/test/java/time/tck/java/time/calendar/CopticDate.java rename to jdk/test/java/time/tck/java/time/chrono/CopticDate.java index 30f1664dd0e..d8447eb660f 100644 --- a/jdk/test/java/time/tck/java/time/calendar/CopticDate.java +++ b/jdk/test/java/time/tck/java/time/chrono/CopticDate.java @@ -53,7 +53,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.calendar; +package tck.java.time.chrono; import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; @@ -67,29 +67,26 @@ import java.io.Serializable; import java.time.DateTimeException; import java.time.LocalDate; +import java.time.Period; +import java.time.chrono.ChronoLocalDate; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; import java.time.temporal.ChronoUnit; -import java.time.temporal.Era; import java.time.temporal.Temporal; -import java.time.temporal.TemporalAdjuster; -import java.time.temporal.TemporalAdder; -import java.time.temporal.TemporalSubtractor; import java.time.temporal.TemporalField; import java.time.temporal.TemporalUnit; import java.time.temporal.ValueRange; -import java.time.temporal.Year; +import java.time.Year; /** * A date in the Coptic calendar system. *

    - * This implements {@code ChronoLocalDate} for the {@link CopticChrono Coptic calendar}. + * This implements {@code ChronoLocalDate} for the {@link CopticChronology Coptic calendar}. * *

    Implementation notes

    * This class is immutable and thread-safe. */ -final class CopticDate - implements ChronoLocalDate, Serializable { +public final class CopticDate + implements ChronoLocalDate, Serializable { /** * Serialization version. @@ -133,7 +130,7 @@ final class CopticDate private static CopticDate resolvePreviousValid(int prolepticYear, int month, int day) { if (month == 13 && day > 5) { - day = CopticChrono.INSTANCE.isLeapYear(prolepticYear) ? 6 : 5; + day = CopticChronology.INSTANCE.isLeapYear(prolepticYear) ? 6 : 5; } return new CopticDate(prolepticYear, month, day); } @@ -148,12 +145,12 @@ final class CopticDate * @throws DateTimeException if the date is invalid */ CopticDate(int prolepticYear, int month, int dayOfMonth) { - CopticChrono.MOY_RANGE.checkValidValue(month, MONTH_OF_YEAR); + CopticChronology.MOY_RANGE.checkValidValue(month, MONTH_OF_YEAR); ValueRange range; if (month == 13) { - range = CopticChrono.INSTANCE.isLeapYear(prolepticYear) ? CopticChrono.DOM_RANGE_LEAP : CopticChrono.DOM_RANGE_NONLEAP; + range = CopticChronology.INSTANCE.isLeapYear(prolepticYear) ? CopticChronology.DOM_RANGE_LEAP : CopticChronology.DOM_RANGE_NONLEAP; } else { - range = CopticChrono.DOM_RANGE; + range = CopticChronology.DOM_RANGE; } range.checkValidValue(dayOfMonth, DAY_OF_MONTH); @@ -174,8 +171,8 @@ final class CopticDate //----------------------------------------------------------------------- @Override - public CopticChrono getChrono() { - return CopticChrono.INSTANCE; + public CopticChronology getChronology() { + return CopticChronology.INSTANCE; } //----------------------------------------------------------------------- @@ -202,11 +199,11 @@ final class CopticDate case YEAR_OF_ERA: return (prolepticYear <= 0 ? ValueRange.of(1, Year.MAX_VALUE + 1) : ValueRange.of(1, Year.MAX_VALUE)); // TODO } - return getChrono().range(f); + return getChronology().range(f); } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doRange(this); + return field.rangeRefinedBy(this); } @Override @@ -228,7 +225,7 @@ final class CopticDate } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doGet(this); + return field.getFrom(this); } @Override @@ -253,7 +250,7 @@ final class CopticDate } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doWith(this, newValue); + return field.adjustInto(this, newValue); } //----------------------------------------------------------------------- @@ -272,7 +269,7 @@ final class CopticDate } throw new DateTimeException(unit.getName() + " not valid for CopticDate"); } - return unit.doPlus(this, amountToAdd); + return unit.addTo(this, amountToAdd); } //----------------------------------------------------------------------- @@ -304,13 +301,32 @@ final class CopticDate throw new DateTimeException("Unable to calculate period between objects of two different types"); } ChronoLocalDate end = (ChronoLocalDate) endDateTime; - if (getChrono().equals(end.getChrono()) == false) { + if (getChronology().equals(end.getChronology()) == false) { throw new DateTimeException("Unable to calculate period between two different chronologies"); } if (unit instanceof ChronoUnit) { return LocalDate.from(this).periodUntil(end, unit); // TODO: this is wrong } - return unit.between(this, endDateTime).getAmount(); + return unit.between(this, endDateTime); + } + + @Override + public Period periodUntil(ChronoLocalDate endDate) { + // TODO: untested + CopticDate end = (CopticDate) getChronology().date(endDate); + long totalMonths = (end.prolepticYear - this.prolepticYear) * 13 + (end.month - this.month); // safe + int days = end.day - this.day; + if (totalMonths > 0 && days < 0) { + totalMonths--; + CopticDate calcDate = this.plusMonths(totalMonths); + days = (int) (end.toEpochDay() - calcDate.toEpochDay()); // safe + } else if (totalMonths < 0 && days > 0) { + totalMonths++; + days -= end.lengthOfMonth(); + } + long years = totalMonths / 13; // safe + int months = (int) (totalMonths % 13); // safe + return Period.of(Math.toIntExact(years), months, days); } //----------------------------------------------------------------------- @@ -328,7 +344,7 @@ final class CopticDate long moy = getLong(MONTH_OF_YEAR); long dom = getLong(DAY_OF_MONTH); StringBuilder buf = new StringBuilder(30); - buf.append(getChrono().toString()) + buf.append(getChronology().toString()) .append(" ") .append(getEra()) .append(" ") diff --git a/jdk/test/java/time/tck/java/time/calendar/CopticEra.java b/jdk/test/java/time/tck/java/time/chrono/CopticEra.java similarity index 63% rename from jdk/test/java/time/tck/java/time/calendar/CopticEra.java rename to jdk/test/java/time/tck/java/time/chrono/CopticEra.java index 2526530ed3b..cfe4bdc9b34 100644 --- a/jdk/test/java/time/tck/java/time/calendar/CopticEra.java +++ b/jdk/test/java/time/tck/java/time/chrono/CopticEra.java @@ -53,23 +53,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.calendar; +package tck.java.time.chrono; -import static java.time.temporal.ChronoField.ERA; - -import java.util.Locale; import java.time.DateTimeException; -import java.time.temporal.ChronoField; -import java.time.temporal.Queries; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalField; -import java.time.temporal.TemporalQuery; -import java.time.temporal.ValueRange; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.Era; -import java.time.format.DateTimeFormatterBuilder; -import java.time.format.TextStyle; +import java.time.chrono.Era; /** * An era in the Coptic calendar system. @@ -83,7 +71,7 @@ import java.time.format.TextStyle; *

    Implementation notes

    * This is an immutable and thread-safe enum. */ -enum CopticEra implements Era { +enum CopticEra implements Era { /** * The singleton instance for the era BEFORE_AM, 'Before Era of the Martyrs'. @@ -131,80 +119,20 @@ enum CopticEra implements Era { } @Override - public CopticChrono getChrono() { - return CopticChrono.INSTANCE; + public CopticChronology getChronology() { + return CopticChronology.INSTANCE; } // JDK8 default methods: //----------------------------------------------------------------------- @Override - public ChronoLocalDate date(int year, int month, int day) { - return getChrono().date(this, year, month, day); + public CopticDate date(int year, int month, int day) { + return (CopticDate)(getChronology().date(this, year, month, day)); } @Override - public ChronoLocalDate dateYearDay(int year, int dayOfYear) { - return getChrono().dateYearDay(this, year, dayOfYear); - } - - //----------------------------------------------------------------------- - @Override - public boolean isSupported(TemporalField field) { - if (field instanceof ChronoField) { - return field == ERA; - } - return field != null && field.doIsSupported(this); - } - - @Override - public ValueRange range(TemporalField field) { - if (field == ERA) { - return field.range(); - } else if (field instanceof ChronoField) { - throw new DateTimeException("Unsupported field: " + field.getName()); - } - return field.doRange(this); - } - - @Override - public int get(TemporalField field) { - if (field == ERA) { - return getValue(); - } - return range(field).checkValidIntValue(getLong(field), field); - } - - @Override - public long getLong(TemporalField field) { - if (field == ERA) { - return getValue(); - } else if (field instanceof ChronoField) { - throw new DateTimeException("Unsupported field: " + field.getName()); - } - return field.doGet(this); - } - - //------------------------------------------------------------------------- - @Override - public Temporal adjustInto(Temporal dateTime) { - return dateTime.with(ERA, getValue()); - } - - @SuppressWarnings("unchecked") - @Override - public R query(TemporalQuery query) { - if (query == Queries.zoneId()) { - return null; - } else if (query == Queries.chrono()) { - return (R) getChrono(); - } - return query.queryFrom(this); - } - - //----------------------------------------------------------------------- - @Override - public String getText(TextStyle style, Locale locale) { - return new DateTimeFormatterBuilder().appendText(ERA, style).toFormatter(locale).print(this); + public CopticDate dateYearDay(int year, int dayOfYear) { + return (CopticDate)(getChronology().dateYearDay(this, year, dayOfYear)); } } diff --git a/jdk/test/java/time/tck/java/time/chrono/TCKChronology.java b/jdk/test/java/time/tck/java/time/chrono/TCKChronology.java new file mode 100644 index 00000000000..c1a43093733 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/chrono/TCKChronology.java @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2012, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.chrono; + +import static org.testng.Assert.assertEquals; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Chronology; +import java.time.chrono.Era; +import java.time.chrono.IsoChronology; +import java.time.temporal.ChronoField; +import java.time.temporal.Queries; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQuery; +import java.time.temporal.ValueRange; +import java.util.List; + +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TCKChronology { + // Can only work with IsoChronology here + // others may be in separate module + + @Test + public void factory_from_TemporalAccessor_dateWithChronlogy() { + assertEquals(Chronology.from(LocalDate.of(2012, 6, 30)), IsoChronology.INSTANCE); + } + + @Test + public void factory_from_TemporalAccessor_chronology() { + assertEquals(Chronology.from(new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + throw new UnsupportedOperationException(); + } + @Override + public long getLong(TemporalField field) { + throw new UnsupportedOperationException(); + } + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.chronology()) { + return (R) IsoChronology.INSTANCE; + } + throw new UnsupportedOperationException(); + } + }), IsoChronology.INSTANCE); + } + + @Test + public void factory_from_TemporalAccessor_noChronology() { + assertEquals(Chronology.from(new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + throw new UnsupportedOperationException(); + } + + @Override + public long getLong(TemporalField field) { + throw new UnsupportedOperationException(); + } + + @Override + public R query(TemporalQuery query) { + if (query == Queries.chronology()) { + return null; + } + throw new UnsupportedOperationException(); + } + }), IsoChronology.INSTANCE); + } + + @Test(expectedExceptions=NullPointerException.class) + public void factory_from_TemporalAccessor_null() { + Chronology.from(null); + } + + //----------------------------------------------------------------------- + @Test + public void test_date_TemporalAccessor() { + assertEquals(IsoChronology.INSTANCE.date(new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + if (field == ChronoField.EPOCH_DAY) { + return true; + } + throw new UnsupportedOperationException(); + } + + @Override + public long getLong(TemporalField field) { + if (field == ChronoField.EPOCH_DAY) { + return LocalDate.of(2012, 6, 30).toEpochDay(); + } + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.localDate()) { + return (R) LocalDate.of(2012, 6, 30); + } + throw new UnsupportedOperationException(); + } + }), LocalDate.of(2012, 6, 30)); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_date_TemporalAccessor_null() { + IsoChronology.INSTANCE.date(null); + } + + //----------------------------------------------------------------------- + @Test + public void test_localDateTime_TemporalAccessor() { + assertEquals(IsoChronology.INSTANCE.localDateTime(new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + if (field == ChronoField.EPOCH_DAY || field == ChronoField.NANO_OF_DAY) { + return true; + } + throw new UnsupportedOperationException(); + } + + @Override + public long getLong(TemporalField field) { + if (field == ChronoField.EPOCH_DAY) { + return LocalDate.of(2012, 6, 30).toEpochDay(); + } + if (field == ChronoField.NANO_OF_DAY) { + return LocalTime.of(12, 30, 40).toNanoOfDay(); + } + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.localDate()) { + return (R) LocalDate.of(2012, 6, 30); + } + if (query == Queries.localTime()) { + return (R) LocalTime.of(12, 30, 40); + } + throw new UnsupportedOperationException(); + } + }), LocalDateTime.of(2012, 6, 30, 12, 30, 40)); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_localDateTime_TemporalAccessor_null() { + IsoChronology.INSTANCE.localDateTime(null); + } + + //----------------------------------------------------------------------- + @Test + public void test_zonedDateTime_TemporalAccessor() { + assertEquals(IsoChronology.INSTANCE.zonedDateTime(new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + if (field == ChronoField.EPOCH_DAY || field == ChronoField.NANO_OF_DAY || + field == ChronoField.INSTANT_SECONDS || field == ChronoField.NANO_OF_SECOND) { + return true; + } + throw new UnsupportedOperationException(); + } + + @Override + public long getLong(TemporalField field) { + if (field == ChronoField.INSTANT_SECONDS) { + return ZonedDateTime.of(2012, 6, 30, 12, 30, 40, 0, ZoneId.of("Europe/London")).toEpochSecond(); + } + if (field == ChronoField.NANO_OF_SECOND) { + return 0; + } + if (field == ChronoField.EPOCH_DAY) { + return LocalDate.of(2012, 6, 30).toEpochDay(); + } + if (field == ChronoField.NANO_OF_DAY) { + return LocalTime.of(12, 30, 40).toNanoOfDay(); + } + throw new UnsupportedOperationException(); + } + + @SuppressWarnings("unchecked") + @Override + public R query(TemporalQuery query) { + if (query == Queries.localDate()) { + return (R) LocalDate.of(2012, 6, 30); + } + if (query == Queries.localTime()) { + return (R) LocalTime.of(12, 30, 40); + } + if (query == Queries.zoneId() || query == Queries.zone()) { + return (R) ZoneId.of("Europe/London"); + } + throw new UnsupportedOperationException(); + } + }), ZonedDateTime.of(2012, 6, 30, 12, 30, 40, 0, ZoneId.of("Europe/London"))); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_zonedDateTime_TemporalAccessor_null() { + IsoChronology.INSTANCE.zonedDateTime(null); + } + +} diff --git a/jdk/test/java/time/tck/java/time/calendar/TestServiceLoader.java b/jdk/test/java/time/tck/java/time/chrono/TCKTestServiceLoader.java similarity index 73% rename from jdk/test/java/time/tck/java/time/calendar/TestServiceLoader.java rename to jdk/test/java/time/tck/java/time/chrono/TCKTestServiceLoader.java index b7381b77c84..0236656aad6 100644 --- a/jdk/test/java/time/tck/java/time/calendar/TestServiceLoader.java +++ b/jdk/test/java/time/tck/java/time/chrono/TCKTestServiceLoader.java @@ -56,51 +56,29 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.calendar; +package tck.java.time.chrono; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.fail; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.ServiceLoader; import java.time.LocalDate; -import java.time.temporal.Chrono; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.ISOChrono; -import java.time.DateTimeException; +import java.time.chrono.Chronology; +import java.time.chrono.ChronoLocalDate; -import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** * Tests that a custom Chronology is available via the ServiceLoader. - * The CopticChrono is configured via META-INF/services/java.time.temporal.Chrono. + * The CopticChronology is configured via META-INF/services/java.time.chrono.Chronology. */ @Test -public class TestServiceLoader { +public class TCKTestServiceLoader { @Test(groups={"tck"}) public void test_CopticServiceLoader() { - Chrono chrono = Chrono.of("Coptic"); - ChronoLocalDate copticDate = chrono.date(1729, 4, 27); + Chronology chrono = Chronology.of("Coptic"); + ChronoLocalDate copticDate = chrono.date(1729, 4, 27); LocalDate ld = LocalDate.from(copticDate); assertEquals(ld, LocalDate.of(2013, 1, 5), "CopticDate does not match LocalDate"); } - @Test(groups="implementation") - public void test_copticServiceLoader() { - Map chronos = new HashMap<>(); - ServiceLoader loader = ServiceLoader.load(Chrono.class, null); - for (Chrono chrono : loader) { - chronos.put(chrono.getId(), chrono); - } - assertNotNull(chronos.get("Coptic"), "CopticChrono not found"); - } - } diff --git a/jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDate.java b/jdk/test/java/time/tck/java/time/chrono/TestChronoLocalDate.java similarity index 84% rename from jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDate.java rename to jdk/test/java/time/tck/java/time/chrono/TestChronoLocalDate.java index 67175c0b06c..51674e27f90 100644 --- a/jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDate.java +++ b/jdk/test/java/time/tck/java/time/chrono/TestChronoLocalDate.java @@ -54,7 +54,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.calendar; +package tck.java.time.chrono; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -63,29 +63,25 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.List; - import java.time.Duration; import java.time.LocalDate; -import java.time.calendar.HijrahChrono; -import java.time.calendar.JapaneseChrono; -import java.time.calendar.MinguoChrono; -import java.time.calendar.ThaiBuddhistChrono; -import java.time.temporal.Chrono; -import java.time.temporal.ChronoLocalDate; +import java.time.chrono.HijrahChronology; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.MinguoChronology; +import java.time.chrono.ThaiBuddhistChronology; +import java.time.chrono.Chronology; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.IsoChronology; import java.time.temporal.ChronoUnit; -import java.time.temporal.SimplePeriod; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; -import java.time.format.DateTimeBuilder; -import java.time.temporal.TemporalAdder; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; -import java.time.temporal.TemporalSubtractor; -import java.time.temporal.ValueRange; import java.time.temporal.TemporalUnit; -import java.time.temporal.ISOChrono; +import java.time.temporal.ValueRange; +import java.util.ArrayList; +import java.util.List; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -101,21 +97,21 @@ public class TestChronoLocalDate { // regular data factory for names and descriptions of available calendars //----------------------------------------------------------------------- @DataProvider(name = "calendars") - Chrono[][] data_of_calendars() { - return new Chrono[][]{ - {HijrahChrono.INSTANCE}, - {ISOChrono.INSTANCE}, - {JapaneseChrono.INSTANCE}, - {MinguoChrono.INSTANCE}, - {ThaiBuddhistChrono.INSTANCE}}; + Chronology[][] data_of_calendars() { + return new Chronology[][]{ + {HijrahChronology.INSTANCE}, + {IsoChronology.INSTANCE}, + {JapaneseChronology.INSTANCE}, + {MinguoChronology.INSTANCE}, + {ThaiBuddhistChronology.INSTANCE}}; } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badWithAdjusterChrono(Chrono chrono) { + public void test_badWithAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDate date = chrono.date(refDate); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDate date2 = chrono2.date(refDate); TemporalAdjuster adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { @@ -134,13 +130,13 @@ public class TestChronoLocalDate { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badPlusAdjusterChrono(Chrono chrono) { + public void test_badPlusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDate date = chrono.date(refDate); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDate date2 = chrono2.date(refDate); - TemporalAdder adjuster = new FixedAdjuster(date2); + TemporalAmount adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { date.plus(adjuster); @@ -157,13 +153,13 @@ public class TestChronoLocalDate { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badMinusAdjusterChrono(Chrono chrono) { + public void test_badMinusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDate date = chrono.date(refDate); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDate date2 = chrono2.date(refDate); - TemporalSubtractor adjuster = new FixedAdjuster(date2); + TemporalAmount adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { date.minus(adjuster); @@ -180,11 +176,11 @@ public class TestChronoLocalDate { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badPlusTemporalUnitChrono(Chrono chrono) { + public void test_badPlusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDate date = chrono.date(refDate); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDate date2 = chrono2.date(refDate); TemporalUnit adjuster = new FixedTemporalUnit(date2); if (chrono != chrono2) { @@ -204,11 +200,11 @@ public class TestChronoLocalDate { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badMinusTemporalUnitChrono(Chrono chrono) { + public void test_badMinusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDate date = chrono.date(refDate); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDate date2 = chrono2.date(refDate); TemporalUnit adjuster = new FixedTemporalUnit(date2); if (chrono != chrono2) { @@ -228,11 +224,11 @@ public class TestChronoLocalDate { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badTemporalFieldChrono(Chrono chrono) { + public void test_badTemporalFieldChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDate date = chrono.date(refDate); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDate date2 = chrono2.date(refDate); TemporalField adjuster = new FixedTemporalField(date2); if (chrono != chrono2) { @@ -255,8 +251,8 @@ public class TestChronoLocalDate { // isBefore, isAfter, isEqual, DATE_COMPARATOR //----------------------------------------------------------------------- @Test(groups={"tck"}, dataProvider="calendars") - public void test_date_comparisons(Chrono chrono) { - List> dates = new ArrayList<>(); + public void test_date_comparisons(Chronology chrono) { + List dates = new ArrayList<>(); ChronoLocalDate date = chrono.date(LocalDate.of(1900, 1, 1)); @@ -278,9 +274,9 @@ public class TestChronoLocalDate { dates.add(date.plus(1000, ChronoUnit.YEARS)); // Check these dates against the corresponding dates for every calendar - for (Chrono[] clist : data_of_calendars()) { + for (Chronology[] clist : data_of_calendars()) { List> otherDates = new ArrayList<>(); - Chrono chrono2 = clist[0]; + Chronology chrono2 = clist[0]; for (ChronoLocalDate d : dates) { otherDates.add(chrono2.date(d)); } @@ -316,9 +312,9 @@ public class TestChronoLocalDate { // Test Serialization of Calendars //----------------------------------------------------------------------- @Test( groups={"tck"}, dataProvider="calendars") - public > void test_ChronoSerialization(C chrono) throws Exception { + public void test_ChronoSerialization(Chronology chrono) throws Exception { LocalDate ref = LocalDate.of(1900, 1, 5); - ChronoLocalDate orginal = chrono.date(ref); + ChronoLocalDate orginal = chrono.date(ref); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(baos); out.writeObject(orginal); @@ -326,7 +322,7 @@ public class TestChronoLocalDate { ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bais); @SuppressWarnings("unchecked") - ChronoLocalDate ser = (ChronoLocalDate) in.readObject(); + ChronoLocalDate ser = (ChronoLocalDate) in.readObject(); assertEquals(ser, orginal, "deserialized date is wrong"); } @@ -334,7 +330,7 @@ public class TestChronoLocalDate { * FixedAdjusted returns a fixed Temporal in all adjustments. * Construct an adjuster with the Temporal that should be returned from adjust. */ - static class FixedAdjuster implements TemporalAdjuster, TemporalAdder, TemporalSubtractor { + static class FixedAdjuster implements TemporalAdjuster, TemporalAmount { private Temporal datetime; FixedAdjuster(Temporal datetime) { @@ -356,6 +352,15 @@ public class TestChronoLocalDate { return datetime; } + @Override + public long get(TemporalUnit unit) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getUnits() { + throw new UnsupportedOperationException("Not supported yet."); + } } /** @@ -385,18 +390,18 @@ public class TestChronoLocalDate { } @Override - public boolean isSupported(Temporal temporal) { + public boolean isSupportedBy(Temporal temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override - public R doPlus(R dateTime, long periodToAdd) { + public R addTo(R temporal, long amount) { return (R) this.temporal; } @Override - public SimplePeriod between(R dateTime1, R dateTime2) { + public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException("Not supported yet."); } } @@ -432,30 +437,24 @@ public class TestChronoLocalDate { } @Override - public boolean doIsSupported(TemporalAccessor temporal) { + public boolean isSupportedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public ValueRange doRange(TemporalAccessor temporal) { + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public long doGet(TemporalAccessor temporal) { + public long getFrom(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override - public R doWith(R temporal, long newValue) { + public R adjustInto(R temporal, long newValue) { return (R) this.temporal; } - - @Override - public boolean resolve(DateTimeBuilder builder, long value) { - throw new UnsupportedOperationException("Not supported yet."); - } - } } diff --git a/jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDateTime.java b/jdk/test/java/time/tck/java/time/chrono/TestChronoLocalDateTime.java similarity index 85% rename from jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDateTime.java rename to jdk/test/java/time/tck/java/time/chrono/TestChronoLocalDateTime.java index e514fb82e02..fd72237b8b7 100644 --- a/jdk/test/java/time/tck/java/time/calendar/TestChronoLocalDateTime.java +++ b/jdk/test/java/time/tck/java/time/chrono/TestChronoLocalDateTime.java @@ -54,7 +54,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.calendar; +package tck.java.time.chrono; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -63,31 +63,28 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.List; - import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.time.calendar.HijrahChrono; -import java.time.calendar.JapaneseChrono; -import java.time.calendar.MinguoChrono; -import java.time.calendar.ThaiBuddhistChrono; -import java.time.temporal.Chrono; -import java.time.temporal.ChronoLocalDateTime; +import java.time.chrono.HijrahChronology; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.MinguoChronology; +import java.time.chrono.ThaiBuddhistChronology; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; import java.time.temporal.ChronoUnit; -import java.time.temporal.SimplePeriod; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; -import java.time.format.DateTimeBuilder; -import java.time.temporal.TemporalAdder; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; -import java.time.temporal.TemporalSubtractor; -import java.time.temporal.ValueRange; -import java.time.temporal.ISOChrono; import java.time.temporal.TemporalUnit; +import java.time.temporal.ValueRange; +import java.util.ArrayList; +import java.util.List; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -102,21 +99,21 @@ public class TestChronoLocalDateTime { // regular data factory for names and descriptions of available calendars //----------------------------------------------------------------------- @DataProvider(name = "calendars") - Chrono[][] data_of_calendars() { - return new Chrono[][]{ - {HijrahChrono.INSTANCE}, - {ISOChrono.INSTANCE}, - {JapaneseChrono.INSTANCE}, - {MinguoChrono.INSTANCE}, - {ThaiBuddhistChrono.INSTANCE}}; + Chronology[][] data_of_calendars() { + return new Chronology[][]{ + {HijrahChronology.INSTANCE}, + {IsoChronology.INSTANCE}, + {JapaneseChronology.INSTANCE}, + {MinguoChronology.INSTANCE}, + {ThaiBuddhistChronology.INSTANCE}}; } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badWithAdjusterChrono(Chrono chrono) { + public void test_badWithAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); TemporalAdjuster adjuster = new FixedAdjuster(cdt2); if (chrono != chrono2) { @@ -136,13 +133,13 @@ public class TestChronoLocalDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badPlusAdjusterChrono(Chrono chrono) { + public void test_badPlusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); - TemporalAdder adjuster = new FixedAdjuster(cdt2); + TemporalAmount adjuster = new FixedAdjuster(cdt2); if (chrono != chrono2) { try { ChronoLocalDateTime notreached = cdt.plus(adjuster); @@ -160,13 +157,13 @@ public class TestChronoLocalDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badMinusAdjusterChrono(Chrono chrono) { + public void test_badMinusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); - TemporalSubtractor adjuster = new FixedAdjuster(cdt2); + TemporalAmount adjuster = new FixedAdjuster(cdt2); if (chrono != chrono2) { try { ChronoLocalDateTime notreached = cdt.minus(adjuster); @@ -184,11 +181,11 @@ public class TestChronoLocalDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badPlusTemporalUnitChrono(Chrono chrono) { + public void test_badPlusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); TemporalUnit adjuster = new FixedTemporalUnit(cdt2); if (chrono != chrono2) { @@ -208,11 +205,11 @@ public class TestChronoLocalDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badMinusTemporalUnitChrono(Chrono chrono) { + public void test_badMinusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); TemporalUnit adjuster = new FixedTemporalUnit(cdt2); if (chrono != chrono2) { @@ -232,11 +229,11 @@ public class TestChronoLocalDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badTemporalFieldChrono(Chrono chrono) { + public void test_badTemporalFieldChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); TemporalField adjuster = new FixedTemporalField(cdt2); if (chrono != chrono2) { @@ -259,7 +256,7 @@ public class TestChronoLocalDateTime { // isBefore, isAfter, isEqual //----------------------------------------------------------------------- @Test(groups={"tck"}, dataProvider="calendars") - public void test_datetime_comparisons(Chrono chrono) { + public void test_datetime_comparisons(Chronology chrono) { List> dates = new ArrayList<>(); ChronoLocalDateTime date = chrono.date(LocalDate.of(1900, 1, 1)).atTime(LocalTime.MIN); @@ -286,11 +283,11 @@ public class TestChronoLocalDateTime { dates.add(date.plus(100, ChronoUnit.YEARS)); // Check these dates against the corresponding dates for every calendar - for (Chrono[] clist : data_of_calendars()) { + for (Chronology[] clist : data_of_calendars()) { List> otherDates = new ArrayList<>(); - Chrono chrono2 = clist[0]; + Chronology chrono2 = clist[0]; for (ChronoLocalDateTime d : dates) { - otherDates.add(chrono2.date(d).atTime(d.getTime())); + otherDates.add(chrono2.date(d).atTime(d.toLocalTime())); } // Now compare the sequence of original dates with the sequence of converted dates @@ -324,16 +321,16 @@ public class TestChronoLocalDateTime { // Test Serialization of ISO via chrono API //----------------------------------------------------------------------- @Test( groups={"tck"}, dataProvider="calendars") - public > void test_ChronoLocalDateTimeSerialization(C chrono) throws Exception { + public void test_ChronoLocalDateTimeSerialization(Chronology chrono) throws Exception { LocalDateTime ref = LocalDate.of(2000, 1, 5).atTime(12, 1, 2, 3); - ChronoLocalDateTime orginal = chrono.date(ref).atTime(ref.getTime()); + ChronoLocalDateTime orginal = chrono.date(ref).atTime(ref.toLocalTime()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(baos); out.writeObject(orginal); out.close(); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bais); - ChronoLocalDateTime ser = (ChronoLocalDateTime) in.readObject(); + ChronoLocalDateTime ser = (ChronoLocalDateTime) in.readObject(); assertEquals(ser, orginal, "deserialized date is wrong"); } @@ -342,7 +339,7 @@ public class TestChronoLocalDateTime { * FixedAdjusted returns a fixed Temporal in all adjustments. * Construct an adjuster with the Temporal that should be returned from adjust. */ - static class FixedAdjuster implements TemporalAdjuster, TemporalAdder, TemporalSubtractor { + static class FixedAdjuster implements TemporalAdjuster, TemporalAmount { private Temporal datetime; FixedAdjuster(Temporal datetime) { @@ -364,6 +361,16 @@ public class TestChronoLocalDateTime { return datetime; } + @Override + public long get(TemporalUnit unit) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getUnits() { + throw new UnsupportedOperationException("Not supported yet."); + } + } /** @@ -393,18 +400,18 @@ public class TestChronoLocalDateTime { } @Override - public boolean isSupported(Temporal temporal) { + public boolean isSupportedBy(Temporal temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override - public R doPlus(R dateTime, long periodToAdd) { + public R addTo(R temporal, long amount) { return (R) this.temporal; } @Override - public SimplePeriod between(R dateTime1, R dateTime2) { + public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException("Not supported yet."); } } @@ -440,30 +447,24 @@ public class TestChronoLocalDateTime { } @Override - public boolean doIsSupported(TemporalAccessor temporal) { + public boolean isSupportedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public ValueRange doRange(TemporalAccessor temporal) { + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public long doGet(TemporalAccessor temporal) { + public long getFrom(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override - public R doWith(R temporal, long newValue) { + public R adjustInto(R temporal, long newValue) { return (R) this.temporal; } - - @Override - public boolean resolve(DateTimeBuilder builder, long value) { - throw new UnsupportedOperationException("Not supported yet."); - } - } } diff --git a/jdk/test/java/time/tck/java/time/calendar/TestHijrahChrono.java b/jdk/test/java/time/tck/java/time/chrono/TestHijrahChronology.java similarity index 71% rename from jdk/test/java/time/tck/java/time/calendar/TestHijrahChrono.java rename to jdk/test/java/time/tck/java/time/chrono/TestHijrahChronology.java index 3157e822f09..1938c5e9849 100644 --- a/jdk/test/java/time/tck/java/time/calendar/TestHijrahChrono.java +++ b/jdk/test/java/time/tck/java/time/chrono/TestHijrahChronology.java @@ -54,7 +54,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.calendar; +package tck.java.time.chrono; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; @@ -64,11 +64,12 @@ import java.time.DateTimeException; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Month; -import java.time.calendar.HijrahChrono; -import java.time.temporal.ChronoLocalDate; +import java.time.chrono.HijrahChronology; +import java.time.chrono.HijrahDate; +import java.time.chrono.ChronoLocalDate; import java.time.temporal.Adjusters; -import java.time.temporal.Chrono; -import java.time.temporal.ISOChrono; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -78,15 +79,15 @@ import org.testng.annotations.Test; * Test. */ @Test -public class TestHijrahChrono { +public class TestHijrahChronology { //----------------------------------------------------------------------- - // Chrono.ofName("Hijrah") Lookup by name + // Chronology.ofName("Hijrah") Lookup by name //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_chrono_byName() { - Chrono c = HijrahChrono.INSTANCE; - Chrono test = Chrono.of("Hijrah"); + Chronology c = HijrahChronology.INSTANCE; + Chronology test = Chronology.of("Hijrah"); Assert.assertNotNull(test, "The Hijrah calendar could not be found byName"); Assert.assertEquals(test.getId(), "Hijrah", "ID mismatch"); Assert.assertEquals(test.getCalendarType(), "islamicc", "Type mismatch"); @@ -99,20 +100,20 @@ public class TestHijrahChrono { @DataProvider(name="samples") Object[][] data_samples() { return new Object[][] { - {HijrahChrono.INSTANCE.date(1, 1, 1), LocalDate.of(622, 7, 19)}, - {HijrahChrono.INSTANCE.date(1, 1, 2), LocalDate.of(622, 7, 20)}, - {HijrahChrono.INSTANCE.date(1, 1, 3), LocalDate.of(622, 7, 21)}, + {HijrahChronology.INSTANCE.date(1, 1, 1), LocalDate.of(622, 7, 19)}, + {HijrahChronology.INSTANCE.date(1, 1, 2), LocalDate.of(622, 7, 20)}, + {HijrahChronology.INSTANCE.date(1, 1, 3), LocalDate.of(622, 7, 21)}, - {HijrahChrono.INSTANCE.date(2, 1, 1), LocalDate.of(623, 7, 8)}, - {HijrahChrono.INSTANCE.date(3, 1, 1), LocalDate.of(624, 6, 27)}, - {HijrahChrono.INSTANCE.date(3, 12, 6), LocalDate.of(625, 5, 23)}, - {HijrahChrono.INSTANCE.date(4, 1, 1), LocalDate.of(625, 6, 16)}, - {HijrahChrono.INSTANCE.date(4, 7, 3), LocalDate.of(625, 12, 12)}, - {HijrahChrono.INSTANCE.date(4, 7, 4), LocalDate.of(625, 12, 13)}, - {HijrahChrono.INSTANCE.date(5, 1, 1), LocalDate.of(626, 6, 5)}, - {HijrahChrono.INSTANCE.date(1662, 3, 3), LocalDate.of(2234, 4, 3)}, - {HijrahChrono.INSTANCE.date(1728, 10, 28), LocalDate.of(2298, 12, 03)}, - {HijrahChrono.INSTANCE.date(1728, 10, 29), LocalDate.of(2298, 12, 04)}, + {HijrahChronology.INSTANCE.date(2, 1, 1), LocalDate.of(623, 7, 8)}, + {HijrahChronology.INSTANCE.date(3, 1, 1), LocalDate.of(624, 6, 27)}, + {HijrahChronology.INSTANCE.date(3, 12, 6), LocalDate.of(625, 5, 23)}, + {HijrahChronology.INSTANCE.date(4, 1, 1), LocalDate.of(625, 6, 16)}, + {HijrahChronology.INSTANCE.date(4, 7, 3), LocalDate.of(625, 12, 12)}, + {HijrahChronology.INSTANCE.date(4, 7, 4), LocalDate.of(625, 12, 13)}, + {HijrahChronology.INSTANCE.date(5, 1, 1), LocalDate.of(626, 6, 5)}, + {HijrahChronology.INSTANCE.date(1662, 3, 3), LocalDate.of(2234, 4, 3)}, + {HijrahChronology.INSTANCE.date(1728, 10, 28), LocalDate.of(2298, 12, 03)}, + {HijrahChronology.INSTANCE.date(1728, 10, 29), LocalDate.of(2298, 12, 04)}, }; } @@ -123,7 +124,7 @@ public class TestHijrahChrono { @Test(dataProvider="samples", groups={"tck"}) public void test_fromCalendrical(ChronoLocalDate hijrahDate, LocalDate iso) { - assertEquals(HijrahChrono.INSTANCE.date(iso), hijrahDate); + assertEquals(HijrahChronology.INSTANCE.date(iso), hijrahDate); } @DataProvider(name="badDates") @@ -148,7 +149,7 @@ public class TestHijrahChrono { @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class) public void test_badDates(int year, int month, int dom) { - HijrahChrono.INSTANCE.date(year, month, dom); + HijrahChronology.INSTANCE.date(year, month, dom); } //----------------------------------------------------------------------- @@ -156,16 +157,16 @@ public class TestHijrahChrono { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_adjust1() { - ChronoLocalDate base = HijrahChrono.INSTANCE.date(1728, 10, 28); + ChronoLocalDate base = HijrahChronology.INSTANCE.date(1728, 10, 28); ChronoLocalDate test = base.with(Adjusters.lastDayOfMonth()); - assertEquals(test, HijrahChrono.INSTANCE.date(1728, 10, 29)); + assertEquals(test, HijrahChronology.INSTANCE.date(1728, 10, 29)); } @Test(groups={"tck"}) public void test_adjust2() { - ChronoLocalDate base = HijrahChrono.INSTANCE.date(1728, 12, 2); + ChronoLocalDate base = HijrahChronology.INSTANCE.date(1728, 12, 2); ChronoLocalDate test = base.with(Adjusters.lastDayOfMonth()); - assertEquals(test, HijrahChrono.INSTANCE.date(1728, 12, 30)); + assertEquals(test, HijrahChronology.INSTANCE.date(1728, 12, 30)); } //----------------------------------------------------------------------- @@ -173,14 +174,14 @@ public class TestHijrahChrono { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_adjust_toLocalDate() { - ChronoLocalDate hijrahDate = HijrahChrono.INSTANCE.date(1726, 1, 4); + ChronoLocalDate hijrahDate = HijrahChronology.INSTANCE.date(1726, 1, 4); ChronoLocalDate test = hijrahDate.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, HijrahChrono.INSTANCE.date(1433, 8, 16)); + assertEquals(test, HijrahChronology.INSTANCE.date(1433, 8, 16)); } @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) public void test_adjust_toMonth() { - ChronoLocalDate hijrahDate = HijrahChrono.INSTANCE.date(1726, 1, 4); + ChronoLocalDate hijrahDate = HijrahChronology.INSTANCE.date(1726, 1, 4); hijrahDate.with(Month.APRIL); } @@ -189,14 +190,14 @@ public class TestHijrahChrono { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_LocalDate_adjustToHijrahDate() { - ChronoLocalDate hijrahDate = HijrahChrono.INSTANCE.date(1728, 10, 29); + ChronoLocalDate hijrahDate = HijrahChronology.INSTANCE.date(1728, 10, 29); LocalDate test = LocalDate.MIN.with(hijrahDate); assertEquals(test, LocalDate.of(2298, 12, 4)); } @Test(groups={"tck"}) public void test_LocalDateTime_adjustToHijrahDate() { - ChronoLocalDate hijrahDate = HijrahChrono.INSTANCE.date(1728, 10, 29); + ChronoLocalDate hijrahDate = HijrahChronology.INSTANCE.date(1728, 10, 29); LocalDateTime test = LocalDateTime.MIN.with(hijrahDate); assertEquals(test, LocalDateTime.of(2298, 12, 4, 0, 0)); } @@ -207,11 +208,11 @@ public class TestHijrahChrono { @DataProvider(name="toString") Object[][] data_toString() { return new Object[][] { - {HijrahChrono.INSTANCE.date(1, 1, 1), "Hijrah AH 1-01-01"}, - {HijrahChrono.INSTANCE.date(1728, 10, 28), "Hijrah AH 1728-10-28"}, - {HijrahChrono.INSTANCE.date(1728, 10, 29), "Hijrah AH 1728-10-29"}, - {HijrahChrono.INSTANCE.date(1727, 12, 5), "Hijrah AH 1727-12-05"}, - {HijrahChrono.INSTANCE.date(1727, 12, 6), "Hijrah AH 1727-12-06"}, + {HijrahChronology.INSTANCE.date(1, 1, 1), "Hijrah AH 1-01-01"}, + {HijrahChronology.INSTANCE.date(1728, 10, 28), "Hijrah AH 1728-10-28"}, + {HijrahChronology.INSTANCE.date(1728, 10, 29), "Hijrah AH 1728-10-29"}, + {HijrahChronology.INSTANCE.date(1727, 12, 5), "Hijrah AH 1727-12-05"}, + {HijrahChronology.INSTANCE.date(1727, 12, 6), "Hijrah AH 1727-12-06"}, }; } @@ -225,12 +226,12 @@ public class TestHijrahChrono { //----------------------------------------------------------------------- @Test(groups="tck") public void test_equals_true() { - assertTrue(HijrahChrono.INSTANCE.equals(HijrahChrono.INSTANCE)); + assertTrue(HijrahChronology.INSTANCE.equals(HijrahChronology.INSTANCE)); } @Test(groups="tck") public void test_equals_false() { - assertFalse(HijrahChrono.INSTANCE.equals(ISOChrono.INSTANCE)); + assertFalse(HijrahChronology.INSTANCE.equals(IsoChronology.INSTANCE)); } } diff --git a/jdk/test/java/time/tck/java/time/chrono/TestJapaneseChronology.java b/jdk/test/java/time/tck/java/time/chrono/TestJapaneseChronology.java new file mode 100644 index 00000000000..b3027dfb6f6 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/chrono/TestJapaneseChronology.java @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2012, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.chrono; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import java.util.List; + +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.Month; +import java.time.Year; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.JapaneseDate; +import java.time.chrono.Chronology; +import java.time.chrono.Era; +import java.time.chrono.IsoChronology; +import java.time.temporal.Adjusters; +import java.util.Locale; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TestJapaneseChronology { + private static int YDIFF_HEISEI = 1988; + private static int YDIFF_MEIJI = 1867; + private static int YDIFF_SHOWA = 1925; + private static int YDIFF_TAISHO = 1911; + + //----------------------------------------------------------------------- + // Chronology.of(String) + //----------------------------------------------------------------------- + @Test + public void test_chrono_byName() { + Chronology c = JapaneseChronology.INSTANCE; + Chronology test = Chronology.of("Japanese"); + Assert.assertNotNull(test, "The Japanese calendar could not be found byName"); + Assert.assertEquals(test.getId(), "Japanese", "ID mismatch"); + Assert.assertEquals(test.getCalendarType(), "japanese", "Type mismatch"); + Assert.assertEquals(test, c); + } + + //----------------------------------------------------------------------- + // Chronology.ofLocale(Locale) + //----------------------------------------------------------------------- + @Test + public void test_chrono_byLocale_fullTag_japaneseCalendarFromJapan() { + Chronology test = Chronology.ofLocale(Locale.forLanguageTag("ja-JP-u-ca-japanese")); + Assert.assertEquals(test.getId(), "Japanese"); + Assert.assertEquals(test, JapaneseChronology.INSTANCE); + } + + @Test + public void test_chrono_byLocale_fullTag_japaneseCalendarFromElsewhere() { + Chronology test = Chronology.ofLocale(Locale.forLanguageTag("en-US-u-ca-japanese")); + Assert.assertEquals(test.getId(), "Japanese"); + Assert.assertEquals(test, JapaneseChronology.INSTANCE); + } + + @Test + public void test_chrono_byLocale_oldJP_noVariant() { + Chronology test = Chronology.ofLocale(new Locale("ja", "JP")); + Assert.assertEquals(test.getId(), "ISO"); + Assert.assertEquals(test, IsoChronology.INSTANCE); + } + + @Test + public void test_chrono_byLocale_oldJP_variant() { + Chronology test = Chronology.ofLocale(new Locale("ja", "JP", "JP")); + Assert.assertEquals(test.getId(), "Japanese"); + Assert.assertEquals(test, JapaneseChronology.INSTANCE); + } + + @Test + public void test_chrono_byLocale_iso() { + Assert.assertEquals(Chronology.ofLocale(new Locale("ja", "JP")).getId(), "ISO"); + Assert.assertEquals(Chronology.ofLocale(Locale.forLanguageTag("ja-JP")).getId(), "ISO"); + Assert.assertEquals(Chronology.ofLocale(Locale.forLanguageTag("ja-JP-JP")).getId(), "ISO"); + } + + //----------------------------------------------------------------------- + // creation, toLocalDate() + //----------------------------------------------------------------------- + @DataProvider(name="samples") + Object[][] data_samples() { + return new Object[][] { + {JapaneseChronology.INSTANCE.date(1, 1, 1), LocalDate.of(1, 1, 1)}, + {JapaneseChronology.INSTANCE.date(1, 1, 2), LocalDate.of(1, 1, 2)}, + {JapaneseChronology.INSTANCE.date(1, 1, 3), LocalDate.of(1, 1, 3)}, + + {JapaneseChronology.INSTANCE.date(2, 1, 1), LocalDate.of(2, 1, 1)}, + {JapaneseChronology.INSTANCE.date(3, 1, 1), LocalDate.of(3, 1, 1)}, + {JapaneseChronology.INSTANCE.date(3, 12, 6), LocalDate.of(3, 12, 6)}, + {JapaneseChronology.INSTANCE.date(4, 1, 1), LocalDate.of(4, 1, 1)}, + {JapaneseChronology.INSTANCE.date(4, 7, 3), LocalDate.of(4, 7, 3)}, + {JapaneseChronology.INSTANCE.date(4, 7, 4), LocalDate.of(4, 7, 4)}, + {JapaneseChronology.INSTANCE.date(5, 1, 1), LocalDate.of(5, 1, 1)}, + {JapaneseChronology.INSTANCE.date(1662, 3, 3), LocalDate.of(1662, 3, 3)}, + {JapaneseChronology.INSTANCE.date(1728, 10, 28), LocalDate.of(1728, 10, 28)}, + {JapaneseChronology.INSTANCE.date(1728, 10, 29), LocalDate.of(1728, 10, 29)}, + + {JapaneseChronology.INSTANCE.date(JapaneseChronology.ERA_HEISEI, 1996 - YDIFF_HEISEI, 2, 29), LocalDate.of(1996, 2, 29)}, + {JapaneseChronology.INSTANCE.date(JapaneseChronology.ERA_HEISEI, 2000 - YDIFF_HEISEI, 2, 29), LocalDate.of(2000, 2, 29)}, + {JapaneseChronology.INSTANCE.date(JapaneseChronology.ERA_MEIJI, 1868 - YDIFF_MEIJI, 2, 29), LocalDate.of(1868, 2, 29)}, + {JapaneseChronology.INSTANCE.date(JapaneseChronology.ERA_SHOWA, 1928 - YDIFF_SHOWA, 2, 29), LocalDate.of(1928, 2, 29)}, + {JapaneseChronology.INSTANCE.date(JapaneseChronology.ERA_TAISHO, 1912 - YDIFF_TAISHO, 2, 29), LocalDate.of(1912, 2, 29)}, + + {JapaneseChronology.INSTANCE.dateYearDay(1996, 60), LocalDate.of(1996, 2, 29)}, + {JapaneseChronology.INSTANCE.dateYearDay(1868, 60), LocalDate.of(1868, 2, 29)}, + {JapaneseChronology.INSTANCE.dateYearDay(1928, 60), LocalDate.of(1928, 2, 29)}, + {JapaneseChronology.INSTANCE.dateYearDay(1912, 60), LocalDate.of(1912, 2, 29)}, + }; + } + + @Test(dataProvider="samples", groups={"tck"}) + public void test_toLocalDate(JapaneseDate jdate, LocalDate iso) { + assertEquals(LocalDate.from(jdate), iso); + } + + @Test(dataProvider="samples", groups={"tck"}) + public void test_fromCalendrical(JapaneseDate jdate, LocalDate iso) { + assertEquals(JapaneseChronology.INSTANCE.date(iso), jdate); + } + + @DataProvider(name="badDates") + Object[][] data_badDates() { + return new Object[][] { + {1728, 0, 0}, + + {1728, -1, 1}, + {1728, 0, 1}, + {1728, 14, 1}, + {1728, 15, 1}, + + {1728, 1, -1}, + {1728, 1, 0}, + {1728, 1, 32}, + + {1728, 12, -1}, + {1728, 12, 0}, + {1728, 12, 32}, + + {1725, 2, 29}, + {500, 2, 29}, + {2100, 2, 29}, + }; + } + + @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_badDates(int year, int month, int dom) { + JapaneseChronology.INSTANCE.date(year, month, dom); + } + + //----------------------------------------------------------------------- + // prolepticYear() and is LeapYear() + //----------------------------------------------------------------------- + @DataProvider(name="prolepticYear") + Object[][] data_prolepticYear() { + return new Object[][] { + {2, JapaneseChronology.ERA_HEISEI, 1, 1 + YDIFF_HEISEI, false}, + {2, JapaneseChronology.ERA_HEISEI, 100, 100 + YDIFF_HEISEI, true}, + {2, JapaneseChronology.ERA_HEISEI, 0, YDIFF_HEISEI, true}, + {2, JapaneseChronology.ERA_HEISEI, -10, -10 + YDIFF_HEISEI, false}, + + {-1, JapaneseChronology.ERA_MEIJI, 1, 1 + YDIFF_MEIJI, true}, + {-1, JapaneseChronology.ERA_MEIJI, 100, 100 + YDIFF_MEIJI, false}, + {-1, JapaneseChronology.ERA_MEIJI, 0, YDIFF_MEIJI, false}, + {-1, JapaneseChronology.ERA_MEIJI, -10, -10 + YDIFF_MEIJI, false}, + + {1, JapaneseChronology.ERA_SHOWA, 1, 1 + YDIFF_SHOWA, false}, + {1, JapaneseChronology.ERA_SHOWA, 100, 100 + YDIFF_SHOWA, false}, + {1, JapaneseChronology.ERA_SHOWA, 0, YDIFF_SHOWA, false}, + {1, JapaneseChronology.ERA_SHOWA, -5, -5 + YDIFF_SHOWA, true}, + + {0, JapaneseChronology.ERA_TAISHO, 1, 1 + YDIFF_TAISHO, true}, + {0, JapaneseChronology.ERA_TAISHO, 100, 100 + YDIFF_TAISHO, false}, + {0, JapaneseChronology.ERA_TAISHO, 0, YDIFF_TAISHO, false}, + {0, JapaneseChronology.ERA_TAISHO, -10, -10 + YDIFF_TAISHO, false}, + + }; + } + + @Test(dataProvider="prolepticYear", groups={"tck"}) + public void test_prolepticYear(int eraValue, Era era, int yearOfEra, int expectedProlepticYear, boolean isLeapYear) { + Era eraObj = JapaneseChronology.INSTANCE.eraOf(eraValue) ; + assertTrue(JapaneseChronology.INSTANCE.eras().contains(eraObj)); + assertEquals(eraObj, era); + assertEquals(JapaneseChronology.INSTANCE.prolepticYear(era, yearOfEra), expectedProlepticYear); + assertEquals(JapaneseChronology.INSTANCE.isLeapYear(expectedProlepticYear), isLeapYear) ; + assertEquals(JapaneseChronology.INSTANCE.isLeapYear(expectedProlepticYear), Year.of(expectedProlepticYear).isLeap()) ; + } + + //----------------------------------------------------------------------- + // with(WithAdjuster) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_adjust1() { + JapaneseDate base = JapaneseChronology.INSTANCE.date(1728, 10, 29); + JapaneseDate test = base.with(Adjusters.lastDayOfMonth()); + assertEquals(test, JapaneseChronology.INSTANCE.date(1728, 10, 31)); + } + + @Test(groups={"tck"}) + public void test_adjust2() { + JapaneseDate base = JapaneseChronology.INSTANCE.date(1728, 12, 2); + JapaneseDate test = base.with(Adjusters.lastDayOfMonth()); + assertEquals(test, JapaneseChronology.INSTANCE.date(1728, 12, 31)); + } + + //----------------------------------------------------------------------- + // JapaneseDate.with(Local*) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_adjust_toLocalDate() { + JapaneseDate jdate = JapaneseChronology.INSTANCE.date(1726, 1, 4); + JapaneseDate test = jdate.with(LocalDate.of(2012, 7, 6)); + assertEquals(test, JapaneseChronology.INSTANCE.date(2012, 7, 6)); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_adjust_toMonth() { + JapaneseDate jdate = JapaneseChronology.INSTANCE.date(1726, 1, 4); + jdate.with(Month.APRIL); + } + + //----------------------------------------------------------------------- + // LocalDate.with(JapaneseDate) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_LocalDate_adjustToJapaneseDate() { + JapaneseDate jdate = JapaneseChronology.INSTANCE.date(1728, 10, 29); + LocalDate test = LocalDate.MIN.with(jdate); + assertEquals(test, LocalDate.of(1728, 10, 29)); + } + + @Test(groups={"tck"}) + public void test_LocalDateTime_adjustToJapaneseDate() { + JapaneseDate jdate = JapaneseChronology.INSTANCE.date(1728, 10, 29); + LocalDateTime test = LocalDateTime.MIN.with(jdate); + assertEquals(test, LocalDateTime.of(1728, 10, 29, 0, 0)); + } + + //----------------------------------------------------------------------- + // Check Japanese Eras + //----------------------------------------------------------------------- + @DataProvider(name="japaneseEras") + Object[][] data_japanseseEras() { + return new Object[][] { + { JapaneseChronology.ERA_SEIREKI, -999, "Seireki"}, + { JapaneseChronology.ERA_MEIJI, -1, "Meiji"}, + { JapaneseChronology.ERA_TAISHO, 0, "Taisho"}, + { JapaneseChronology.ERA_SHOWA, 1, "Showa"}, + { JapaneseChronology.ERA_HEISEI, 2, "Heisei"}, + }; + } + + @Test(groups={"tck"}, dataProvider="japaneseEras") + public void test_Japanese_Eras(Era era, int eraValue, String name) { + assertEquals(era.getValue(), eraValue, "EraValue"); + assertEquals(era.toString(), name, "Era Name"); + assertEquals(era, JapaneseChronology.INSTANCE.eraOf(eraValue), "JapaneseChronology.eraOf()"); + List eras = JapaneseChronology.INSTANCE.eras(); + assertTrue(eras.contains(era), "Era is not present in JapaneseChronology.INSTANCE.eras()"); + } + + @Test(groups="tck") + public void test_Japanese_badEras() { + int badEras[] = {-1000, -998, -997, -2, 3, 4, 1000}; + for (int badEra : badEras) { + try { + Era era = JapaneseChronology.INSTANCE.eraOf(badEra); + fail("JapaneseChronology.eraOf returned " + era + " + for invalid eraValue " + badEra); + } catch (DateTimeException ex) { + // ignore expected exception + } + } + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="toString") + Object[][] data_toString() { + return new Object[][] { + {JapaneseChronology.INSTANCE.date(0001, 1, 1), "Japanese 0001-01-01"}, + {JapaneseChronology.INSTANCE.date(1728, 10, 28), "Japanese 1728-10-28"}, + {JapaneseChronology.INSTANCE.date(1728, 10, 29), "Japanese 1728-10-29"}, + {JapaneseChronology.INSTANCE.date(1727, 12, 5), "Japanese 1727-12-05"}, + {JapaneseChronology.INSTANCE.date(1727, 12, 6), "Japanese 1727-12-06"}, + {JapaneseChronology.INSTANCE.date(1868, 9, 8), "Japanese Meiji 1-09-08"}, + {JapaneseChronology.INSTANCE.date(1912, 7, 29), "Japanese Meiji 45-07-29"}, + {JapaneseChronology.INSTANCE.date(1912, 7, 30), "Japanese Taisho 1-07-30"}, + {JapaneseChronology.INSTANCE.date(1926, 12, 24), "Japanese Taisho 15-12-24"}, + {JapaneseChronology.INSTANCE.date(1926, 12, 25), "Japanese Showa 1-12-25"}, + {JapaneseChronology.INSTANCE.date(1989, 1, 7), "Japanese Showa 64-01-07"}, + {JapaneseChronology.INSTANCE.date(1989, 1, 8), "Japanese Heisei 1-01-08"}, + {JapaneseChronology.INSTANCE.date(2012, 12, 6), "Japanese Heisei 24-12-06"}, + }; + } + + @Test(dataProvider="toString", groups={"tck"}) + public void test_toString(JapaneseDate jdate, String expected) { + assertEquals(jdate.toString(), expected); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test(groups="tck") + public void test_equals_true() { + assertTrue(JapaneseChronology.INSTANCE.equals(JapaneseChronology.INSTANCE)); + } + + @Test(groups="tck") + public void test_equals_false() { + assertFalse(JapaneseChronology.INSTANCE.equals(IsoChronology.INSTANCE)); + } + +} diff --git a/jdk/test/java/time/tck/java/time/calendar/TestMinguoChrono.java b/jdk/test/java/time/tck/java/time/chrono/TestMinguoChronology.java similarity index 52% rename from jdk/test/java/time/tck/java/time/calendar/TestMinguoChrono.java rename to jdk/test/java/time/tck/java/time/chrono/TestMinguoChronology.java index 118f7d89b70..5ea1979bcdf 100644 --- a/jdk/test/java/time/tck/java/time/calendar/TestMinguoChrono.java +++ b/jdk/test/java/time/tck/java/time/chrono/TestMinguoChronology.java @@ -54,7 +54,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package tck.java.time.calendar; +package tck.java.time.chrono; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; @@ -66,14 +66,17 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; import java.time.ZoneOffset; -import java.time.calendar.MinguoChrono; +import java.time.chrono.MinguoChronology; +import java.time.chrono.MinguoDate; import java.time.temporal.Adjusters; import java.time.temporal.ChronoUnit; -import java.time.temporal.ChronoZonedDateTime; -import java.time.temporal.Chrono; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.ChronoLocalDateTime; -import java.time.temporal.ISOChrono; +import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.IsoChronology; +import java.time.chrono.Era; +import java.time.Year; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -83,15 +86,16 @@ import org.testng.annotations.Test; * Test. */ @Test -public class TestMinguoChrono { +public class TestMinguoChronology { + private static final int YDIFF = 1911; //----------------------------------------------------------------------- - // Chrono.ofName("Minguo") Lookup by name + // Chronology.ofName("Minguo") Lookup by name //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_chrono_byName() { - Chrono c = MinguoChrono.INSTANCE; - Chrono test = Chrono.of("Minguo"); + Chronology c = MinguoChronology.INSTANCE; + Chronology test = Chronology.of("Minguo"); Assert.assertNotNull(test, "The Minguo calendar could not be found byName"); Assert.assertEquals(test.getId(), "Minguo", "ID mismatch"); Assert.assertEquals(test.getCalendarType(), "roc", "Type mismatch"); @@ -104,40 +108,45 @@ public class TestMinguoChrono { @DataProvider(name="samples") Object[][] data_samples() { return new Object[][] { - {MinguoChrono.INSTANCE.date(1, 1, 1), LocalDate.of(1912, 1, 1)}, - {MinguoChrono.INSTANCE.date(1, 1, 2), LocalDate.of(1912, 1, 2)}, - {MinguoChrono.INSTANCE.date(1, 1, 3), LocalDate.of(1912, 1, 3)}, + {MinguoChronology.INSTANCE.date(1, 1, 1), LocalDate.of(1 + YDIFF, 1, 1)}, + {MinguoChronology.INSTANCE.date(1, 1, 2), LocalDate.of(1 + YDIFF, 1, 2)}, + {MinguoChronology.INSTANCE.date(1, 1, 3), LocalDate.of(1 + YDIFF, 1, 3)}, - {MinguoChrono.INSTANCE.date(2, 1, 1), LocalDate.of(1913, 1, 1)}, - {MinguoChrono.INSTANCE.date(3, 1, 1), LocalDate.of(1914, 1, 1)}, - {MinguoChrono.INSTANCE.date(3, 12, 6), LocalDate.of(1914, 12, 6)}, - {MinguoChrono.INSTANCE.date(4, 1, 1), LocalDate.of(1915, 1, 1)}, - {MinguoChrono.INSTANCE.date(4, 7, 3), LocalDate.of(1915, 7, 3)}, - {MinguoChrono.INSTANCE.date(4, 7, 4), LocalDate.of(1915, 7, 4)}, - {MinguoChrono.INSTANCE.date(5, 1, 1), LocalDate.of(1916, 1, 1)}, - {MinguoChrono.INSTANCE.date(100, 3, 3), LocalDate.of(2011, 3, 3)}, - {MinguoChrono.INSTANCE.date(101, 10, 28), LocalDate.of(2012, 10, 28)}, - {MinguoChrono.INSTANCE.date(101, 10, 29), LocalDate.of(2012, 10, 29)}, + {MinguoChronology.INSTANCE.date(2, 1, 1), LocalDate.of(2 + YDIFF, 1, 1)}, + {MinguoChronology.INSTANCE.date(3, 1, 1), LocalDate.of(3 + YDIFF, 1, 1)}, + {MinguoChronology.INSTANCE.date(3, 12, 6), LocalDate.of(3 + YDIFF, 12, 6)}, + {MinguoChronology.INSTANCE.date(4, 1, 1), LocalDate.of(4 + YDIFF, 1, 1)}, + {MinguoChronology.INSTANCE.date(4, 7, 3), LocalDate.of(4 + YDIFF, 7, 3)}, + {MinguoChronology.INSTANCE.date(4, 7, 4), LocalDate.of(4 + YDIFF, 7, 4)}, + {MinguoChronology.INSTANCE.date(5, 1, 1), LocalDate.of(5 + YDIFF, 1, 1)}, + {MinguoChronology.INSTANCE.date(100, 3, 3), LocalDate.of(100 + YDIFF, 3, 3)}, + {MinguoChronology.INSTANCE.date(101, 10, 28), LocalDate.of(101 + YDIFF, 10, 28)}, + {MinguoChronology.INSTANCE.date(101, 10, 29), LocalDate.of(101 + YDIFF, 10, 29)}, + + {MinguoChronology.INSTANCE.dateYearDay(1916 - YDIFF, 60), LocalDate.of(1916, 2, 29)}, + {MinguoChronology.INSTANCE.dateYearDay(1908 - YDIFF, 60), LocalDate.of(1908, 2, 29)}, + {MinguoChronology.INSTANCE.dateYearDay(2000 - YDIFF, 60), LocalDate.of(2000, 2, 29)}, + {MinguoChronology.INSTANCE.dateYearDay(2400 - YDIFF, 60), LocalDate.of(2400, 2, 29)}, }; } @Test(dataProvider="samples", groups={"tck"}) - public void test_toLocalDate(ChronoLocalDate minguo, LocalDate iso) { + public void test_toLocalDate(MinguoDate minguo, LocalDate iso) { assertEquals(LocalDate.from(minguo), iso); } @Test(dataProvider="samples", groups={"tck"}) - public void test_fromCalendrical(ChronoLocalDate minguo, LocalDate iso) { - assertEquals(MinguoChrono.INSTANCE.date(iso), minguo); + public void test_fromCalendrical(MinguoDate minguo, LocalDate iso) { + assertEquals(MinguoChronology.INSTANCE.date(iso), minguo); } @SuppressWarnings("unused") @Test(dataProvider="samples", groups={"implementation"}) - public void test_MinguoDate(ChronoLocalDate minguoDate, LocalDate iso) { - ChronoLocalDate hd = minguoDate; - ChronoLocalDateTime hdt = hd.atTime(LocalTime.NOON); + public void test_MinguoDate(MinguoDate minguoDate, LocalDate iso) { + MinguoDate hd = minguoDate; + ChronoLocalDateTime hdt = hd.atTime(LocalTime.NOON); ZoneOffset zo = ZoneOffset.ofHours(1); - ChronoZonedDateTime hzdt = hdt.atZone(zo); + ChronoZonedDateTime hzdt = hdt.atZone(zo); hdt = hdt.plus(1, ChronoUnit.YEARS); hdt = hdt.plus(1, ChronoUnit.MONTHS); hdt = hdt.plus(1, ChronoUnit.DAYS); @@ -145,19 +154,19 @@ public class TestMinguoChrono { hdt = hdt.plus(1, ChronoUnit.MINUTES); hdt = hdt.plus(1, ChronoUnit.SECONDS); hdt = hdt.plus(1, ChronoUnit.NANOS); - ChronoLocalDateTime a2 = hzdt.getDateTime(); - ChronoLocalDate a3 = a2.getDate(); - ChronoLocalDate a5 = hzdt.getDate(); + ChronoLocalDateTime a2 = hzdt.toLocalDateTime(); + MinguoDate a3 = a2.toLocalDate(); + MinguoDate a5 = hzdt.toLocalDate(); //System.out.printf(" d: %s, dt: %s; odt: %s; zodt: %s; a4: %s%n", date, hdt, hodt, hzdt, a5); } @Test() public void test_MinguoChrono() { - ChronoLocalDate h1 = MinguoChrono.ERA_ROC.date(1, 2, 3); - ChronoLocalDate h2 = h1; - ChronoLocalDateTime h3 = h2.atTime(LocalTime.NOON); + MinguoDate h1 = (MinguoDate)MinguoChronology.ERA_ROC.date(1, 2, 3); + MinguoDate h2 = h1; + ChronoLocalDateTime h3 = h2.atTime(LocalTime.NOON); @SuppressWarnings("unused") - ChronoZonedDateTime h4 = h3.atZone(ZoneOffset.UTC); + ChronoZonedDateTime h4 = h3.atZone(ZoneOffset.UTC); } @DataProvider(name="badDates") @@ -179,12 +188,56 @@ public class TestMinguoChrono { {1912, 12, -1}, {1912, 12, 0}, {1912, 12, 32}, + + {1907 - YDIFF, 2, 29}, + {100 - YDIFF, 2, 29}, + {2100 - YDIFF, 2, 29}, + {2101 - YDIFF, 2, 29}, }; } @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class) public void test_badDates(int year, int month, int dom) { - MinguoChrono.INSTANCE.date(year, month, dom); + MinguoChronology.INSTANCE.date(year, month, dom); + } + + //----------------------------------------------------------------------- + // prolepticYear() and is LeapYear() + //----------------------------------------------------------------------- + @DataProvider(name="prolepticYear") + Object[][] data_prolepticYear() { + return new Object[][] { + {1, MinguoChronology.ERA_ROC, 1912 - YDIFF, 1912 - YDIFF, true}, + {1, MinguoChronology.ERA_ROC, 1916 - YDIFF, 1916 - YDIFF, true}, + {1, MinguoChronology.ERA_ROC, 1914 - YDIFF, 1914 - YDIFF, false}, + {1, MinguoChronology.ERA_ROC, 2000 - YDIFF, 2000 - YDIFF, true}, + {1, MinguoChronology.ERA_ROC, 2100 - YDIFF, 2100 - YDIFF, false}, + {1, MinguoChronology.ERA_ROC, 0, 0, false}, + {1, MinguoChronology.ERA_ROC, 1908 - YDIFF, 1908 - YDIFF, true}, + {1, MinguoChronology.ERA_ROC, 1900 - YDIFF, 1900 - YDIFF, false}, + {1, MinguoChronology.ERA_ROC, 1600 - YDIFF, 1600 - YDIFF, true}, + + {0, MinguoChronology.ERA_BEFORE_ROC, YDIFF - 1911, 1912 - YDIFF, true}, + {0, MinguoChronology.ERA_BEFORE_ROC, YDIFF - 1915, 1916 - YDIFF, true}, + {0, MinguoChronology.ERA_BEFORE_ROC, YDIFF - 1913, 1914 - YDIFF, false}, + {0, MinguoChronology.ERA_BEFORE_ROC, YDIFF - 1999, 2000 - YDIFF, true}, + {0, MinguoChronology.ERA_BEFORE_ROC, YDIFF - 2099, 2100 - YDIFF, false}, + {0, MinguoChronology.ERA_BEFORE_ROC, 1, 0, false}, + {0, MinguoChronology.ERA_BEFORE_ROC, YDIFF - 1907, 1908 - YDIFF, true}, + {0, MinguoChronology.ERA_BEFORE_ROC, YDIFF - 1899, 1900 - YDIFF, false}, + {0, MinguoChronology.ERA_BEFORE_ROC, YDIFF - 1599, 1600 - YDIFF, true}, + + }; + } + + @Test(dataProvider="prolepticYear", groups={"tck"}) + public void test_prolepticYear(int eraValue, Era era, int yearOfEra, int expectedProlepticYear, boolean isLeapYear) { + Era eraObj = MinguoChronology.INSTANCE.eraOf(eraValue) ; + assertTrue(MinguoChronology.INSTANCE.eras().contains(eraObj)); + assertEquals(eraObj, era); + assertEquals(MinguoChronology.INSTANCE.prolepticYear(era, yearOfEra), expectedProlepticYear); + assertEquals(MinguoChronology.INSTANCE.isLeapYear(expectedProlepticYear), isLeapYear) ; + assertEquals(MinguoChronology.INSTANCE.isLeapYear(expectedProlepticYear), Year.of(expectedProlepticYear + YDIFF).isLeap()) ; } //----------------------------------------------------------------------- @@ -192,16 +245,16 @@ public class TestMinguoChrono { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_adjust1() { - ChronoLocalDate base = MinguoChrono.INSTANCE.date(2012, 10, 29); - ChronoLocalDate test = base.with(Adjusters.lastDayOfMonth()); - assertEquals(test, MinguoChrono.INSTANCE.date(2012, 10, 31)); + MinguoDate base = MinguoChronology.INSTANCE.date(2012, 10, 29); + MinguoDate test = base.with(Adjusters.lastDayOfMonth()); + assertEquals(test, MinguoChronology.INSTANCE.date(2012, 10, 31)); } @Test(groups={"tck"}) public void test_adjust2() { - ChronoLocalDate base = MinguoChrono.INSTANCE.date(1728, 12, 2); - ChronoLocalDate test = base.with(Adjusters.lastDayOfMonth()); - assertEquals(test, MinguoChrono.INSTANCE.date(1728, 12, 31)); + MinguoDate base = MinguoChronology.INSTANCE.date(1728, 12, 2); + MinguoDate test = base.with(Adjusters.lastDayOfMonth()); + assertEquals(test, MinguoChronology.INSTANCE.date(1728, 12, 31)); } //----------------------------------------------------------------------- @@ -209,14 +262,14 @@ public class TestMinguoChrono { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_adjust_toLocalDate() { - ChronoLocalDate minguo = MinguoChrono.INSTANCE.date(99, 1, 4); - ChronoLocalDate test = minguo.with(LocalDate.of(2012, 7, 6)); - assertEquals(test, MinguoChrono.INSTANCE.date(101, 7, 6)); + MinguoDate minguo = MinguoChronology.INSTANCE.date(99, 1, 4); + MinguoDate test = minguo.with(LocalDate.of(2012, 7, 6)); + assertEquals(test, MinguoChronology.INSTANCE.date(101, 7, 6)); } @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) public void test_adjust_toMonth() { - ChronoLocalDate minguo = MinguoChrono.INSTANCE.date(1726, 1, 4); + MinguoDate minguo = MinguoChronology.INSTANCE.date(1726, 1, 4); minguo.with(Month.APRIL); } @@ -225,14 +278,14 @@ public class TestMinguoChrono { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_LocalDate_adjustToMinguoDate() { - ChronoLocalDate minguo = MinguoChrono.INSTANCE.date(101, 10, 29); + MinguoDate minguo = MinguoChronology.INSTANCE.date(101, 10, 29); LocalDate test = LocalDate.MIN.with(minguo); assertEquals(test, LocalDate.of(2012, 10, 29)); } @Test(groups={"tck"}) public void test_LocalDateTime_adjustToMinguoDate() { - ChronoLocalDate minguo = MinguoChrono.INSTANCE.date(101, 10, 29); + MinguoDate minguo = MinguoChronology.INSTANCE.date(101, 10, 29); LocalDateTime test = LocalDateTime.MIN.with(minguo); assertEquals(test, LocalDateTime.of(2012, 10, 29, 0, 0)); } @@ -243,16 +296,16 @@ public class TestMinguoChrono { @DataProvider(name="toString") Object[][] data_toString() { return new Object[][] { - {MinguoChrono.INSTANCE.date(1, 1, 1), "Minguo ROC 1-01-01"}, - {MinguoChrono.INSTANCE.date(1728, 10, 28), "Minguo ROC 1728-10-28"}, - {MinguoChrono.INSTANCE.date(1728, 10, 29), "Minguo ROC 1728-10-29"}, - {MinguoChrono.INSTANCE.date(1727, 12, 5), "Minguo ROC 1727-12-05"}, - {MinguoChrono.INSTANCE.date(1727, 12, 6), "Minguo ROC 1727-12-06"}, + {MinguoChronology.INSTANCE.date(1, 1, 1), "Minguo ROC 1-01-01"}, + {MinguoChronology.INSTANCE.date(1728, 10, 28), "Minguo ROC 1728-10-28"}, + {MinguoChronology.INSTANCE.date(1728, 10, 29), "Minguo ROC 1728-10-29"}, + {MinguoChronology.INSTANCE.date(1727, 12, 5), "Minguo ROC 1727-12-05"}, + {MinguoChronology.INSTANCE.date(1727, 12, 6), "Minguo ROC 1727-12-06"}, }; } @Test(dataProvider="toString", groups={"tck"}) - public void test_toString(ChronoLocalDate minguo, String expected) { + public void test_toString(MinguoDate minguo, String expected) { assertEquals(minguo.toString(), expected); } @@ -261,12 +314,12 @@ public class TestMinguoChrono { //----------------------------------------------------------------------- @Test(groups="tck") public void test_equals_true() { - assertTrue(MinguoChrono.INSTANCE.equals(MinguoChrono.INSTANCE)); + assertTrue(MinguoChronology.INSTANCE.equals(MinguoChronology.INSTANCE)); } @Test(groups="tck") public void test_equals_false() { - assertFalse(MinguoChrono.INSTANCE.equals(ISOChrono.INSTANCE)); + assertFalse(MinguoChronology.INSTANCE.equals(IsoChronology.INSTANCE)); } } diff --git a/jdk/test/java/time/tck/java/time/chrono/TestThaiBuddhistChronology.java b/jdk/test/java/time/tck/java/time/chrono/TestThaiBuddhistChronology.java new file mode 100644 index 00000000000..32eae1e073e --- /dev/null +++ b/jdk/test/java/time/tck/java/time/chrono/TestThaiBuddhistChronology.java @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2012, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.chrono; + +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_YEAR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.YEAR_OF_ERA; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import java.time.DateTimeException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.Month; +import java.time.Year; +import java.time.chrono.ThaiBuddhistChronology; +import java.time.chrono.ThaiBuddhistDate; +import java.time.chrono.Chronology; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Era; +import java.time.chrono.IsoChronology; +import java.time.temporal.Adjusters; +import java.time.temporal.ChronoField; +import java.time.temporal.ValueRange; +import java.util.Locale; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TestThaiBuddhistChronology { + + private static final int YDIFF = 543; + + //----------------------------------------------------------------------- + // Chronology.of(String) + //----------------------------------------------------------------------- + @Test + public void test_chrono_byName() { + Chronology c = ThaiBuddhistChronology.INSTANCE; + Chronology test = Chronology.of("ThaiBuddhist"); + Assert.assertNotNull(test, "The ThaiBuddhist calendar could not be found byName"); + Assert.assertEquals(test.getId(), "ThaiBuddhist", "ID mismatch"); + Assert.assertEquals(test.getCalendarType(), "buddhist", "Type mismatch"); + Assert.assertEquals(test, c); + } + + //----------------------------------------------------------------------- + // Chronology.ofLocale(Locale) + //----------------------------------------------------------------------- + @Test + public void test_chrono_byLocale_fullTag_thaiCalendarFromThai() { + Chronology test = Chronology.ofLocale(Locale.forLanguageTag("th-TH-u-ca-buddhist")); + Assert.assertEquals(test.getId(), "ThaiBuddhist"); + Assert.assertEquals(test, ThaiBuddhistChronology.INSTANCE); + } + + @Test + public void test_chrono_byLocale_fullTag_thaiCalendarFromElsewhere() { + Chronology test = Chronology.ofLocale(Locale.forLanguageTag("en-US-u-ca-buddhist")); + Assert.assertEquals(test.getId(), "ThaiBuddhist"); + Assert.assertEquals(test, ThaiBuddhistChronology.INSTANCE); + } + + @Test + public void test_chrono_byLocale_oldTH_noVariant() { // deliberately different to Calendar + Chronology test = Chronology.ofLocale(new Locale("th", "TH")); + Assert.assertEquals(test.getId(), "ISO"); + Assert.assertEquals(test, IsoChronology.INSTANCE); + } + + @Test + public void test_chrono_byLocale_oldTH_variant() { + Chronology test = Chronology.ofLocale(new Locale("th", "TH", "TH")); + Assert.assertEquals(test.getId(), "ISO"); + Assert.assertEquals(test, IsoChronology.INSTANCE); + } + + @Test + public void test_chrono_byLocale_iso() { + Assert.assertEquals(Chronology.ofLocale(new Locale("th", "TH")).getId(), "ISO"); + Assert.assertEquals(Chronology.ofLocale(Locale.forLanguageTag("th-TH")).getId(), "ISO"); + Assert.assertEquals(Chronology.ofLocale(Locale.forLanguageTag("th-TH-TH")).getId(), "ISO"); + } + + //----------------------------------------------------------------------- + // creation, toLocalDate() + //----------------------------------------------------------------------- + @DataProvider(name="samples") + Object[][] data_samples() { + return new Object[][] { + {ThaiBuddhistChronology.INSTANCE.date(1 + YDIFF, 1, 1), LocalDate.of(1, 1, 1)}, + {ThaiBuddhistChronology.INSTANCE.date(1 + YDIFF, 1, 2), LocalDate.of(1, 1, 2)}, + {ThaiBuddhistChronology.INSTANCE.date(1 + YDIFF, 1, 3), LocalDate.of(1, 1, 3)}, + + {ThaiBuddhistChronology.INSTANCE.date(2 + YDIFF, 1, 1), LocalDate.of(2, 1, 1)}, + {ThaiBuddhistChronology.INSTANCE.date(3 + YDIFF, 1, 1), LocalDate.of(3, 1, 1)}, + {ThaiBuddhistChronology.INSTANCE.date(3 + YDIFF, 12, 6), LocalDate.of(3, 12, 6)}, + {ThaiBuddhistChronology.INSTANCE.date(4 + YDIFF, 1, 1), LocalDate.of(4, 1, 1)}, + {ThaiBuddhistChronology.INSTANCE.date(4 + YDIFF, 7, 3), LocalDate.of(4, 7, 3)}, + {ThaiBuddhistChronology.INSTANCE.date(4 + YDIFF, 7, 4), LocalDate.of(4, 7, 4)}, + {ThaiBuddhistChronology.INSTANCE.date(5 + YDIFF, 1, 1), LocalDate.of(5, 1, 1)}, + {ThaiBuddhistChronology.INSTANCE.date(1662 + YDIFF, 3, 3), LocalDate.of(1662, 3, 3)}, + {ThaiBuddhistChronology.INSTANCE.date(1728 + YDIFF, 10, 28), LocalDate.of(1728, 10, 28)}, + {ThaiBuddhistChronology.INSTANCE.date(1728 + YDIFF, 10, 29), LocalDate.of(1728, 10, 29)}, + {ThaiBuddhistChronology.INSTANCE.date(2555, 8, 29), LocalDate.of(2012, 8, 29)}, + + {ThaiBuddhistChronology.INSTANCE.dateYearDay(4 + YDIFF, 60), LocalDate.of(4, 2, 29)}, + {ThaiBuddhistChronology.INSTANCE.dateYearDay(400 + YDIFF, 60), LocalDate.of(400, 2, 29)}, + {ThaiBuddhistChronology.INSTANCE.dateYearDay(2000 + YDIFF, 60), LocalDate.of(2000, 2, 29)}, + + }; + } + + @Test(dataProvider="samples", groups={"tck"}) + public void test_toLocalDate(ThaiBuddhistDate jdate, LocalDate iso) { + assertEquals(LocalDate.from(jdate), iso); + } + + @Test(dataProvider="samples", groups={"tck"}) + public void test_fromCalendrical(ThaiBuddhistDate jdate, LocalDate iso) { + assertEquals(ThaiBuddhistChronology.INSTANCE.date(iso), jdate); + } + + @DataProvider(name="badDates") + Object[][] data_badDates() { + return new Object[][] { + {1728, 0, 0}, + + {1728, -1, 1}, + {1728, 0, 1}, + {1728, 14, 1}, + {1728, 15, 1}, + + {1728, 1, -1}, + {1728, 1, 0}, + {1728, 1, 32}, + + {1728, 12, -1}, + {1728, 12, 0}, + {1728, 12, 32}, + + {3 + YDIFF, 2, 29}, + {600 + YDIFF, 2, 29}, + {1501 + YDIFF, 2, 29}, + }; + } + + @Test(dataProvider="badDates", groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_badDates(int year, int month, int dom) { + ThaiBuddhistChronology.INSTANCE.date(year, month, dom); + } + + //----------------------------------------------------------------------- + // prolepticYear() and is LeapYear() + //----------------------------------------------------------------------- + @DataProvider(name="prolepticYear") + Object[][] data_prolepticYear() { + return new Object[][] { + {1, ThaiBuddhistChronology.ERA_BE, 4 + YDIFF, 4 + YDIFF, true}, + {1, ThaiBuddhistChronology.ERA_BE, 7 + YDIFF, 7 + YDIFF, false}, + {1, ThaiBuddhistChronology.ERA_BE, 8 + YDIFF, 8 + YDIFF, true}, + {1, ThaiBuddhistChronology.ERA_BE, 1000 + YDIFF, 1000 + YDIFF, false}, + {1, ThaiBuddhistChronology.ERA_BE, 2000 + YDIFF, 2000 + YDIFF, true}, + {1, ThaiBuddhistChronology.ERA_BE, 0, 0, false}, + {1, ThaiBuddhistChronology.ERA_BE, -4 + YDIFF, -4 + YDIFF, true}, + {1, ThaiBuddhistChronology.ERA_BE, -7 + YDIFF, -7 + YDIFF, false}, + {1, ThaiBuddhistChronology.ERA_BE, -100 + YDIFF, -100 + YDIFF, false}, + {1, ThaiBuddhistChronology.ERA_BE, -800 + YDIFF, -800 + YDIFF, true}, + + {0, ThaiBuddhistChronology.ERA_BEFORE_BE, -3 - YDIFF, 4 + YDIFF, true}, + {0, ThaiBuddhistChronology.ERA_BEFORE_BE, -6 - YDIFF, 7 + YDIFF, false}, + {0, ThaiBuddhistChronology.ERA_BEFORE_BE, -7 - YDIFF, 8 + YDIFF, true}, + {0, ThaiBuddhistChronology.ERA_BEFORE_BE, -999 - YDIFF, 1000 + YDIFF, false}, + {0, ThaiBuddhistChronology.ERA_BEFORE_BE, -1999 - YDIFF, 2000 + YDIFF, true}, + {0, ThaiBuddhistChronology.ERA_BEFORE_BE, 1, 0, false}, + {0, ThaiBuddhistChronology.ERA_BEFORE_BE, 5 - YDIFF, -4 + YDIFF, true}, + {0, ThaiBuddhistChronology.ERA_BEFORE_BE, 8 - YDIFF, -7 + YDIFF, false}, + {0, ThaiBuddhistChronology.ERA_BEFORE_BE, 101 - YDIFF, -100 + YDIFF, false}, + {0, ThaiBuddhistChronology.ERA_BEFORE_BE, 801 - YDIFF, -800 + YDIFF, true}, + + }; + } + + @Test(dataProvider="prolepticYear", groups={"tck"}) + public void test_prolepticYear(int eraValue, Era era, int yearOfEra, int expectedProlepticYear, boolean isLeapYear) { + Era eraObj = ThaiBuddhistChronology.INSTANCE.eraOf(eraValue) ; + assertTrue(ThaiBuddhistChronology.INSTANCE.eras().contains(eraObj)); + assertEquals(eraObj, era); + assertEquals(ThaiBuddhistChronology.INSTANCE.prolepticYear(era, yearOfEra), expectedProlepticYear); + assertEquals(ThaiBuddhistChronology.INSTANCE.isLeapYear(expectedProlepticYear), isLeapYear) ; + assertEquals(ThaiBuddhistChronology.INSTANCE.isLeapYear(expectedProlepticYear), Year.of(expectedProlepticYear - YDIFF).isLeap()) ; + } + + //----------------------------------------------------------------------- + // with(WithAdjuster) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_adjust1() { + ThaiBuddhistDate base = ThaiBuddhistChronology.INSTANCE.date(1728, 10, 29); + ThaiBuddhistDate test = base.with(Adjusters.lastDayOfMonth()); + assertEquals(test, ThaiBuddhistChronology.INSTANCE.date(1728, 10, 31)); + } + + @Test(groups={"tck"}) + public void test_adjust2() { + ThaiBuddhistDate base = ThaiBuddhistChronology.INSTANCE.date(1728, 12, 2); + ThaiBuddhistDate test = base.with(Adjusters.lastDayOfMonth()); + assertEquals(test, ThaiBuddhistChronology.INSTANCE.date(1728, 12, 31)); + } + + //----------------------------------------------------------------------- + // withYear() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withYear_BE() { + ThaiBuddhistDate base = ThaiBuddhistChronology.INSTANCE.date(2555, 8, 29); + ThaiBuddhistDate test = base.with(YEAR, 2554); + assertEquals(test, ThaiBuddhistChronology.INSTANCE.date(2554, 8, 29)); + } + + @Test(groups={"tck"}) + public void test_withYear_BBE() { + ThaiBuddhistDate base = ThaiBuddhistChronology.INSTANCE.date(-2554, 8, 29); + ThaiBuddhistDate test = base.with(YEAR_OF_ERA, 2554); + assertEquals(test, ThaiBuddhistChronology.INSTANCE.date(-2553, 8, 29)); + } + + //----------------------------------------------------------------------- + // withEra() + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_withEra_BE() { + ThaiBuddhistDate base = ThaiBuddhistChronology.INSTANCE.date(2555, 8, 29); + ThaiBuddhistDate test = base.with(ChronoField.ERA, ThaiBuddhistChronology.ERA_BE.getValue()); + assertEquals(test, ThaiBuddhistChronology.INSTANCE.date(2555, 8, 29)); + } + + @Test(groups={"tck"}) + public void test_withEra_BBE() { + ThaiBuddhistDate base = ThaiBuddhistChronology.INSTANCE.date(-2554, 8, 29); + ThaiBuddhistDate test = base.with(ChronoField.ERA, ThaiBuddhistChronology.ERA_BEFORE_BE.getValue()); + assertEquals(test, ThaiBuddhistChronology.INSTANCE.date(-2554, 8, 29)); + } + + @Test(groups={"tck"}) + public void test_withEra_swap() { + ThaiBuddhistDate base = ThaiBuddhistChronology.INSTANCE.date(-2554, 8, 29); + ThaiBuddhistDate test = base.with(ChronoField.ERA, ThaiBuddhistChronology.ERA_BE.getValue()); + assertEquals(test, ThaiBuddhistChronology.INSTANCE.date(2555, 8, 29)); + } + + //----------------------------------------------------------------------- + // BuddhistDate.with(Local*) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_adjust_toLocalDate() { + ThaiBuddhistDate jdate = ThaiBuddhistChronology.INSTANCE.date(1726, 1, 4); + ThaiBuddhistDate test = jdate.with(LocalDate.of(2012, 7, 6)); + assertEquals(test, ThaiBuddhistChronology.INSTANCE.date(2555, 7, 6)); + } + + @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) + public void test_adjust_toMonth() { + ThaiBuddhistDate jdate = ThaiBuddhistChronology.INSTANCE.date(1726, 1, 4); + jdate.with(Month.APRIL); + } + + //----------------------------------------------------------------------- + // LocalDate.with(BuddhistDate) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_LocalDate_adjustToBuddhistDate() { + ThaiBuddhistDate jdate = ThaiBuddhistChronology.INSTANCE.date(2555, 10, 29); + LocalDate test = LocalDate.MIN.with(jdate); + assertEquals(test, LocalDate.of(2012, 10, 29)); + } + + @Test(groups={"tck"}) + public void test_LocalDateTime_adjustToBuddhistDate() { + ThaiBuddhistDate jdate = ThaiBuddhistChronology.INSTANCE.date(2555, 10, 29); + LocalDateTime test = LocalDateTime.MIN.with(jdate); + assertEquals(test, LocalDateTime.of(2012, 10, 29, 0, 0)); + } + + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- + @DataProvider(name="toString") + Object[][] data_toString() { + return new Object[][] { + {ThaiBuddhistChronology.INSTANCE.date(544, 1, 1), "ThaiBuddhist BE 544-01-01"}, + {ThaiBuddhistChronology.INSTANCE.date(2271, 10, 28), "ThaiBuddhist BE 2271-10-28"}, + {ThaiBuddhistChronology.INSTANCE.date(2271, 10, 29), "ThaiBuddhist BE 2271-10-29"}, + {ThaiBuddhistChronology.INSTANCE.date(2270, 12, 5), "ThaiBuddhist BE 2270-12-05"}, + {ThaiBuddhistChronology.INSTANCE.date(2270, 12, 6), "ThaiBuddhist BE 2270-12-06"}, + }; + } + + @Test(dataProvider="toString", groups={"tck"}) + public void test_toString(ThaiBuddhistDate jdate, String expected) { + assertEquals(jdate.toString(), expected); + } + + //----------------------------------------------------------------------- + // chronology range(ChronoField) + //----------------------------------------------------------------------- + @Test(groups={"tck"}) + public void test_Chrono_range() { + long minYear = LocalDate.MIN.getYear() + YDIFF; + long maxYear = LocalDate.MAX.getYear() + YDIFF; + assertEquals(ThaiBuddhistChronology.INSTANCE.range(YEAR), ValueRange.of(minYear, maxYear)); + assertEquals(ThaiBuddhistChronology.INSTANCE.range(YEAR_OF_ERA), ValueRange.of(1, -minYear + 1, maxYear)); + + assertEquals(ThaiBuddhistChronology.INSTANCE.range(DAY_OF_MONTH), DAY_OF_MONTH.range()); + assertEquals(ThaiBuddhistChronology.INSTANCE.range(DAY_OF_YEAR), DAY_OF_YEAR.range()); + assertEquals(ThaiBuddhistChronology.INSTANCE.range(MONTH_OF_YEAR), MONTH_OF_YEAR.range()); + } + + //----------------------------------------------------------------------- + // equals() + //----------------------------------------------------------------------- + @Test(groups="tck") + public void test_equals_true() { + assertTrue(ThaiBuddhistChronology.INSTANCE.equals(ThaiBuddhistChronology.INSTANCE)); + } + + @Test(groups="tck") + public void test_equals_false() { + assertFalse(ThaiBuddhistChronology.INSTANCE.equals(IsoChronology.INSTANCE)); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestPadParserDecorator.java b/jdk/test/java/time/tck/java/time/format/TCKChronoPrinterParser.java similarity index 50% rename from jdk/test/java/time/test/java/time/format/TestPadParserDecorator.java rename to jdk/test/java/time/tck/java/time/format/TCKChronoPrinterParser.java index 08a9e24544d..e4e74f6f351 100644 --- a/jdk/test/java/time/test/java/time/format/TestPadParserDecorator.java +++ b/jdk/test/java/time/tck/java/time/format/TCKChronoPrinterParser.java @@ -27,7 +27,7 @@ * However, the following notice accompanied the original version of this * file: * - * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos * * All rights reserved. * @@ -57,84 +57,110 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package test.java.time.format; +package tck.java.time.format; -import java.time.format.*; - -import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static org.testng.Assert.assertEquals; import java.text.ParsePosition; -import java.time.format.DateTimeBuilder; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.ThaiBuddhistChronology; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.Queries; +import java.time.temporal.TemporalAccessor; +import java.util.Locale; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** - * Test PadPrinterParserDecorator. + * Test formatter chrono. */ -@Test(groups={"implementation"}) -public class TestPadParserDecorator extends AbstractTestPrinterParser { +@Test +public class TCKChronoPrinterParser { + // this test assumes ISO, ThaiBuddhist and Japanese are available + + private DateTimeFormatterBuilder builder; + private ParsePosition pos; + + @BeforeMethod + public void setUp() { + builder = new DateTimeFormatterBuilder(); + pos = new ParsePosition(0); + } //----------------------------------------------------------------------- @Test(expectedExceptions=IndexOutOfBoundsException.class) - public void test_parse_negativePosition() throws Exception { - builder.padNext(3, '-').appendLiteral('Z'); - getFormatter().parseToBuilder("--Z", new ParsePosition(-1)); + public void test_parse_negativePosition() { + builder.appendChronologyId().toFormatter().parseUnresolved("ISO", new ParsePosition(-1)); } @Test(expectedExceptions=IndexOutOfBoundsException.class) - public void test_parse_offEndPosition() throws Exception { - builder.padNext(3, '-').appendLiteral('Z'); - getFormatter().parseToBuilder("--Z", new ParsePosition(4)); + public void test_parse_offEndPosition() { + builder.appendChronologyId().toFormatter().parseUnresolved("ISO", new ParsePosition(4)); } //----------------------------------------------------------------------- - public void test_parse() throws Exception { - ParsePosition pos = new ParsePosition(0); - builder.padNext(3, '-').appendValue(MONTH_OF_YEAR, 1, 3, SignStyle.NEVER); - DateTimeBuilder dtb = getFormatter().parseToBuilder("--2", pos); - assertEquals(pos.getIndex(), 3); - assertEquals(dtb.getFieldValueMap().size(), 1); - assertEquals(dtb.getLong(MONTH_OF_YEAR), 2L); + @DataProvider(name="parseValid") + Object[][] data_parseValid() { + return new Object[][] { + {"ISO", IsoChronology.INSTANCE}, + {"ThaiBuddhist", ThaiBuddhistChronology.INSTANCE}, + {"Japanese", JapaneseChronology.INSTANCE}, + + {"ISO2012", IsoChronology.INSTANCE}, + {"ThaiBuddhistXXX", ThaiBuddhistChronology.INSTANCE}, + {"JapaneseXXX", JapaneseChronology.INSTANCE}, + }; } - public void test_parse_noReadBeyond() throws Exception { - ParsePosition pos = new ParsePosition(0); - builder.padNext(3, '-').appendValue(MONTH_OF_YEAR, 1, 3, SignStyle.NEVER); - DateTimeBuilder dtb = getFormatter().parseToBuilder("--22", pos); - assertEquals(pos.getIndex(), 3); - assertEquals(dtb.getFieldValueMap().size(), 1); - assertEquals(dtb.getLong(MONTH_OF_YEAR), 2L); + @Test(dataProvider="parseValid") + public void test_parseValid_caseSensitive(String text, Chronology expected) { + builder.appendChronologyId(); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text, pos); + assertEquals(pos.getIndex(), expected.getId().length()); + assertEquals(pos.getErrorIndex(), -1); + assertEquals(parsed.query(Queries.chronology()), expected); } - public void test_parse_textLessThanPadWidth() throws Exception { - ParsePosition pos = new ParsePosition(0); - builder.padNext(3, '-').appendValue(MONTH_OF_YEAR, 1, 3, SignStyle.NEVER); - DateTimeBuilder dtb = getFormatter().parseToBuilder("-1", pos); + @Test(dataProvider="parseValid") + public void test_parseValid_caseSensitive_lowercaseRejected(String text, Chronology expected) { + builder.appendChronologyId(); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text.toLowerCase(Locale.ENGLISH), pos); + assertEquals(pos.getIndex(), 0); assertEquals(pos.getErrorIndex(), 0); + assertEquals(parsed, null); } - public void test_parse_decoratedErrorPassedBack() throws Exception { - ParsePosition pos = new ParsePosition(0); - builder.padNext(3, '-').appendValue(MONTH_OF_YEAR, 1, 3, SignStyle.NEVER); - DateTimeBuilder dtb = getFormatter().parseToBuilder("--A", pos); - assertEquals(pos.getErrorIndex(), 2); - } - - public void test_parse_decoratedDidNotParseToPadWidth() throws Exception { - ParsePosition pos = new ParsePosition(0); - builder.padNext(3, '-').appendValue(MONTH_OF_YEAR, 1, 3, SignStyle.NEVER); - DateTimeBuilder dtb = getFormatter().parseToBuilder("-1X", pos); - assertEquals(pos.getErrorIndex(), 0); + @Test(dataProvider="parseValid") + public void test_parseValid_caseInsensitive(String text, Chronology expected) { + builder.parseCaseInsensitive().appendChronologyId(); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text.toLowerCase(Locale.ENGLISH), pos); + assertEquals(pos.getIndex(), expected.getId().length()); + assertEquals(pos.getErrorIndex(), -1); + assertEquals(parsed.query(Queries.chronology()), expected); } //----------------------------------------------------------------------- - public void test_parse_decoratedStartsWithPad() throws Exception { - ParsePosition pos = new ParsePosition(0); - builder.padNext(8, '-').appendLiteral("-HELLO-"); - DateTimeBuilder dtb = getFormatter().parseToBuilder("--HELLO-", pos); - assertEquals(pos.getIndex(), 8); - assertEquals(dtb.getFieldValueMap().size(), 0); + @DataProvider(name="parseInvalid") + Object[][] data_parseInvalid() { + return new Object[][] { + {"Rubbish"}, + {"IS"}, + {"Thai"}, + {"Japan"}, + }; + } + + @Test(dataProvider="parseInvalid") + public void test_parseInvalid(String text) { + builder.appendChronologyId(); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text, pos); + assertEquals(pos.getIndex(), 0); + assertEquals(pos.getErrorIndex(), 0); + assertEquals(parsed, null); } } diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java index e206a1f28a7..f124d7ef215 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatter.java @@ -61,12 +61,13 @@ package tck.java.time.format; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.HOUR_OF_DAY; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.YEAR; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; -import java.io.IOException; import java.text.Format; import java.text.ParseException; import java.text.ParsePosition; @@ -80,20 +81,16 @@ import java.time.LocalTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; -import java.time.calendar.ThaiBuddhistChrono; +import java.time.chrono.ThaiBuddhistChronology; import java.time.format.DateTimeFormatSymbols; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; -import java.time.format.DateTimeFormatters; import java.time.format.DateTimeParseException; -import java.time.format.DateTimePrintException; import java.time.format.SignStyle; -import java.time.format.DateTimeBuilder; -import java.time.temporal.Chrono; -import java.time.temporal.ISOChrono; -import java.time.temporal.OffsetDate; -import java.time.temporal.OffsetDateTime; -import java.time.temporal.OffsetTime; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; +import java.time.OffsetDateTime; +import java.time.OffsetTime; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalQuery; @@ -101,7 +98,6 @@ import java.time.temporal.TemporalQuery; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import test.java.time.format.MockIOExceptionAppendable; /** * Test DateTimeFormatter. @@ -113,8 +109,8 @@ public class TCKDateTimeFormatter { private static final ZoneOffset OFFSET_PTHREE = ZoneOffset.ofHours(3); private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris"); - private static final DateTimeFormatter BASIC_FORMATTER = DateTimeFormatters.pattern("'ONE'd"); - private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatters.pattern("'ONE'yyyy MM dd"); + private static final DateTimeFormatter BASIC_FORMATTER = DateTimeFormatter.ofPattern("'ONE'd"); + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("'ONE'yyyy MM dd"); private DateTimeFormatter fmt; @@ -141,13 +137,13 @@ public class TCKDateTimeFormatter { //----------------------------------------------------------------------- @Test - public void test_withChrono() { + public void test_withChronology() { DateTimeFormatter test = fmt; - assertEquals(test.getChrono(), null); - test = test.withChrono(ISOChrono.INSTANCE); - assertEquals(test.getChrono(), ISOChrono.INSTANCE); - test = test.withChrono(null); - assertEquals(test.getChrono(), null); + assertEquals(test.getChronology(), null); + test = test.withChronology(IsoChronology.INSTANCE); + assertEquals(test.getChronology(), IsoChronology.INSTANCE); + test = test.withChronology(null); + assertEquals(test.getChronology(), null); } //----------------------------------------------------------------------- @@ -167,11 +163,10 @@ public class TCKDateTimeFormatter { // print //----------------------------------------------------------------------- @DataProvider(name="print") - Object[][] data_print() { + Object[][] data_format() { LocalDate ld = LocalDate.of(2008, 6, 30); LocalTime lt = LocalTime.of(11, 30); LocalDateTime ldt = LocalDateTime.of(2008, 6, 30, 11, 30); - OffsetDate od = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); OffsetTime ot = OffsetTime.of(LocalTime.of(11, 30), OFFSET_PONE); OffsetDateTime odt = OffsetDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30), OFFSET_PONE); ZonedDateTime zdt = ZonedDateTime.of(LocalDateTime.of(2008, 6, 30, 11, 30), ZONE_PARIS); @@ -180,7 +175,6 @@ public class TCKDateTimeFormatter { {null, null, ld, "2008::"}, {null, null, lt, ":11:"}, {null, null, ldt, "2008:11:"}, - {null, null, od, "2008::+01:00"}, {null, null, ot, ":11:+01:00"}, {null, null, odt, "2008:11:+01:00"}, {null, null, zdt, "2008:11:+02:00Europe/Paris"}, @@ -189,7 +183,6 @@ public class TCKDateTimeFormatter { {null, ZONE_PARIS, ld, "2008::"}, {null, ZONE_PARIS, lt, ":11:"}, {null, ZONE_PARIS, ldt, "2008:11:"}, - {null, ZONE_PARIS, od, "2008::+01:00"}, {null, ZONE_PARIS, ot, ":11:+01:00"}, {null, ZONE_PARIS, odt, "2008:12:+02:00Europe/Paris"}, {null, ZONE_PARIS, zdt, "2008:11:+02:00Europe/Paris"}, @@ -198,61 +191,58 @@ public class TCKDateTimeFormatter { {null, OFFSET_PTHREE, ld, "2008::"}, {null, OFFSET_PTHREE, lt, ":11:"}, {null, OFFSET_PTHREE, ldt, "2008:11:"}, - {null, OFFSET_PTHREE, od, "2008::+01:00"}, {null, OFFSET_PTHREE, ot, ":11:+01:00"}, {null, OFFSET_PTHREE, odt, "2008:13:+03:00"}, {null, OFFSET_PTHREE, zdt, "2008:12:+03:00"}, {null, OFFSET_PTHREE, instant, "1970:04:+03:00"}, - {ThaiBuddhistChrono.INSTANCE, null, ld, "2551::"}, - {ThaiBuddhistChrono.INSTANCE, null, lt, ":11:"}, - {ThaiBuddhistChrono.INSTANCE, null, ldt, "2551:11:"}, - {ThaiBuddhistChrono.INSTANCE, null, od, "2551::+01:00"}, - {ThaiBuddhistChrono.INSTANCE, null, ot, ":11:+01:00"}, - {ThaiBuddhistChrono.INSTANCE, null, odt, "2551:11:+01:00"}, - {ThaiBuddhistChrono.INSTANCE, null, zdt, "2551:11:+02:00Europe/Paris"}, - {ThaiBuddhistChrono.INSTANCE, null, instant, "::"}, + {ThaiBuddhistChronology.INSTANCE, null, ld, "2551::"}, + {ThaiBuddhistChronology.INSTANCE, null, lt, ":11:"}, + {ThaiBuddhistChronology.INSTANCE, null, ldt, "2551:11:"}, + {ThaiBuddhistChronology.INSTANCE, null, ot, ":11:+01:00"}, + {ThaiBuddhistChronology.INSTANCE, null, odt, "2551:11:+01:00"}, + {ThaiBuddhistChronology.INSTANCE, null, zdt, "2551:11:+02:00Europe/Paris"}, + {ThaiBuddhistChronology.INSTANCE, null, instant, "::"}, - {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, ld, "2551::"}, - {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, lt, ":11:"}, - {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, ldt, "2551:11:"}, - {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, od, "2551::+01:00"}, - {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, ot, ":11:+01:00"}, - {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, odt, "2551:12:+02:00Europe/Paris"}, - {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, zdt, "2551:11:+02:00Europe/Paris"}, - {ThaiBuddhistChrono.INSTANCE, ZONE_PARIS, instant, "1970:02:+01:00Europe/Paris"}, + {ThaiBuddhistChronology.INSTANCE, ZONE_PARIS, ld, "2551::"}, + {ThaiBuddhistChronology.INSTANCE, ZONE_PARIS, lt, ":11:"}, + {ThaiBuddhistChronology.INSTANCE, ZONE_PARIS, ldt, "2551:11:"}, + {ThaiBuddhistChronology.INSTANCE, ZONE_PARIS, ot, ":11:+01:00"}, + {ThaiBuddhistChronology.INSTANCE, ZONE_PARIS, odt, "2551:12:+02:00Europe/Paris"}, + {ThaiBuddhistChronology.INSTANCE, ZONE_PARIS, zdt, "2551:11:+02:00Europe/Paris"}, + {ThaiBuddhistChronology.INSTANCE, ZONE_PARIS, instant, "1970:02:+01:00Europe/Paris"}, }; } @Test(dataProvider="print") - public void test_print_Temporal(Chrono overrideChrono, ZoneId overrideZone, Temporal temporal, String expected) { + public void test_print_Temporal(Chronology overrideChrono, ZoneId overrideZone, Temporal temporal, String expected) { DateTimeFormatter test = new DateTimeFormatterBuilder() .optionalStart().appendValue(YEAR, 4).optionalEnd() .appendLiteral(':').optionalStart().appendValue(HOUR_OF_DAY, 2).optionalEnd() .appendLiteral(':').optionalStart().appendOffsetId().optionalStart().appendZoneRegionId().optionalEnd().optionalEnd() .toFormatter(Locale.ENGLISH) - .withChrono(overrideChrono).withZone(overrideZone); - String result = test.print(temporal); + .withChronology(overrideChrono).withZone(overrideZone); + String result = test.format(temporal); assertEquals(result, expected); } @Test public void test_print_Temporal_simple() throws Exception { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - String result = test.print(LocalDate.of(2008, 6, 30)); + String result = test.format(LocalDate.of(2008, 6, 30)); assertEquals(result, "ONE30"); } @Test(expectedExceptions=DateTimeException.class) public void test_print_Temporal_noSuchField() throws Exception { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - test.print(LocalTime.of(11, 30)); + test.format(LocalTime.of(11, 30)); } @Test(expectedExceptions=NullPointerException.class) public void test_print_Temporal_null() throws Exception { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - test.print((TemporalAccessor) null); + test.format((TemporalAccessor) null); } //----------------------------------------------------------------------- @@ -260,7 +250,7 @@ public class TCKDateTimeFormatter { public void test_print_TemporalAppendable() throws Exception { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); StringBuilder buf = new StringBuilder(); - test.printTo(LocalDate.of(2008, 6, 30), buf); + test.formatTo(LocalDate.of(2008, 6, 30), buf); assertEquals(buf.toString(), "ONE30"); } @@ -268,33 +258,117 @@ public class TCKDateTimeFormatter { public void test_print_TemporalAppendable_noSuchField() throws Exception { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); StringBuilder buf = new StringBuilder(); - test.printTo(LocalTime.of(11, 30), buf); + test.formatTo(LocalTime.of(11, 30), buf); } @Test(expectedExceptions=NullPointerException.class) public void test_print_TemporalAppendable_nullTemporal() throws Exception { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); StringBuilder buf = new StringBuilder(); - test.printTo((TemporalAccessor) null, buf); + test.formatTo((TemporalAccessor) null, buf); } @Test(expectedExceptions=NullPointerException.class) public void test_print_TemporalAppendable_nullAppendable() throws Exception { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - test.printTo(LocalDate.of(2008, 6, 30), (Appendable) null); + test.formatTo(LocalDate.of(2008, 6, 30), (Appendable) null); } - @Test(expectedExceptions=IOException.class) // IOException - public void test_print_TemporalAppendable_ioError() throws Exception { + //----------------------------------------------------------------------- + // parse(CharSequence) + //----------------------------------------------------------------------- + @Test + public void test_parse_CharSequence() { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + TemporalAccessor result = test.parse("ONE30"); + assertEquals(result.isSupported(DAY_OF_MONTH), true); + assertEquals(result.getLong(DAY_OF_MONTH), 30L); + assertEquals(result.isSupported(HOUR_OF_DAY), false); + } + + @Test + public void test_parse_CharSequence_resolved() { + DateTimeFormatter test = DateTimeFormatter.ISO_DATE; + TemporalAccessor result = test.parse("2012-06-30"); + assertEquals(result.isSupported(YEAR), true); + assertEquals(result.isSupported(MONTH_OF_YEAR), true); + assertEquals(result.isSupported(DAY_OF_MONTH), true); + assertEquals(result.isSupported(HOUR_OF_DAY), false); + assertEquals(result.getLong(YEAR), 2012L); + assertEquals(result.getLong(MONTH_OF_YEAR), 6L); + assertEquals(result.getLong(DAY_OF_MONTH), 30L); + assertEquals(result.query(LocalDate::from), LocalDate.of(2012, 6, 30)); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_parse_CharSequence_null() { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + test.parse((String) null); + } + + //----------------------------------------------------------------------- + // parse(CharSequence) + //----------------------------------------------------------------------- + @Test + public void test_parse_CharSequence_ParsePosition() { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + ParsePosition pos = new ParsePosition(3); + TemporalAccessor result = test.parse("XXXONE30XXX", pos); + assertEquals(pos.getIndex(), 8); + assertEquals(pos.getErrorIndex(), -1); + assertEquals(result.isSupported(DAY_OF_MONTH), true); + assertEquals(result.getLong(DAY_OF_MONTH), 30L); + assertEquals(result.isSupported(HOUR_OF_DAY), false); + } + + @Test + public void test_parse_CharSequence_ParsePosition_resolved() { + DateTimeFormatter test = DateTimeFormatter.ISO_DATE; + ParsePosition pos = new ParsePosition(3); + TemporalAccessor result = test.parse("XXX2012-06-30XXX", pos); + assertEquals(pos.getIndex(), 13); + assertEquals(pos.getErrorIndex(), -1); + assertEquals(result.isSupported(YEAR), true); + assertEquals(result.isSupported(MONTH_OF_YEAR), true); + assertEquals(result.isSupported(DAY_OF_MONTH), true); + assertEquals(result.isSupported(HOUR_OF_DAY), false); + assertEquals(result.getLong(YEAR), 2012L); + assertEquals(result.getLong(MONTH_OF_YEAR), 6L); + assertEquals(result.getLong(DAY_OF_MONTH), 30L); + assertEquals(result.query(LocalDate::from), LocalDate.of(2012, 6, 30)); + } + + @Test(expectedExceptions=DateTimeParseException.class) + public void test_parse_CharSequence_ParsePosition_parseError() { + DateTimeFormatter test = DateTimeFormatter.ISO_DATE; + ParsePosition pos = new ParsePosition(3); try { - test.printTo(LocalDate.of(2008, 6, 30), new MockIOExceptionAppendable()); - } catch (DateTimePrintException ex) { - assertEquals(ex.getCause() instanceof IOException, true); - ex.rethrowIOException(); + test.parse("XXX2012XXX", pos); + fail(); + } catch (DateTimeParseException ex) { + assertEquals(ex.getErrorIndex(), 7); + throw ex; } } + @Test(expectedExceptions=IndexOutOfBoundsException.class) + public void test_parse_CharSequence_ParsePosition_indexTooBig() { + DateTimeFormatter test = DateTimeFormatter.ISO_DATE; + test.parse("Text", new ParsePosition(5)); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_parse_CharSequence_ParsePosition_nullText() { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + test.parse((CharSequence) null, new ParsePosition(0)); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_parse_CharSequence_ParsePosition_nullParsePosition() { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + test.parse("Text", (ParsePosition) null); + } + //----------------------------------------------------------------------- // parse(Query) //----------------------------------------------------------------------- @@ -363,23 +437,24 @@ public class TCKDateTimeFormatter { //----------------------------------------------------------------------- @Test public void test_parseBest_firstOption() throws Exception { - DateTimeFormatter test = DateTimeFormatters.pattern("yyyy-MM-dd[ZZZ]"); - TemporalAccessor result = test.parseBest("2011-06-30+03:00", OffsetDate::from, LocalDate::from); - assertEquals(result, OffsetDate.of(LocalDate.of(2011, 6, 30), ZoneOffset.ofHours(3))); + DateTimeFormatter test = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm[XXX]"); + TemporalAccessor result = test.parseBest("2011-06-30 12:30+03:00", ZonedDateTime::from, LocalDateTime::from); + LocalDateTime ldt = LocalDateTime.of(2011, 6, 30, 12, 30); + assertEquals(result, ZonedDateTime.of(ldt, ZoneOffset.ofHours(3))); } @Test public void test_parseBest_secondOption() throws Exception { - DateTimeFormatter test = DateTimeFormatters.pattern("yyyy-MM-dd[ZZZ]"); - TemporalAccessor result = test.parseBest("2011-06-30", OffsetDate::from, LocalDate::from); + DateTimeFormatter test = DateTimeFormatter.ofPattern("yyyy-MM-dd[ HH:mm[XXX]]"); + TemporalAccessor result = test.parseBest("2011-06-30", ZonedDateTime::from, LocalDate::from); assertEquals(result, LocalDate.of(2011, 6, 30)); } @Test(expectedExceptions=DateTimeParseException.class) public void test_parseBest_String_parseError() throws Exception { - DateTimeFormatter test = DateTimeFormatters.pattern("yyyy-MM-dd[ZZZ]"); + DateTimeFormatter test = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm[XXX]"); try { - test.parseBest("2011-06-XX", OffsetDate::from, LocalDate::from); + test.parseBest("2011-06-XX", ZonedDateTime::from, LocalDateTime::from); } catch (DateTimeParseException ex) { assertEquals(ex.getMessage().contains("could not be parsed"), true); assertEquals(ex.getMessage().contains("XX"), true); @@ -393,7 +468,7 @@ public class TCKDateTimeFormatter { public void test_parseBest_String_parseErrorLongText() throws Exception { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); try { - test.parseBest("ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789", LocalDate::from, OffsetDate::from); + test.parseBest("ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789", ZonedDateTime::from, LocalDate::from); } catch (DateTimeParseException ex) { assertEquals(ex.getMessage().contains("could not be parsed"), true); assertEquals(ex.getMessage().contains("ONEXXX6789012345678901234567890123456789012345678901234567890123..."), true); @@ -407,7 +482,7 @@ public class TCKDateTimeFormatter { public void test_parseBest_String_parseIncomplete() throws Exception { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); try { - test.parseBest("ONE30SomethingElse", LocalDate::from, OffsetDate::from); + test.parseBest("ONE30SomethingElse", ZonedDateTime::from, LocalDate::from); } catch (DateTimeParseException ex) { assertEquals(ex.getMessage().contains("could not be parsed"), true); assertEquals(ex.getMessage().contains("ONE30SomethingElse"), true); @@ -420,7 +495,7 @@ public class TCKDateTimeFormatter { @Test(expectedExceptions=NullPointerException.class) public void test_parseBest_String_nullText() throws Exception { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - test.parseBest((String) null, LocalDate::from, OffsetDate::from); + test.parseBest((String) null, ZonedDateTime::from, LocalDate::from); } @Test(expectedExceptions=NullPointerException.class) @@ -443,108 +518,65 @@ public class TCKDateTimeFormatter { //----------------------------------------------------------------------- @Test - public void test_parseToBuilder_String() throws Exception { - DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - DateTimeBuilder result = test.parseToBuilder("ONE30"); - assertEquals(result.getFieldValueMap().size(), 1); - assertEquals(result.getFieldValue(DAY_OF_MONTH), 30L); - assertEquals(result.getCalendricalList().size(), 0); - } - - @Test - public void test_parseToBuilder_CharSequence() throws Exception { - DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - DateTimeBuilder result = test.parseToBuilder(new StringBuilder("ONE30")); - assertEquals(result.getFieldValueMap().size(), 1); - assertEquals(result.getFieldValue(DAY_OF_MONTH), 30L); - assertEquals(result.getCalendricalList().size(), 0); - } - - @Test(expectedExceptions=DateTimeParseException.class) - public void test_parseToBuilder_String_parseError() throws Exception { - DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - try { - test.parseToBuilder("ONEXXX"); - } catch (DateTimeParseException ex) { - assertEquals(ex.getMessage().contains("ONEXXX"), true); - assertEquals(ex.getParsedString(), "ONEXXX"); - assertEquals(ex.getErrorIndex(), 3); - throw ex; - } - } - - @Test(expectedExceptions=DateTimeParseException.class) - public void test_parseToBuilder_String_parseErrorLongText() throws Exception { - DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - try { - test.parseToBuilder("ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789"); - } catch (DateTimeParseException ex) { - assertEquals(ex.getMessage().contains("ONEXXX6789012345678901234567890123456789012345678901234567890123..."), true); - assertEquals(ex.getParsedString(), "ONEXXX67890123456789012345678901234567890123456789012345678901234567890123456789"); - assertEquals(ex.getErrorIndex(), 3); - throw ex; - } - } - - @Test(expectedExceptions=DateTimeParseException.class) - public void test_parseToBuilder_String_parseIncomplete() throws Exception { - DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - try { - test.parseToBuilder("ONE30SomethingElse"); - } catch (DateTimeParseException ex) { - assertEquals(ex.getMessage().contains("ONE30SomethingElse"), true); - assertEquals(ex.getParsedString(), "ONE30SomethingElse"); - assertEquals(ex.getErrorIndex(), 5); - throw ex; - } - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_parseToBuilder_String_null() throws Exception { - DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - test.parseToBuilder((String) null); - } - - //----------------------------------------------------------------------- - @Test - public void test_parseToBuilder_StringParsePosition() throws Exception { + public void test_parseUnresolved_StringParsePosition() { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); ParsePosition pos = new ParsePosition(0); - DateTimeBuilder result = test.parseToBuilder("ONE30XXX", pos); + TemporalAccessor result = test.parseUnresolved("ONE30XXX", pos); assertEquals(pos.getIndex(), 5); assertEquals(pos.getErrorIndex(), -1); - assertEquals(result.getFieldValueMap().size(), 1); - assertEquals(result.getFieldValueMap().get(DAY_OF_MONTH), Long.valueOf(30)); + assertEquals(result.getLong(DAY_OF_MONTH), 30L); } @Test - public void test_parseToBuilder_StringParsePosition_parseError() throws Exception { + public void test_parseUnresolved_StringParsePosition_parseError() { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); ParsePosition pos = new ParsePosition(0); - DateTimeBuilder result = test.parseToBuilder("ONEXXX", pos); - assertEquals(pos.getIndex(), 0); // TODO: is this right? + TemporalAccessor result = test.parseUnresolved("ONEXXX", pos); + assertEquals(pos.getIndex(), 0); assertEquals(pos.getErrorIndex(), 3); assertEquals(result, null); } - @Test(expectedExceptions=NullPointerException.class) - public void test_parseToBuilder_StringParsePosition_nullString() throws Exception { - DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - ParsePosition pos = new ParsePosition(0); - test.parseToBuilder((String) null, pos); + @Test + public void test_parseUnresolved_StringParsePosition_duplicateFieldSameValue() { + DateTimeFormatter test = new DateTimeFormatterBuilder() + .appendValue(MONTH_OF_YEAR).appendLiteral('-').appendValue(MONTH_OF_YEAR).toFormatter(); + ParsePosition pos = new ParsePosition(3); + TemporalAccessor result = test.parseUnresolved("XXX6-6", pos); + assertEquals(pos.getIndex(), 6); + assertEquals(pos.getErrorIndex(), -1); + assertEquals(result.getLong(MONTH_OF_YEAR), 6); + } + + @Test + public void test_parseUnresolved_StringParsePosition_duplicateFieldDifferentValue() { + DateTimeFormatter test = new DateTimeFormatterBuilder() + .appendValue(MONTH_OF_YEAR).appendLiteral('-').appendValue(MONTH_OF_YEAR).toFormatter(); + ParsePosition pos = new ParsePosition(3); + TemporalAccessor result = test.parseUnresolved("XXX6-7", pos); + assertEquals(pos.getIndex(), 3); + assertEquals(pos.getErrorIndex(), 5); + assertEquals(result, null); } @Test(expectedExceptions=NullPointerException.class) - public void test_parseToBuilder_StringParsePosition_nullParsePosition() throws Exception { + public void test_parseUnresolved_StringParsePosition_nullString() { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); - test.parseToBuilder("ONE30", (ParsePosition) null); + ParsePosition pos = new ParsePosition(0); + test.parseUnresolved((String) null, pos); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_parseUnresolved_StringParsePosition_nullParsePosition() { + DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); + test.parseUnresolved("ONE30", (ParsePosition) null); } @Test(expectedExceptions=IndexOutOfBoundsException.class) - public void test_parseToBuilder_StringParsePosition_invalidPosition() throws Exception { + public void test_parseUnresolved_StringParsePosition_invalidPosition() { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); ParsePosition pos = new ParsePosition(6); - test.parseToBuilder("ONE30", pos); + test.parseUnresolved("ONE30", pos); } //----------------------------------------------------------------------- @@ -576,9 +608,9 @@ public class TCKDateTimeFormatter { public void test_toFormat_parseObject_String() throws Exception { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); Format format = test.toFormat(); - DateTimeBuilder result = (DateTimeBuilder) format.parseObject("ONE30"); - assertEquals(result.getFieldValueMap().size(), 1); - assertEquals(result.getFieldValue(DAY_OF_MONTH), 30L); + TemporalAccessor result = (TemporalAccessor) format.parseObject("ONE30"); + assertEquals(result.isSupported(DAY_OF_MONTH), true); + assertEquals(result.getLong(DAY_OF_MONTH), 30L); } @Test(expectedExceptions=ParseException.class) @@ -621,11 +653,11 @@ public class TCKDateTimeFormatter { DateTimeFormatter test = fmt.withLocale(Locale.ENGLISH).withSymbols(DateTimeFormatSymbols.STANDARD); Format format = test.toFormat(); ParsePosition pos = new ParsePosition(0); - DateTimeBuilder result = (DateTimeBuilder) format.parseObject("ONE30XXX", pos); + TemporalAccessor result = (TemporalAccessor) format.parseObject("ONE30XXX", pos); assertEquals(pos.getIndex(), 5); assertEquals(pos.getErrorIndex(), -1); - assertEquals(result.getFieldValueMap().size(), 1); - assertEquals(result.getFieldValue(DAY_OF_MONTH), 30L); + assertEquals(result.isSupported(DAY_OF_MONTH), true); + assertEquals(result.getLong(DAY_OF_MONTH), 30L); } @Test diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java index 1fe79b165eb..0cb5cb1c7a3 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatterBuilder.java @@ -59,25 +59,24 @@ */ package tck.java.time.format; -import java.time.LocalDate; -import java.time.ZoneOffset; -import java.time.format.*; - import static java.time.temporal.ChronoField.DAY_OF_MONTH; -import static java.time.temporal.ChronoField.DAY_OF_WEEK; import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.YEAR; import static org.testng.Assert.assertEquals; -import java.text.ParsePosition; +import java.time.LocalDate; +import java.time.YearMonth; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.SignStyle; +import java.time.format.TextStyle; +import java.time.temporal.Temporal; import java.util.HashMap; import java.util.Locale; import java.util.Map; -import java.time.format.DateTimeBuilder; -import java.time.temporal.Temporal; - import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -90,238 +89,116 @@ public class TCKDateTimeFormatterBuilder { private DateTimeFormatterBuilder builder; - @BeforeMethod(groups={"tck"}) + @BeforeMethod public void setUp() { builder = new DateTimeFormatterBuilder(); } //----------------------------------------------------------------------- - @Test(groups={"tck"}) + @Test public void test_toFormatter_empty() throws Exception { DateTimeFormatter f = builder.toFormatter(); assertEquals(f.toString(), ""); } //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_parseCaseSensitive() throws Exception { - builder.parseCaseSensitive(); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "ParseCaseSensitive(true)"); - } - - @Test(groups={"tck"}) - public void test_parseCaseInsensitive() throws Exception { - builder.parseCaseInsensitive(); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "ParseCaseSensitive(false)"); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_parseStrict() throws Exception { - builder.parseStrict(); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "ParseStrict(true)"); - } - - @Test(groups={"tck"}) - public void test_parseLenient() throws Exception { - builder.parseLenient(); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "ParseStrict(false)"); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_appendValue_1arg() throws Exception { - builder.appendValue(DAY_OF_MONTH); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(DayOfMonth)"); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendValue_1arg_null() throws Exception { builder.appendValue(null); } //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_appendValue_2arg() throws Exception { - builder.appendValue(DAY_OF_MONTH, 3); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(DayOfMonth,3)"); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendValue_2arg_null() throws Exception { builder.appendValue(null, 3); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendValue_2arg_widthTooSmall() throws Exception { builder.appendValue(DAY_OF_MONTH, 0); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendValue_2arg_widthTooBig() throws Exception { builder.appendValue(DAY_OF_MONTH, 20); } //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_appendValue_3arg() throws Exception { - builder.appendValue(DAY_OF_MONTH, 2, 3, SignStyle.NORMAL); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(DayOfMonth,2,3,NORMAL)"); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendValue_3arg_nullField() throws Exception { builder.appendValue(null, 2, 3, SignStyle.NORMAL); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendValue_3arg_minWidthTooSmall() throws Exception { builder.appendValue(DAY_OF_MONTH, 0, 2, SignStyle.NORMAL); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendValue_3arg_minWidthTooBig() throws Exception { builder.appendValue(DAY_OF_MONTH, 20, 2, SignStyle.NORMAL); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendValue_3arg_maxWidthTooSmall() throws Exception { builder.appendValue(DAY_OF_MONTH, 2, 0, SignStyle.NORMAL); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendValue_3arg_maxWidthTooBig() throws Exception { builder.appendValue(DAY_OF_MONTH, 2, 20, SignStyle.NORMAL); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendValue_3arg_maxWidthMinWidth() throws Exception { builder.appendValue(DAY_OF_MONTH, 4, 2, SignStyle.NORMAL); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendValue_3arg_nullSignStyle() throws Exception { builder.appendValue(DAY_OF_MONTH, 2, 3, null); } //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_appendValue_subsequent2_parse3() throws Exception { - builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)"); - DateTimeBuilder cal = f.parseToBuilder("123", new ParsePosition(0)); - assertEquals(cal.getFieldValueMap().get(MONTH_OF_YEAR), Long.valueOf(1)); - assertEquals(cal.getFieldValueMap().get(DAY_OF_MONTH), Long.valueOf(23)); - } - - @Test(groups={"tck"}) - public void test_appendValue_subsequent2_parse4() throws Exception { - builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)"); - DateTimeBuilder cal = f.parseToBuilder("0123", new ParsePosition(0)); - assertEquals(cal.getFieldValueMap().get(MONTH_OF_YEAR), Long.valueOf(1)); - assertEquals(cal.getFieldValueMap().get(DAY_OF_MONTH), Long.valueOf(23)); - } - - @Test(groups={"tck"}) - public void test_appendValue_subsequent2_parse5() throws Exception { - builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2).appendLiteral('4'); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)'4'"); - DateTimeBuilder cal = f.parseToBuilder("01234", new ParsePosition(0)); - assertEquals(cal.getFieldValueMap().get(MONTH_OF_YEAR), Long.valueOf(1)); - assertEquals(cal.getFieldValueMap().get(DAY_OF_MONTH), Long.valueOf(23)); - } - - @Test(groups={"tck"}) - public void test_appendValue_subsequent3_parse6() throws Exception { - builder - .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) - .appendValue(MONTH_OF_YEAR, 2) - .appendValue(DAY_OF_MONTH, 2); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(Year,4,10,EXCEEDS_PAD)Value(MonthOfYear,2)Value(DayOfMonth,2)"); - DateTimeBuilder cal = f.parseToBuilder("20090630", new ParsePosition(0)); - assertEquals(cal.getFieldValueMap().get(YEAR), Long.valueOf(2009)); - assertEquals(cal.getFieldValueMap().get(MONTH_OF_YEAR), Long.valueOf(6)); - assertEquals(cal.getFieldValueMap().get(DAY_OF_MONTH), Long.valueOf(30)); - } - - //----------------------------------------------------------------------- - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendValueReduced_null() throws Exception { builder.appendValueReduced(null, 2, 2000); } - @Test(groups={"tck"}) - public void test_appendValueReduced() throws Exception { - builder.appendValueReduced(YEAR, 2, 2000); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "ReducedValue(Year,2,2000)"); - DateTimeBuilder cal = f.parseToBuilder("12", new ParsePosition(0)); - assertEquals(cal.getFieldValueMap().get(YEAR), Long.valueOf(2012)); - } - - @Test(groups={"tck"}) - public void test_appendValueReduced_subsequent_parse() throws Exception { - builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValueReduced(YEAR, 2, 2000); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)ReducedValue(Year,2,2000)"); - DateTimeBuilder cal = f.parseToBuilder("123", new ParsePosition(0)); - assertEquals(cal.getFieldValueMap().get(MONTH_OF_YEAR), Long.valueOf(1)); - assertEquals(cal.getFieldValueMap().get(YEAR), Long.valueOf(2023)); - } - //----------------------------------------------------------------------- //----------------------------------------------------------------------- //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_appendFraction_4arg() throws Exception { - builder.appendFraction(MINUTE_OF_HOUR, 1, 9, false); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Fraction(MinuteOfHour,1,9)"); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendFraction_4arg_nullRule() throws Exception { builder.appendFraction(null, 1, 9, false); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendFraction_4arg_invalidRuleNotFixedSet() throws Exception { builder.appendFraction(DAY_OF_MONTH, 1, 9, false); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendFraction_4arg_minTooSmall() throws Exception { builder.appendFraction(MINUTE_OF_HOUR, -1, 9, false); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendFraction_4arg_minTooBig() throws Exception { builder.appendFraction(MINUTE_OF_HOUR, 10, 9, false); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendFraction_4arg_maxTooSmall() throws Exception { builder.appendFraction(MINUTE_OF_HOUR, 0, -1, false); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendFraction_4arg_maxTooBig() throws Exception { builder.appendFraction(MINUTE_OF_HOUR, 1, 10, false); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_appendFraction_4arg_maxWidthMinWidth() throws Exception { builder.appendFraction(MINUTE_OF_HOUR, 9, 3, false); } @@ -329,63 +206,29 @@ public class TCKDateTimeFormatterBuilder { //----------------------------------------------------------------------- //----------------------------------------------------------------------- //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_appendText_1arg() throws Exception { - builder.appendText(MONTH_OF_YEAR); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Text(MonthOfYear)"); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendText_1arg_null() throws Exception { builder.appendText(null); } //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_appendText_2arg() throws Exception { - builder.appendText(MONTH_OF_YEAR, TextStyle.SHORT); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Text(MonthOfYear,SHORT)"); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendText_2arg_nullRule() throws Exception { builder.appendText(null, TextStyle.SHORT); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendText_2arg_nullStyle() throws Exception { builder.appendText(MONTH_OF_YEAR, (TextStyle) null); } //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_appendTextMap() throws Exception { - Map map = new HashMap(); - map.put(1L, "JNY"); - map.put(2L, "FBY"); - map.put(3L, "MCH"); - map.put(4L, "APL"); - map.put(5L, "MAY"); - map.put(6L, "JUN"); - map.put(7L, "JLY"); - map.put(8L, "AGT"); - map.put(9L, "SPT"); - map.put(10L, "OBR"); - map.put(11L, "NVR"); - map.put(12L, "DBR"); - builder.appendText(MONTH_OF_YEAR, map); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Text(MonthOfYear)"); // TODO: toString should be different? - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendTextMap_nullRule() throws Exception { - builder.appendText(null, new HashMap()); + builder.appendText(null, new HashMap<>()); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendTextMap_nullStyle() throws Exception { builder.appendText(MONTH_OF_YEAR, (Map) null); } @@ -393,13 +236,6 @@ public class TCKDateTimeFormatterBuilder { //----------------------------------------------------------------------- //----------------------------------------------------------------------- //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_appendOffsetId() throws Exception { - builder.appendOffsetId(); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Offset('Z',+HH:MM:ss)"); - } - @DataProvider(name="offsetPatterns") Object[][] data_offsetPatterns() { return new Object[][] { @@ -447,21 +283,20 @@ public class TCKDateTimeFormatterBuilder { }; } - @Test(dataProvider="offsetPatterns", groups={"tck"}) - public void test_appendOffset_print(String pattern, int h, int m, int s, String expected) throws Exception { + @Test(dataProvider="offsetPatterns") + public void test_appendOffset_format(String pattern, int h, int m, int s, String expected) throws Exception { builder.appendOffset(pattern, "Z"); DateTimeFormatter f = builder.toFormatter(); ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(h, m, s); - assertEquals(f.print(offset), expected); + assertEquals(f.format(offset), expected); } - @Test(dataProvider="offsetPatterns", groups={"tck"}) + @Test(dataProvider="offsetPatterns") public void test_appendOffset_parse(String pattern, int h, int m, int s, String expected) throws Exception { builder.appendOffset(pattern, "Z"); DateTimeFormatter f = builder.toFormatter(); - ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(h, m, s); ZoneOffset parsed = f.parse(expected, ZoneOffset::from); - assertEquals(f.print(parsed), expected); + assertEquals(f.format(parsed), expected); } @DataProvider(name="badOffsetPatterns") @@ -481,17 +316,17 @@ public class TCKDateTimeFormatterBuilder { }; } - @Test(dataProvider="badOffsetPatterns", expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(dataProvider="badOffsetPatterns", expectedExceptions=IllegalArgumentException.class) public void test_appendOffset_badPattern(String pattern) throws Exception { builder.appendOffset(pattern, "Z"); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendOffset_3arg_nullText() throws Exception { builder.appendOffset("+HH:MM", null); } - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendOffset_3arg_nullPattern() throws Exception { builder.appendOffset(null, "Z"); } @@ -499,21 +334,7 @@ public class TCKDateTimeFormatterBuilder { //----------------------------------------------------------------------- //----------------------------------------------------------------------- //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_appendZoneId() throws Exception { - builder.appendZoneId(); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "ZoneId()"); - } - - @Test(groups={"tck"}) - public void test_appendZoneText_1arg() throws Exception { - builder.appendZoneText(TextStyle.FULL); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "ZoneText(FULL)"); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) + @Test(expectedExceptions=NullPointerException.class) public void test_appendZoneText_1arg_nullText() throws Exception { builder.appendZoneText(null); } @@ -521,101 +342,43 @@ public class TCKDateTimeFormatterBuilder { //----------------------------------------------------------------------- //----------------------------------------------------------------------- //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_padNext_1arg() throws Exception { - builder.appendValue(MONTH_OF_YEAR).padNext(2).appendValue(DAY_OF_MONTH).appendValue(DAY_OF_WEEK); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear)Pad(Value(DayOfMonth),2)Value(DayOfWeek)"); + @Test + public void test_padNext_1arg() { + builder.appendValue(MONTH_OF_YEAR).appendLiteral(':').padNext(2).appendValue(DAY_OF_MONTH); + assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2: 1"); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_padNext_1arg_invalidWidth() throws Exception { builder.padNext(0); } //----------------------------------------------------------------------- - @Test(groups={"tck"}) + @Test public void test_padNext_2arg_dash() throws Exception { - builder.appendValue(MONTH_OF_YEAR).padNext(2, '-').appendValue(DAY_OF_MONTH).appendValue(DAY_OF_WEEK); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear)Pad(Value(DayOfMonth),2,'-')Value(DayOfWeek)"); + builder.appendValue(MONTH_OF_YEAR).appendLiteral(':').padNext(2, '-').appendValue(DAY_OF_MONTH); + assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2:-1"); } - @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalArgumentException.class) public void test_padNext_2arg_invalidWidth() throws Exception { builder.padNext(0, '-'); } //----------------------------------------------------------------------- - @Test(groups={"tck"}) + @Test public void test_padOptional() throws Exception { - builder.appendValue(MONTH_OF_YEAR).padNext(5).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd().appendValue(DAY_OF_WEEK); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear)Pad([Value(DayOfMonth)],5)Value(DayOfWeek)"); + builder.appendValue(MONTH_OF_YEAR).appendLiteral(':') + .padNext(5).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd() + .appendLiteral(':').appendValue(YEAR); + assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2: 1:2013"); + assertEquals(builder.toFormatter().format(YearMonth.of(2013, 2)), "2: :2013"); } //----------------------------------------------------------------------- //----------------------------------------------------------------------- //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_optionalStart_noEnd() throws Exception { - builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).appendValue(DAY_OF_WEEK); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)Value(DayOfWeek)]"); - } - - @Test(groups={"tck"}) - public void test_optionalStart2_noEnd() throws Exception { - builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).optionalStart().appendValue(DAY_OF_WEEK); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)[Value(DayOfWeek)]]"); - } - - @Test(groups={"tck"}) - public void test_optionalStart_doubleStart() throws Exception { - builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]"); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_optionalEnd() throws Exception { - builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd().appendValue(DAY_OF_WEEK); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)]Value(DayOfWeek)"); - } - - @Test(groups={"tck"}) - public void test_optionalEnd2() throws Exception { - builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH) - .optionalStart().appendValue(DAY_OF_WEEK).optionalEnd().appendValue(DAY_OF_MONTH).optionalEnd(); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)[Value(DayOfWeek)]Value(DayOfMonth)]"); - } - - @Test(groups={"tck"}) - public void test_optionalEnd_doubleStartSingleEnd() throws Exception { - builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH).optionalEnd(); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]"); - } - - @Test(groups={"tck"}) - public void test_optionalEnd_doubleStartDoubleEnd() throws Exception { - builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH).optionalEnd().optionalEnd(); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]"); - } - - @Test(groups={"tck"}) - public void test_optionalStartEnd_immediateStartEnd() throws Exception { - builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalEnd().appendValue(DAY_OF_MONTH); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), "Value(MonthOfYear)Value(DayOfMonth)"); - } - - @Test(expectedExceptions=IllegalStateException.class, groups={"tck"}) + @Test(expectedExceptions=IllegalStateException.class) public void test_optionalEnd_noStart() throws Exception { builder.optionalEnd(); } @@ -626,157 +389,149 @@ public class TCKDateTimeFormatterBuilder { @DataProvider(name="validPatterns") Object[][] dataValid() { return new Object[][] { - {"'a'", "'a'"}, - {"''", "''"}, - {"'!'", "'!'"}, - {"!", "'!'"}, + {"'a'"}, + {"''"}, + {"'!'"}, + {"!"}, - {"'hello_people,][)('", "'hello_people,][)('"}, - {"'hi'", "'hi'"}, - {"'yyyy'", "'yyyy'"}, - {"''''", "''"}, - {"'o''clock'", "'o''clock'"}, + {"'hello_people,][)('"}, + {"'hi'"}, + {"'yyyy'"}, + {"''''"}, + {"'o''clock'"}, - {"G", "Value(Era)"}, - {"GG", "Value(Era,2)"}, - {"GGG", "Text(Era,SHORT)"}, - {"GGGG", "Text(Era)"}, - {"GGGGG", "Text(Era,NARROW)"}, + {"G"}, + {"GG"}, + {"GGG"}, + {"GGGG"}, + {"GGGGG"}, - {"y", "Value(Year)"}, - {"yy", "ReducedValue(Year,2,2000)"}, - {"yyy", "Value(Year,3,19,NORMAL)"}, - {"yyyy", "Value(Year,4,19,EXCEEDS_PAD)"}, - {"yyyyy", "Value(Year,5,19,EXCEEDS_PAD)"}, + {"y"}, + {"yy"}, + {"yyy"}, + {"yyyy"}, + {"yyyyy"}, -// {"Y", "Value(WeekBasedYear)"}, -// {"YY", "ReducedValue(WeekBasedYear,2,2000)"}, -// {"YYY", "Value(WeekBasedYear,3,19,NORMAL)"}, -// {"YYYY", "Value(WeekBasedYear,4,19,EXCEEDS_PAD)"}, -// {"YYYYY", "Value(WeekBasedYear,5,19,EXCEEDS_PAD)"}, + {"M"}, + {"MM"}, + {"MMM"}, + {"MMMM"}, + {"MMMMM"}, - {"M", "Value(MonthOfYear)"}, - {"MM", "Value(MonthOfYear,2)"}, - {"MMM", "Text(MonthOfYear,SHORT)"}, - {"MMMM", "Text(MonthOfYear)"}, - {"MMMMM", "Text(MonthOfYear,NARROW)"}, + {"D"}, + {"DD"}, + {"DDD"}, - {"D", "Value(DayOfYear)"}, - {"DD", "Value(DayOfYear,2)"}, - {"DDD", "Value(DayOfYear,3)"}, + {"d"}, + {"dd"}, + {"ddd"}, - {"d", "Value(DayOfMonth)"}, - {"dd", "Value(DayOfMonth,2)"}, - {"ddd", "Value(DayOfMonth,3)"}, + {"F"}, + {"FF"}, + {"FFF"}, - {"F", "Value(AlignedWeekOfMonth)"}, - {"FF", "Value(AlignedWeekOfMonth,2)"}, - {"FFF", "Value(AlignedWeekOfMonth,3)"}, + {"Q"}, + {"QQ"}, + {"QQQ"}, + {"QQQQ"}, + {"QQQQQ"}, - {"Q", "Value(QuarterOfYear)"}, - {"QQ", "Value(QuarterOfYear,2)"}, - {"QQQ", "Text(QuarterOfYear,SHORT)"}, - {"QQQQ", "Text(QuarterOfYear)"}, - {"QQQQQ", "Text(QuarterOfYear,NARROW)"}, + {"E"}, + {"EE"}, + {"EEE"}, + {"EEEE"}, + {"EEEEE"}, - {"E", "Value(DayOfWeek)"}, - {"EE", "Value(DayOfWeek,2)"}, - {"EEE", "Text(DayOfWeek,SHORT)"}, - {"EEEE", "Text(DayOfWeek)"}, - {"EEEEE", "Text(DayOfWeek,NARROW)"}, + {"a"}, + {"aa"}, + {"aaa"}, + {"aaaa"}, + {"aaaaa"}, - {"a", "Text(AmPmOfDay,SHORT)"}, - {"aa", "Text(AmPmOfDay,SHORT)"}, - {"aaa", "Text(AmPmOfDay,SHORT)"}, - {"aaaa", "Text(AmPmOfDay)"}, - {"aaaaa", "Text(AmPmOfDay,NARROW)"}, + {"H"}, + {"HH"}, + {"HHH"}, - {"H", "Value(HourOfDay)"}, - {"HH", "Value(HourOfDay,2)"}, - {"HHH", "Value(HourOfDay,3)"}, + {"K"}, + {"KK"}, + {"KKK"}, - {"K", "Value(HourOfAmPm)"}, - {"KK", "Value(HourOfAmPm,2)"}, - {"KKK", "Value(HourOfAmPm,3)"}, + {"k"}, + {"kk"}, + {"kkk"}, - {"k", "Value(ClockHourOfDay)"}, - {"kk", "Value(ClockHourOfDay,2)"}, - {"kkk", "Value(ClockHourOfDay,3)"}, + {"h"}, + {"hh"}, + {"hhh"}, - {"h", "Value(ClockHourOfAmPm)"}, - {"hh", "Value(ClockHourOfAmPm,2)"}, - {"hhh", "Value(ClockHourOfAmPm,3)"}, + {"m"}, + {"mm"}, + {"mmm"}, - {"m", "Value(MinuteOfHour)"}, - {"mm", "Value(MinuteOfHour,2)"}, - {"mmm", "Value(MinuteOfHour,3)"}, + {"s"}, + {"ss"}, + {"sss"}, - {"s", "Value(SecondOfMinute)"}, - {"ss", "Value(SecondOfMinute,2)"}, - {"sss", "Value(SecondOfMinute,3)"}, + {"S"}, + {"SS"}, + {"SSS"}, + {"SSSSSSSSS"}, - {"S", "Fraction(NanoOfSecond,1,1)"}, - {"SS", "Fraction(NanoOfSecond,2,2)"}, - {"SSS", "Fraction(NanoOfSecond,3,3)"}, - {"SSSSSSSSS", "Fraction(NanoOfSecond,9,9)"}, + {"A"}, + {"AA"}, + {"AAA"}, - {"A", "Value(MilliOfDay)"}, - {"AA", "Value(MilliOfDay,2)"}, - {"AAA", "Value(MilliOfDay,3)"}, + {"n"}, + {"nn"}, + {"nnn"}, - {"n", "Value(NanoOfSecond)"}, - {"nn", "Value(NanoOfSecond,2)"}, - {"nnn", "Value(NanoOfSecond,3)"}, + {"N"}, + {"NN"}, + {"NNN"}, - {"N", "Value(NanoOfDay)"}, - {"NN", "Value(NanoOfDay,2)"}, - {"NNN", "Value(NanoOfDay,3)"}, + {"z"}, + {"zz"}, + {"zzz"}, + {"zzzz"}, - {"z", "ZoneText(SHORT)"}, - {"zz", "ZoneText(SHORT)"}, - {"zzz", "ZoneText(SHORT)"}, - {"zzzz", "ZoneText(FULL)"}, - {"zzzzz", "ZoneText(FULL)"}, + {"VV"}, - {"I", "ZoneId()"}, - {"II", "ZoneId()"}, - {"III", "ZoneId()"}, - {"IIII", "ZoneId()"}, - {"IIIII", "ZoneId()"}, + {"Z"}, + {"ZZ"}, + {"ZZZ"}, - {"Z", "Offset('+0000',+HHMM)"}, // SimpleDateFormat compatible - {"ZZ", "Offset('+0000',+HHMM)"}, - {"ZZZ", "Offset('+00:00',+HH:MM)"}, + {"X"}, + {"XX"}, + {"XXX"}, + {"XXXX"}, + {"XXXXX"}, - {"X", "Offset('Z',+HH)"}, - {"XX", "Offset('Z',+HHMM)"}, - {"XXX", "Offset('Z',+HH:MM)"}, - {"XXXX", "Offset('Z',+HHMMss)"}, - {"XXXXX", "Offset('Z',+HH:MM:ss)"}, + {"x"}, + {"xx"}, + {"xxx"}, + {"xxxx"}, + {"xxxxx"}, - {"ppH", "Pad(Value(HourOfDay),2)"}, - {"pppDD", "Pad(Value(DayOfYear,2),3)"}, + {"ppH"}, + {"pppDD"}, - {"yyyy[-MM[-dd", "Value(Year,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"}, - {"yyyy[-MM[-dd]]", "Value(Year,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"}, - {"yyyy[-MM[]-dd]", "Value(Year,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)]"}, + {"yyyy[-MM[-dd"}, + {"yyyy[-MM[-dd]]"}, + {"yyyy[-MM[]-dd]"}, - {"yyyy-MM-dd'T'HH:mm:ss.SSS", "Value(Year,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)" + - "'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)'.'Fraction(NanoOfSecond,3,3)"}, + {"yyyy-MM-dd'T'HH:mm:ss.SSS"}, - {"e", "WeekBased(e1)"}, - {"w", "WeekBased(w1)"}, - {"W", "WeekBased(W1)"}, - {"WW", "WeekBased(W2)"}, + {"e"}, + {"w"}, + {"W"}, + {"WW"}, }; } - @Test(dataProvider="validPatterns", groups={"implementation"}) - public void test_appendPattern_valid(String input, String expected) throws Exception { - builder.appendPattern(input); - DateTimeFormatter f = builder.toFormatter(); - assertEquals(f.toString(), expected); + @Test(dataProvider="validPatterns") + public void test_appendPattern_valid(String input) throws Exception { + builder.appendPattern(input); // test is for no error here } //----------------------------------------------------------------------- @@ -801,6 +556,7 @@ public class TCKDateTimeFormatterBuilder { {"aaaaaa"}, {"ZZZZ"}, {"XXXXXX"}, + {"zzzzz"}, {"RO"}, @@ -821,13 +577,9 @@ public class TCKDateTimeFormatterBuilder { }; } - @Test(dataProvider="invalidPatterns", expectedExceptions=IllegalArgumentException.class, groups={"tck"}) + @Test(dataProvider="invalidPatterns", expectedExceptions=IllegalArgumentException.class) public void test_appendPattern_invalid(String input) throws Exception { - try { - builder.appendPattern(input); - } catch (IllegalArgumentException ex) { - throw ex; - } + builder.appendPattern(input); // test is for error here } //----------------------------------------------------------------------- @@ -842,10 +594,10 @@ public class TCKDateTimeFormatterBuilder { }; } - @Test(dataProvider="patternPrint", groups={"tck"}) + @Test(dataProvider="patternPrint") public void test_appendPattern_patternPrint(String input, Temporal temporal, String expected) throws Exception { DateTimeFormatter f = builder.appendPattern(input).toFormatter(Locale.UK); - String test = f.print(temporal); + String test = f.format(temporal); assertEquals(test, expected); } diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatters.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatters.java index cbb79b981b9..45548772f50 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatters.java +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeFormatters.java @@ -74,37 +74,33 @@ import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import java.text.ParsePosition; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; - import java.time.DateTimeException; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.Year; +import java.time.YearMonth; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; -import java.time.format.DateTimeBuilder; +import java.time.chrono.Chronology; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; import java.time.format.DateTimeParseException; -import java.time.format.DateTimePrintException; -import java.time.temporal.ISOFields; +import java.time.temporal.IsoFields; import java.time.temporal.Queries; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; import java.time.temporal.TemporalQuery; -import java.time.temporal.Year; -import java.time.temporal.YearMonth; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** - * Test DateTimeFormatters. + * Test DateTimeFormatter. */ @Test public class TCKDateTimeFormatters { @@ -116,7 +112,7 @@ public class TCKDateTimeFormatters { //----------------------------------------------------------------------- @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_print_nullCalendrical() { - DateTimeFormatters.isoDate().print((TemporalAccessor) null); + DateTimeFormatter.ISO_DATE.format((TemporalAccessor) null); } //----------------------------------------------------------------------- @@ -124,19 +120,19 @@ public class TCKDateTimeFormatters { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_pattern_String() { - DateTimeFormatter test = DateTimeFormatters.pattern("d MMM yyyy"); + DateTimeFormatter test = DateTimeFormatter.ofPattern("d MMM yyyy"); assertEquals(test.toString(), "Value(DayOfMonth)' 'Text(MonthOfYear,SHORT)' 'Value(Year,4,19,EXCEEDS_PAD)"); assertEquals(test.getLocale(), Locale.getDefault()); } @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) public void test_pattern_String_invalid() { - DateTimeFormatters.pattern("p"); + DateTimeFormatter.ofPattern("p"); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_pattern_String_null() { - DateTimeFormatters.pattern(null); + DateTimeFormatter.ofPattern(null); } //----------------------------------------------------------------------- @@ -144,24 +140,24 @@ public class TCKDateTimeFormatters { //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_pattern_StringLocale() { - DateTimeFormatter test = DateTimeFormatters.pattern("d MMM yyyy", Locale.UK); + DateTimeFormatter test = DateTimeFormatter.ofPattern("d MMM yyyy", Locale.UK); assertEquals(test.toString(), "Value(DayOfMonth)' 'Text(MonthOfYear,SHORT)' 'Value(Year,4,19,EXCEEDS_PAD)"); assertEquals(test.getLocale(), Locale.UK); } @Test(expectedExceptions=IllegalArgumentException.class, groups={"tck"}) public void test_pattern_StringLocale_invalid() { - DateTimeFormatters.pattern("p", Locale.UK); + DateTimeFormatter.ofPattern("p", Locale.UK); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_pattern_StringLocale_nullPattern() { - DateTimeFormatters.pattern(null, Locale.UK); + DateTimeFormatter.ofPattern(null, Locale.UK); } @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) public void test_pattern_StringLocale_nullLocale() { - DateTimeFormatters.pattern("yyyy", null); + DateTimeFormatter.ofPattern("yyyy", null); } //----------------------------------------------------------------------- @@ -193,10 +189,10 @@ public class TCKDateTimeFormatters { String expected, Class expectedEx) { TemporalAccessor test = buildAccessor(year, month, day, null, null, null, null, offsetId, zoneId); if (expectedEx == null) { - assertEquals(DateTimeFormatters.isoLocalDate().print(test), expected); + assertEquals(DateTimeFormatter.ISO_LOCAL_DATE.format(test), expected); } else { try { - DateTimeFormatters.isoLocalDate().print(test); + DateTimeFormatter.ISO_LOCAL_DATE.format(test); fail(); } catch (Exception ex) { assertTrue(expectedEx.isInstance(ex)); @@ -209,23 +205,23 @@ public class TCKDateTimeFormatters { Integer year, Integer month, Integer day, String offsetId, String zoneId, String input, Class invalid) { if (input != null) { - DateTimeBuilder expected = createDate(year, month, day); + Expected expected = createDate(year, month, day); // offset/zone not expected to be parsed - assertParseMatch(DateTimeFormatters.isoLocalDate().parseToBuilder(input, new ParsePosition(0)), expected); + assertParseMatch(DateTimeFormatter.ISO_LOCAL_DATE.parseUnresolved(input, new ParsePosition(0)), expected); } } @Test(groups={"tck"}) public void test_parse_isoLocalDate_999999999() { - DateTimeBuilder expected = createDate(999999999, 8, 6); - assertParseMatch(DateTimeFormatters.isoLocalDate().parseToBuilder("+999999999-08-06", new ParsePosition(0)), expected); + Expected expected = createDate(999999999, 8, 6); + assertParseMatch(DateTimeFormatter.ISO_LOCAL_DATE.parseUnresolved("+999999999-08-06", new ParsePosition(0)), expected); assertEquals(LocalDate.parse("+999999999-08-06"), LocalDate.of(999999999, 8, 6)); } @Test(groups={"tck"}) public void test_parse_isoLocalDate_1000000000() { - DateTimeBuilder expected = createDate(1000000000, 8, 6); - assertParseMatch(DateTimeFormatters.isoLocalDate().parseToBuilder("+1000000000-08-06", new ParsePosition(0)), expected); + Expected expected = createDate(1000000000, 8, 6); + assertParseMatch(DateTimeFormatter.ISO_LOCAL_DATE.parseUnresolved("+1000000000-08-06", new ParsePosition(0)), expected); } @Test(expectedExceptions = DateTimeException.class, groups={"tck"}) @@ -235,15 +231,15 @@ public class TCKDateTimeFormatters { @Test(groups={"tck"}) public void test_parse_isoLocalDate_M999999999() { - DateTimeBuilder expected = createDate(-999999999, 8, 6); - assertParseMatch(DateTimeFormatters.isoLocalDate().parseToBuilder("-999999999-08-06", new ParsePosition(0)), expected); + Expected expected = createDate(-999999999, 8, 6); + assertParseMatch(DateTimeFormatter.ISO_LOCAL_DATE.parseUnresolved("-999999999-08-06", new ParsePosition(0)), expected); assertEquals(LocalDate.parse("-999999999-08-06"), LocalDate.of(-999999999, 8, 6)); } @Test(groups={"tck"}) public void test_parse_isoLocalDate_M1000000000() { - DateTimeBuilder expected = createDate(-1000000000, 8, 6); - assertParseMatch(DateTimeFormatters.isoLocalDate().parseToBuilder("-1000000000-08-06", new ParsePosition(0)), expected); + Expected expected = createDate(-1000000000, 8, 6); + assertParseMatch(DateTimeFormatter.ISO_LOCAL_DATE.parseUnresolved("-1000000000-08-06", new ParsePosition(0)), expected); } @Test(expectedExceptions = DateTimeException.class, groups={"tck"}) @@ -280,10 +276,10 @@ public class TCKDateTimeFormatters { String expected, Class expectedEx) { TemporalAccessor test = buildAccessor(year, month, day, null, null, null, null, offsetId, zoneId); if (expectedEx == null) { - assertEquals(DateTimeFormatters.isoOffsetDate().print(test), expected); + assertEquals(DateTimeFormatter.ISO_OFFSET_DATE.format(test), expected); } else { try { - DateTimeFormatters.isoOffsetDate().print(test); + DateTimeFormatter.ISO_OFFSET_DATE.format(test); fail(); } catch (Exception ex) { assertTrue(expectedEx.isInstance(ex)); @@ -296,9 +292,9 @@ public class TCKDateTimeFormatters { Integer year, Integer month, Integer day, String offsetId, String zoneId, String input, Class invalid) { if (input != null) { - DateTimeBuilder expected = createDate(year, month, day); + Expected expected = createDate(year, month, day); buildCalendrical(expected, offsetId, null); // zone not expected to be parsed - assertParseMatch(DateTimeFormatters.isoOffsetDate().parseToBuilder(input, new ParsePosition(0)), expected); + assertParseMatch(DateTimeFormatter.ISO_OFFSET_DATE.parseUnresolved(input, new ParsePosition(0)), expected); } } @@ -331,10 +327,10 @@ public class TCKDateTimeFormatters { String expected, Class expectedEx) { TemporalAccessor test = buildAccessor(year, month, day, null, null, null, null, offsetId, zoneId); if (expectedEx == null) { - assertEquals(DateTimeFormatters.isoDate().print(test), expected); + assertEquals(DateTimeFormatter.ISO_DATE.format(test), expected); } else { try { - DateTimeFormatters.isoDate().print(test); + DateTimeFormatter.ISO_DATE.format(test); fail(); } catch (Exception ex) { assertTrue(expectedEx.isInstance(ex)); @@ -347,11 +343,11 @@ public class TCKDateTimeFormatters { Integer year, Integer month, Integer day, String offsetId, String zoneId, String input, Class invalid) { if (input != null) { - DateTimeBuilder expected = createDate(year, month, day); + Expected expected = createDate(year, month, day); if (offsetId != null) { - expected.addFieldValue(OFFSET_SECONDS, ZoneOffset.of(offsetId).getTotalSeconds()); + expected.add(ZoneOffset.of(offsetId)); } - assertParseMatch(DateTimeFormatters.isoDate().parseToBuilder(input, new ParsePosition(0)), expected); + assertParseMatch(DateTimeFormatter.ISO_DATE.parseUnresolved(input, new ParsePosition(0)), expected); } } @@ -396,10 +392,10 @@ public class TCKDateTimeFormatters { String expected, Class expectedEx) { TemporalAccessor test = buildAccessor(null, null, null, hour, min, sec, nano, offsetId, zoneId); if (expectedEx == null) { - assertEquals(DateTimeFormatters.isoLocalTime().print(test), expected); + assertEquals(DateTimeFormatter.ISO_LOCAL_TIME.format(test), expected); } else { try { - DateTimeFormatters.isoLocalTime().print(test); + DateTimeFormatter.ISO_LOCAL_TIME.format(test); fail(); } catch (Exception ex) { assertTrue(expectedEx.isInstance(ex)); @@ -412,9 +408,9 @@ public class TCKDateTimeFormatters { Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, String input, Class invalid) { if (input != null) { - DateTimeBuilder expected = createTime(hour, min, sec, nano); + Expected expected = createTime(hour, min, sec, nano); // offset/zone not expected to be parsed - assertParseMatch(DateTimeFormatters.isoLocalTime().parseToBuilder(input, new ParsePosition(0)), expected); + assertParseMatch(DateTimeFormatter.ISO_LOCAL_TIME.parseUnresolved(input, new ParsePosition(0)), expected); } } @@ -459,10 +455,10 @@ public class TCKDateTimeFormatters { String expected, Class expectedEx) { TemporalAccessor test = buildAccessor(null, null, null, hour, min, sec, nano, offsetId, zoneId); if (expectedEx == null) { - assertEquals(DateTimeFormatters.isoOffsetTime().print(test), expected); + assertEquals(DateTimeFormatter.ISO_OFFSET_TIME.format(test), expected); } else { try { - DateTimeFormatters.isoOffsetTime().print(test); + DateTimeFormatter.ISO_OFFSET_TIME.format(test); fail(); } catch (Exception ex) { assertTrue(expectedEx.isInstance(ex)); @@ -475,9 +471,9 @@ public class TCKDateTimeFormatters { Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, String input, Class invalid) { if (input != null) { - DateTimeBuilder expected = createTime(hour, min, sec, nano); + Expected expected = createTime(hour, min, sec, nano); buildCalendrical(expected, offsetId, null); // zoneId is not expected from parse - assertParseMatch(DateTimeFormatters.isoOffsetTime().parseToBuilder(input, new ParsePosition(0)), expected); + assertParseMatch(DateTimeFormatter.ISO_OFFSET_TIME.parseUnresolved(input, new ParsePosition(0)), expected); } } @@ -522,10 +518,10 @@ public class TCKDateTimeFormatters { String expected, Class expectedEx) { TemporalAccessor test = buildAccessor(null, null, null, hour, min, sec, nano, offsetId, zoneId); if (expectedEx == null) { - assertEquals(DateTimeFormatters.isoTime().print(test), expected); + assertEquals(DateTimeFormatter.ISO_TIME.format(test), expected); } else { try { - DateTimeFormatters.isoTime().print(test); + DateTimeFormatter.ISO_TIME.format(test); fail(); } catch (Exception ex) { assertTrue(expectedEx.isInstance(ex)); @@ -538,11 +534,11 @@ public class TCKDateTimeFormatters { Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, String input, Class invalid) { if (input != null) { - DateTimeBuilder expected = createTime(hour, min, sec, nano); + Expected expected = createTime(hour, min, sec, nano); if (offsetId != null) { - expected.addFieldValue(OFFSET_SECONDS, ZoneOffset.of(offsetId).getTotalSeconds()); + expected.add(ZoneOffset.of(offsetId)); } - assertParseMatch(DateTimeFormatters.isoTime().parseToBuilder(input, new ParsePosition(0)), expected); + assertParseMatch(DateTimeFormatter.ISO_TIME.parseUnresolved(input, new ParsePosition(0)), expected); } } @@ -596,10 +592,10 @@ public class TCKDateTimeFormatters { String expected, Class expectedEx) { TemporalAccessor test = buildAccessor(year, month, day, hour, min, sec, nano, offsetId, zoneId); if (expectedEx == null) { - assertEquals(DateTimeFormatters.isoLocalDateTime().print(test), expected); + assertEquals(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(test), expected); } else { try { - DateTimeFormatters.isoLocalDateTime().print(test); + DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(test); fail(); } catch (Exception ex) { assertTrue(expectedEx.isInstance(ex)); @@ -613,8 +609,8 @@ public class TCKDateTimeFormatters { Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, String input, Class invalid) { if (input != null) { - DateTimeBuilder expected = createDateTime(year, month, day, hour, min, sec, nano); - assertParseMatch(DateTimeFormatters.isoLocalDateTime().parseToBuilder(input, new ParsePosition(0)), expected); + Expected expected = createDateTime(year, month, day, hour, min, sec, nano); + assertParseMatch(DateTimeFormatter.ISO_LOCAL_DATE_TIME.parseUnresolved(input, new ParsePosition(0)), expected); } } @@ -668,10 +664,10 @@ public class TCKDateTimeFormatters { String expected, Class expectedEx) { TemporalAccessor test = buildAccessor(year, month, day, hour, min, sec, nano, offsetId, zoneId); if (expectedEx == null) { - assertEquals(DateTimeFormatters.isoOffsetDateTime().print(test), expected); + assertEquals(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(test), expected); } else { try { - DateTimeFormatters.isoOffsetDateTime().print(test); + DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(test); fail(); } catch (Exception ex) { assertTrue(expectedEx.isInstance(ex)); @@ -685,9 +681,9 @@ public class TCKDateTimeFormatters { Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, String input, Class invalid) { if (input != null) { - DateTimeBuilder expected = createDateTime(year, month, day, hour, min, sec, nano); + Expected expected = createDateTime(year, month, day, hour, min, sec, nano); buildCalendrical(expected, offsetId, null); // zone not expected to be parsed - assertParseMatch(DateTimeFormatters.isoOffsetDateTime().parseToBuilder(input, new ParsePosition(0)), expected); + assertParseMatch(DateTimeFormatter.ISO_OFFSET_DATE_TIME.parseUnresolved(input, new ParsePosition(0)), expected); } } @@ -750,10 +746,10 @@ public class TCKDateTimeFormatters { String expected, Class expectedEx) { TemporalAccessor test = buildAccessor(year, month, day, hour, min, sec, nano, offsetId, zoneId); if (expectedEx == null) { - assertEquals(DateTimeFormatters.isoZonedDateTime().print(test), expected); + assertEquals(DateTimeFormatter.ISO_ZONED_DATE_TIME.format(test), expected); } else { try { - DateTimeFormatters.isoZonedDateTime().print(test); + DateTimeFormatter.ISO_ZONED_DATE_TIME.format(test); fail(test.toString()); } catch (Exception ex) { assertTrue(expectedEx.isInstance(ex)); @@ -767,13 +763,13 @@ public class TCKDateTimeFormatters { Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, String input, Class invalid) { if (input != null) { - DateTimeBuilder expected = createDateTime(year, month, day, hour, min, sec, nano); + Expected expected = createDateTime(year, month, day, hour, min, sec, nano); if (offsetId.equals(zoneId)) { buildCalendrical(expected, offsetId, null); } else { buildCalendrical(expected, offsetId, zoneId); } - assertParseMatch(DateTimeFormatters.isoZonedDateTime().parseToBuilder(input, new ParsePosition(0)), expected); + assertParseMatch(DateTimeFormatter.ISO_ZONED_DATE_TIME.parseUnresolved(input, new ParsePosition(0)), expected); } } @@ -827,10 +823,10 @@ public class TCKDateTimeFormatters { String expected, Class expectedEx) { TemporalAccessor test = buildAccessor(year, month, day, hour, min, sec, nano, offsetId, zoneId); if (expectedEx == null) { - assertEquals(DateTimeFormatters.isoDateTime().print(test), expected); + assertEquals(DateTimeFormatter.ISO_DATE_TIME.format(test), expected); } else { try { - DateTimeFormatters.isoDateTime().print(test); + DateTimeFormatter.ISO_DATE_TIME.format(test); fail(); } catch (Exception ex) { assertTrue(expectedEx.isInstance(ex)); @@ -844,14 +840,14 @@ public class TCKDateTimeFormatters { Integer hour, Integer min, Integer sec, Integer nano, String offsetId, String zoneId, String input, Class invalid) { if (input != null) { - DateTimeBuilder expected = createDateTime(year, month, day, hour, min, sec, nano); + Expected expected = createDateTime(year, month, day, hour, min, sec, nano); if (offsetId != null) { - expected.addFieldValue(OFFSET_SECONDS, ZoneOffset.of(offsetId).getTotalSeconds()); + expected.add(ZoneOffset.of(offsetId)); if (zoneId != null) { - expected.addCalendrical(ZoneId.of(zoneId)); + expected.zone = ZoneId.of(zoneId); } } - assertParseMatch(DateTimeFormatters.isoDateTime().parseToBuilder(input, new ParsePosition(0)), expected); + assertParseMatch(DateTimeFormatter.ISO_DATE_TIME.parseUnresolved(input, new ParsePosition(0)), expected); } } @@ -861,50 +857,66 @@ public class TCKDateTimeFormatters { @Test(groups={"tck"}) public void test_print_isoOrdinalDate() { TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), null, null); - assertEquals(DateTimeFormatters.isoOrdinalDate().print(test), "2008-155"); + assertEquals(DateTimeFormatter.ISO_ORDINAL_DATE.format(test), "2008-155"); } @Test(groups={"tck"}) public void test_print_isoOrdinalDate_offset() { TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), "Z", null); - assertEquals(DateTimeFormatters.isoOrdinalDate().print(test), "2008-155Z"); + assertEquals(DateTimeFormatter.ISO_ORDINAL_DATE.format(test), "2008-155Z"); } @Test(groups={"tck"}) public void test_print_isoOrdinalDate_zoned() { TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), "+02:00", "Europe/Paris"); - assertEquals(DateTimeFormatters.isoOrdinalDate().print(test), "2008-155+02:00"); + assertEquals(DateTimeFormatter.ISO_ORDINAL_DATE.format(test), "2008-155+02:00"); } @Test(groups={"tck"}) public void test_print_isoOrdinalDate_zoned_largeYear() { TemporalAccessor test = buildAccessor(LocalDateTime.of(123456, 6, 3, 11, 5, 30), "Z", null); - assertEquals(DateTimeFormatters.isoOrdinalDate().print(test), "+123456-155Z"); + assertEquals(DateTimeFormatter.ISO_ORDINAL_DATE.format(test), "+123456-155Z"); } - @Test(groups={"tck"}) + @Test public void test_print_isoOrdinalDate_fields() { - TemporalAccessor test = new DateTimeBuilder(YEAR, 2008).addFieldValue(DAY_OF_YEAR, 231); - assertEquals(DateTimeFormatters.isoOrdinalDate().print(test), "2008-231"); + // mock for testing that does not fully comply with TemporalAccessor contract + TemporalAccessor test = new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + return field == YEAR || field == DAY_OF_YEAR; + } + @Override + public long getLong(TemporalField field) { + if (field == YEAR) { + return 2008; + } + if (field == DAY_OF_YEAR) { + return 231; + } + throw new DateTimeException("Unsupported"); + } + }; + assertEquals(DateTimeFormatter.ISO_ORDINAL_DATE.format(test), "2008-231"); } - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) + @Test(expectedExceptions=DateTimeException.class) public void test_print_isoOrdinalDate_missingField() { TemporalAccessor test = Year.of(2008); - DateTimeFormatters.isoOrdinalDate().print(test); + DateTimeFormatter.ISO_ORDINAL_DATE.format(test); } //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_parse_isoOrdinalDate() { - DateTimeBuilder expected = new DateTimeBuilder(YEAR, 2008).addFieldValue(DAY_OF_YEAR, 123); - assertParseMatch(DateTimeFormatters.isoOrdinalDate().parseToBuilder("2008-123", new ParsePosition(0)), expected); + Expected expected = new Expected(YEAR, 2008, DAY_OF_YEAR, 123); + assertParseMatch(DateTimeFormatter.ISO_ORDINAL_DATE.parseUnresolved("2008-123", new ParsePosition(0)), expected); } @Test(groups={"tck"}) public void test_parse_isoOrdinalDate_largeYear() { - DateTimeBuilder expected = new DateTimeBuilder(YEAR, 123456).addFieldValue(DAY_OF_YEAR, 123); - assertParseMatch(DateTimeFormatters.isoOrdinalDate().parseToBuilder("+123456-123", new ParsePosition(0)), expected); + Expected expected = new Expected(YEAR, 123456, DAY_OF_YEAR, 123); + assertParseMatch(DateTimeFormatter.ISO_ORDINAL_DATE.parseUnresolved("+123456-123", new ParsePosition(0)), expected); } //----------------------------------------------------------------------- @@ -913,51 +925,51 @@ public class TCKDateTimeFormatters { @Test(groups={"tck"}) public void test_print_basicIsoDate() { TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), null, null); - assertEquals(DateTimeFormatters.basicIsoDate().print(test), "20080603"); + assertEquals(DateTimeFormatter.BASIC_ISO_DATE.format(test), "20080603"); } @Test(groups={"tck"}) public void test_print_basicIsoDate_offset() { TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), "Z", null); - assertEquals(DateTimeFormatters.basicIsoDate().print(test), "20080603Z"); + assertEquals(DateTimeFormatter.BASIC_ISO_DATE.format(test), "20080603Z"); } @Test(groups={"tck"}) public void test_print_basicIsoDate_zoned() { TemporalAccessor test = buildAccessor(LocalDateTime.of(2008, 6, 3, 11, 5, 30), "+02:00", "Europe/Paris"); - assertEquals(DateTimeFormatters.basicIsoDate().print(test), "20080603+0200"); + assertEquals(DateTimeFormatter.BASIC_ISO_DATE.format(test), "20080603+0200"); } - @Test(expectedExceptions=DateTimePrintException.class, groups={"tck"}) + @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) public void test_print_basicIsoDate_largeYear() { TemporalAccessor test = buildAccessor(LocalDateTime.of(123456, 6, 3, 11, 5, 30), "Z", null); - DateTimeFormatters.basicIsoDate().print(test); + DateTimeFormatter.BASIC_ISO_DATE.format(test); } @Test(groups={"tck"}) public void test_print_basicIsoDate_fields() { TemporalAccessor test = buildAccessor(LocalDate.of(2008, 6, 3), null, null); - assertEquals(DateTimeFormatters.basicIsoDate().print(test), "20080603"); + assertEquals(DateTimeFormatter.BASIC_ISO_DATE.format(test), "20080603"); } @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) public void test_print_basicIsoDate_missingField() { TemporalAccessor test = YearMonth.of(2008, 6); - DateTimeFormatters.basicIsoDate().print(test); + DateTimeFormatter.BASIC_ISO_DATE.format(test); } //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_parse_basicIsoDate() { LocalDate expected = LocalDate.of(2008, 6, 3); - assertEquals(DateTimeFormatters.basicIsoDate().parse("20080603", LocalDate::from), expected); + assertEquals(DateTimeFormatter.BASIC_ISO_DATE.parse("20080603", LocalDate::from), expected); } @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) public void test_parse_basicIsoDate_largeYear() { try { LocalDate expected = LocalDate.of(123456, 6, 3); - assertEquals(DateTimeFormatters.basicIsoDate().parse("+1234560603", LocalDate::from), expected); + assertEquals(DateTimeFormatter.BASIC_ISO_DATE.parse("+1234560603", LocalDate::from), expected); } catch (DateTimeParseException ex) { assertEquals(ex.getErrorIndex(), 0); assertEquals(ex.getParsedString(), "+1234560603"); @@ -1002,40 +1014,40 @@ public class TCKDateTimeFormatters { @Test(dataProvider="weekDate", groups={"tck"}) public void test_print_isoWeekDate(TemporalAccessor test, String expected) { - assertEquals(DateTimeFormatters.isoWeekDate().print(test), expected); + assertEquals(DateTimeFormatter.ISO_WEEK_DATE.format(test), expected); } @Test(groups={"tck"}) public void test_print_isoWeekDate_zoned_largeYear() { TemporalAccessor test = buildAccessor(LocalDateTime.of(123456, 6, 3, 11, 5, 30), "Z", null); - assertEquals(DateTimeFormatters.isoWeekDate().print(test), "+123456-W23-2Z"); + assertEquals(DateTimeFormatter.ISO_WEEK_DATE.format(test), "+123456-W23-2Z"); } @Test(groups={"tck"}) public void test_print_isoWeekDate_fields() { TemporalAccessor test = buildAccessor(LocalDate.of(2004, 1, 27), null, null); - assertEquals(DateTimeFormatters.isoWeekDate().print(test), "2004-W05-2"); + assertEquals(DateTimeFormatter.ISO_WEEK_DATE.format(test), "2004-W05-2"); } @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) public void test_print_isoWeekDate_missingField() { TemporalAccessor test = YearMonth.of(2008, 6); - DateTimeFormatters.isoWeekDate().print(test); + DateTimeFormatter.ISO_WEEK_DATE.format(test); } //----------------------------------------------------------------------- @Test(groups={"tck"}) public void test_parse_weekDate() { LocalDate expected = LocalDate.of(2004, 1, 28); - assertEquals(DateTimeFormatters.isoWeekDate().parse("2004-W05-3", LocalDate::from), expected); + assertEquals(DateTimeFormatter.ISO_WEEK_DATE.parse("2004-W05-3", LocalDate::from), expected); } @Test(groups={"tck"}) public void test_parse_weekDate_largeYear() { - DateTimeBuilder builder = DateTimeFormatters.isoWeekDate().parseToBuilder("+123456-W04-5", new ParsePosition(0)); - assertEquals(builder.getFieldValue(ISOFields.WEEK_BASED_YEAR), 123456); - assertEquals(builder.getFieldValue(ISOFields.WEEK_OF_WEEK_BASED_YEAR), 4); - assertEquals(builder.getFieldValue(DAY_OF_WEEK), 5); + TemporalAccessor parsed = DateTimeFormatter.ISO_WEEK_DATE.parseUnresolved("+123456-W04-5", new ParsePosition(0)); + assertEquals(parsed.getLong(IsoFields.WEEK_BASED_YEAR), 123456L); + assertEquals(parsed.getLong(IsoFields.WEEK_OF_WEEK_BASED_YEAR), 4L); + assertEquals(parsed.getLong(DAY_OF_WEEK), 5L); } //----------------------------------------------------------------------- @@ -1054,79 +1066,79 @@ public class TCKDateTimeFormatters { @Test(groups={"tck"}, dataProvider="rfc") public void test_print_rfc1123(LocalDateTime base, String offsetId, String expected) { TemporalAccessor test = buildAccessor(base, offsetId, null); - assertEquals(DateTimeFormatters.rfc1123().print(test), expected); + assertEquals(DateTimeFormatter.RFC_1123_DATE_TIME.format(test), expected); } @Test(groups={"tck"}, dataProvider="rfc") public void test_print_rfc1123_french(LocalDateTime base, String offsetId, String expected) { TemporalAccessor test = buildAccessor(base, offsetId, null); - assertEquals(DateTimeFormatters.rfc1123().withLocale(Locale.FRENCH).print(test), expected); + assertEquals(DateTimeFormatter.RFC_1123_DATE_TIME.withLocale(Locale.FRENCH).format(test), expected); } @Test(groups={"tck"}, expectedExceptions=DateTimeException.class) public void test_print_rfc1123_missingField() { TemporalAccessor test = YearMonth.of(2008, 6); - DateTimeFormatters.rfc1123().print(test); + DateTimeFormatter.RFC_1123_DATE_TIME.format(test); } //----------------------------------------------------------------------- //----------------------------------------------------------------------- //----------------------------------------------------------------------- - private DateTimeBuilder createDate(Integer year, Integer month, Integer day) { - DateTimeBuilder test = new DateTimeBuilder(); + private Expected createDate(Integer year, Integer month, Integer day) { + Expected test = new Expected(); if (year != null) { - test.addFieldValue(YEAR, year); + test.fieldValues.put(YEAR, (long) year); } if (month != null) { - test.addFieldValue(MONTH_OF_YEAR, month); + test.fieldValues.put(MONTH_OF_YEAR, (long) month); } if (day != null) { - test.addFieldValue(DAY_OF_MONTH, day); + test.fieldValues.put(DAY_OF_MONTH, (long) day); } return test; } - private DateTimeBuilder createTime(Integer hour, Integer min, Integer sec, Integer nano) { - DateTimeBuilder test = new DateTimeBuilder(); + private Expected createTime(Integer hour, Integer min, Integer sec, Integer nano) { + Expected test = new Expected(); if (hour != null) { - test.addFieldValue(HOUR_OF_DAY, hour); + test.fieldValues.put(HOUR_OF_DAY, (long) hour); } if (min != null) { - test.addFieldValue(MINUTE_OF_HOUR, min); + test.fieldValues.put(MINUTE_OF_HOUR, (long) min); } if (sec != null) { - test.addFieldValue(SECOND_OF_MINUTE, sec); + test.fieldValues.put(SECOND_OF_MINUTE, (long) sec); } if (nano != null) { - test.addFieldValue(NANO_OF_SECOND, nano); + test.fieldValues.put(NANO_OF_SECOND, (long) nano); } return test; } - private DateTimeBuilder createDateTime( + private Expected createDateTime( Integer year, Integer month, Integer day, Integer hour, Integer min, Integer sec, Integer nano) { - DateTimeBuilder test = new DateTimeBuilder(); + Expected test = new Expected(); if (year != null) { - test.addFieldValue(YEAR, year); + test.fieldValues.put(YEAR, (long) year); } if (month != null) { - test.addFieldValue(MONTH_OF_YEAR, month); + test.fieldValues.put(MONTH_OF_YEAR, (long) month); } if (day != null) { - test.addFieldValue(DAY_OF_MONTH, day); + test.fieldValues.put(DAY_OF_MONTH, (long) day); } if (hour != null) { - test.addFieldValue(HOUR_OF_DAY, hour); + test.fieldValues.put(HOUR_OF_DAY, (long) hour); } if (min != null) { - test.addFieldValue(MINUTE_OF_HOUR, min); + test.fieldValues.put(MINUTE_OF_HOUR, (long) min); } if (sec != null) { - test.addFieldValue(SECOND_OF_MINUTE, sec); + test.fieldValues.put(SECOND_OF_MINUTE, (long) sec); } if (nano != null) { - test.addFieldValue(NANO_OF_SECOND, nano); + test.fieldValues.put(NANO_OF_SECOND, (long) nano); } return test; } @@ -1178,23 +1190,22 @@ public class TCKDateTimeFormatters { return mock; } - private void buildCalendrical(DateTimeBuilder cal, String offsetId, String zoneId) { + private void buildCalendrical(Expected expected, String offsetId, String zoneId) { if (offsetId != null) { - cal.addFieldValue(OFFSET_SECONDS, ZoneOffset.of(offsetId).getTotalSeconds()); + expected.add(ZoneOffset.of(offsetId)); } if (zoneId != null) { - cal.addCalendrical(ZoneId.of(zoneId)); + expected.zone = ZoneId.of(zoneId); } } - private void assertParseMatch(DateTimeBuilder parsed, DateTimeBuilder expected) { - Map parsedFVMap = parsed.getFieldValueMap(); - Map expectedFVMap = expected.getFieldValueMap(); - assertEquals(parsedFVMap, expectedFVMap); - - List parsedCMap = parsed.getCalendricalList(); - List expectedCMap = expected.getCalendricalList(); - assertEquals(parsedCMap, expectedCMap); + private void assertParseMatch(TemporalAccessor parsed, Expected expected) { + for (TemporalField field : expected.fieldValues.keySet()) { + assertEquals(parsed.isSupported(field), true); + parsed.getLong(field); + } + assertEquals(parsed.query(Queries.chronology()), expected.chrono); + assertEquals(parsed.query(Queries.zoneId()), expected.zone); } //------------------------------------------------------------------------- @@ -1211,8 +1222,8 @@ public class TCKDateTimeFormatters { fields.put(DAY_OF_MONTH, (long) dt.getDayOfMonth()); fields.put(DAY_OF_YEAR, (long) dt.getDayOfYear()); fields.put(DAY_OF_WEEK, (long) dt.getDayOfWeek().getValue()); - fields.put(ISOFields.WEEK_BASED_YEAR, dt.getLong(ISOFields.WEEK_BASED_YEAR)); - fields.put(ISOFields.WEEK_OF_WEEK_BASED_YEAR, dt.getLong(ISOFields.WEEK_OF_WEEK_BASED_YEAR)); + fields.put(IsoFields.WEEK_BASED_YEAR, dt.getLong(IsoFields.WEEK_BASED_YEAR)); + fields.put(IsoFields.WEEK_OF_WEEK_BASED_YEAR, dt.getLong(IsoFields.WEEK_OF_WEEK_BASED_YEAR)); } } @@ -1223,8 +1234,8 @@ public class TCKDateTimeFormatters { fields.put(DAY_OF_MONTH, (long) dt.getDayOfMonth()); fields.put(DAY_OF_YEAR, (long) dt.getDayOfYear()); fields.put(DAY_OF_WEEK, (long) dt.getDayOfWeek().getValue()); - fields.put(ISOFields.WEEK_BASED_YEAR, dt.getLong(ISOFields.WEEK_BASED_YEAR)); - fields.put(ISOFields.WEEK_OF_WEEK_BASED_YEAR, dt.getLong(ISOFields.WEEK_OF_WEEK_BASED_YEAR)); + fields.put(IsoFields.WEEK_BASED_YEAR, dt.getLong(IsoFields.WEEK_BASED_YEAR)); + fields.put(IsoFields.WEEK_OF_WEEK_BASED_YEAR, dt.getLong(IsoFields.WEEK_OF_WEEK_BASED_YEAR)); fields.put(HOUR_OF_DAY, (long) dt.getHour()); fields.put(MINUTE_OF_HOUR, (long) dt.getMinute()); fields.put(SECOND_OF_MINUTE, (long) dt.getSecond()); @@ -1273,4 +1284,22 @@ public class TCKDateTimeFormatters { } } + //----------------------------------------------------------------------- + static class Expected { + Map fieldValues = new HashMap<>(); + ZoneId zone; + Chronology chrono; + + Expected() { + } + + Expected(TemporalField field1, long value1, TemporalField field2, long value2) { + fieldValues.put(field1, value1); + fieldValues.put(field2, value2); + } + + void add(ZoneOffset offset) { + fieldValues.put(OFFSET_SECONDS, (long) offset.getTotalSeconds()); + } + } } diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimePrintException.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimePrintException.java deleted file mode 100644 index 0117629f8cb..00000000000 --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimePrintException.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file: - * - * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of JSR-310 nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tck.java.time.format; - -import java.time.format.*; -import test.java.time.format.*; - -import static org.testng.Assert.assertEquals; - -import java.io.IOException; - -import org.testng.annotations.Test; - -/** - * Test DateTimePrintException. - */ -@Test -public class TCKDateTimePrintException { - - @Test(groups={"tck"}) - public void test_constructor_String() throws Exception { - DateTimePrintException ex = new DateTimePrintException("TEST"); - assertEquals(ex.getMessage(), "TEST"); - } - - @Test(groups={"tck"}) - public void test_constructor_StringThrowable_notIOException_equal() throws Exception { - IllegalArgumentException iaex = new IllegalArgumentException("INNER"); - DateTimePrintException ex = new DateTimePrintException("TEST", iaex); - assertEquals(ex.getMessage(), "TEST"); - assertEquals(ex.getCause(), iaex); - ex.rethrowIOException(); // no effect - } - - @Test(expectedExceptions=IOException.class, groups={"tck"}) - public void test_constructor_StringThrowable_IOException() throws Exception { - IOException ioex = new IOException("INNER"); - DateTimePrintException ex = new DateTimePrintException("TEST", ioex); - assertEquals(ex.getMessage(), "TEST"); - assertEquals(ex.getCause(), ioex); - ex.rethrowIOException(); // rethrows - } - -} diff --git a/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java b/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java index 5af0ebf41a9..d436fb41ad4 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java +++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java @@ -136,21 +136,21 @@ public class TCKDateTimeTextPrinting { } @Test(dataProvider="printText", groups={"tck"}) - public void test_appendText2arg_print(TemporalField field, TextStyle style, int value, String expected) throws Exception { + public void test_appendText2arg_format(TemporalField field, TextStyle style, int value, String expected) throws Exception { DateTimeFormatter f = builder.appendText(field, style).toFormatter(Locale.ENGLISH); LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0); dt = dt.with(field, value); - String text = f.print(dt); + String text = f.format(dt); assertEquals(text, expected); } @Test(dataProvider="printText", groups={"tck"}) - public void test_appendText1arg_print(TemporalField field, TextStyle style, int value, String expected) throws Exception { + public void test_appendText1arg_format(TemporalField field, TextStyle style, int value, String expected) throws Exception { if (style == TextStyle.FULL) { DateTimeFormatter f = builder.appendText(field).toFormatter(Locale.ENGLISH); LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0); dt = dt.with(field, value); - String text = f.print(dt); + String text = f.format(dt); assertEquals(text, expected); } } @@ -160,7 +160,7 @@ public class TCKDateTimeTextPrinting { public void test_print_appendText2arg_french_long() throws Exception { DateTimeFormatter f = builder.appendText(MONTH_OF_YEAR, TextStyle.FULL).toFormatter(Locale.FRENCH); LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0); - String text = f.print(dt); + String text = f.format(dt); assertEquals(text, "janvier"); } @@ -168,7 +168,7 @@ public class TCKDateTimeTextPrinting { public void test_print_appendText2arg_french_short() throws Exception { DateTimeFormatter f = builder.appendText(MONTH_OF_YEAR, TextStyle.SHORT).toFormatter(Locale.FRENCH); LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0); - String text = f.print(dt); + String text = f.format(dt); assertEquals(text, "janv."); } @@ -192,7 +192,7 @@ public class TCKDateTimeTextPrinting { DateTimeFormatter f = builder.toFormatter(); LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0); for (Month month : Month.values()) { - assertEquals(f.print(dt.with(month)), map.get((long) month.getValue())); + assertEquals(f.format(dt.with(month)), map.get((long) month.getValue())); } } @@ -205,9 +205,9 @@ public class TCKDateTimeTextPrinting { builder.appendText(DAY_OF_MONTH, map); DateTimeFormatter f = builder.toFormatter(); LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0); - assertEquals(f.print(dt.withDayOfMonth(1)), "1st"); - assertEquals(f.print(dt.withDayOfMonth(2)), "2nd"); - assertEquals(f.print(dt.withDayOfMonth(3)), "3rd"); + assertEquals(f.format(dt.withDayOfMonth(1)), "1st"); + assertEquals(f.format(dt.withDayOfMonth(2)), "2nd"); + assertEquals(f.format(dt.withDayOfMonth(3)), "3rd"); } @Test(groups={"tck"}) @@ -217,7 +217,7 @@ public class TCKDateTimeTextPrinting { builder.appendText(MONTH_OF_YEAR, map); DateTimeFormatter f = builder.toFormatter(); LocalDateTime dt = LocalDateTime.of(2010, 2, 1, 0, 0); - assertEquals(f.print(dt), "2"); + assertEquals(f.format(dt), "2"); } } diff --git a/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java b/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java index d6f5f1619bb..0d7975a8310 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java +++ b/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldParser.java @@ -59,22 +59,21 @@ */ package tck.java.time.format; -import java.time.format.*; - +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.YEAR; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; import java.text.ParsePosition; -import java.time.format.DateTimeBuilder; - import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; import java.time.temporal.WeekFields; -import test.java.time.format.AbstractTestPrinterParser; - import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import test.java.time.format.AbstractTestPrinterParser; /** * Test TCKLocalizedFieldParser. @@ -114,12 +113,12 @@ public class TCKLocalizedFieldParser extends AbstractTestPrinterParser { DateTimeFormatterBuilder b = new DateTimeFormatterBuilder().appendPattern(pattern); DateTimeFormatter dtf = b.toFormatter(locale); - DateTimeBuilder dtb = dtf.parseToBuilder(text, ppos); + TemporalAccessor parsed = dtf.parseUnresolved(text, ppos); if (ppos.getErrorIndex() != -1) { assertEquals(ppos.getErrorIndex(), expectedPos); } else { assertEquals(ppos.getIndex(), expectedPos, "Incorrect ending parse position"); - long value = dtb.getLong(field); + long value = parsed.getLong(field); assertEquals(value, expectedValue, "Value incorrect for " + field); } } @@ -143,20 +142,23 @@ public class TCKLocalizedFieldParser extends AbstractTestPrinterParser { "Date: 2012, day-of-week: 6, week-of-year: 29", 0, 44, LocalDate.of(2012, 7, 20)}, }; } + @Test(dataProvider="LocalDatePatterns",groups={"tck"}) public void test_parse_textLocalDate(String pattern, String text, int pos, int expectedPos, LocalDate expectedValue) { - WeekFields weekDef = WeekFields.of(locale); ParsePosition ppos = new ParsePosition(pos); - DateTimeFormatterBuilder b - = new DateTimeFormatterBuilder().appendPattern(pattern); + DateTimeFormatterBuilder b = new DateTimeFormatterBuilder().appendPattern(pattern); DateTimeFormatter dtf = b.toFormatter(locale); - DateTimeBuilder dtb = dtf.parseToBuilder(text, ppos); + TemporalAccessor parsed = dtf.parseUnresolved(text, ppos); if (ppos.getErrorIndex() != -1) { assertEquals(ppos.getErrorIndex(), expectedPos); } else { assertEquals(ppos.getIndex(), expectedPos, "Incorrect ending parse position"); - dtb.resolve(); - LocalDate result = dtb.query(LocalDate::from); + assertEquals(parsed.isSupported(YEAR), true); + assertEquals(parsed.isSupported(WeekFields.of(locale).dayOfWeek()), true); + assertEquals(parsed.isSupported(WeekFields.of(locale).weekOfMonth()) || + parsed.isSupported(WeekFields.of(locale).weekOfYear()), true); + // ensure combination resolves into a date + LocalDate result = LocalDate.parse(text, dtf); assertEquals(result, expectedValue, "LocalDate incorrect for " + pattern); } } diff --git a/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldPrinter.java b/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldPrinter.java index dac65b6b110..3be85a9a03c 100644 --- a/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldPrinter.java +++ b/jdk/test/java/time/tck/java/time/format/TCKLocalizedFieldPrinter.java @@ -98,7 +98,7 @@ public class TCKLocalizedFieldPrinter extends AbstractTestPrinterParser { = new DateTimeFormatterBuilder().appendPattern(pattern); LocalDate date = LocalDate.of(2012, 7, 20); - String result = b.toFormatter(locale).print(date); + String result = b.toFormatter(locale).format(date); assertEquals(result, expected, "Wrong output for pattern '" + pattern + "'."); } diff --git a/jdk/test/java/time/tck/java/time/format/TCKLocalizedPrinterParser.java b/jdk/test/java/time/tck/java/time/format/TCKLocalizedPrinterParser.java new file mode 100644 index 00000000000..cb348b264c3 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKLocalizedPrinterParser.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.format; + +import static org.testng.Assert.assertEquals; + +import java.text.DateFormat; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.FormatStyle; +import java.time.temporal.TemporalAccessor; +import java.util.Date; +import java.util.Locale; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test localized behavior of formatter. + */ +@Test +public class TCKLocalizedPrinterParser { + + private DateTimeFormatterBuilder builder; + private ParsePosition pos; + + @BeforeMethod + public void setUp() { + builder = new DateTimeFormatterBuilder(); + pos = new ParsePosition(0); + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_parse_negativePosition() { + builder.appendLocalized(null, null); + } + + //----------------------------------------------------------------------- + @DataProvider(name="date") + Object[][] data_date() { + return new Object[][] { + {LocalDate.of(2012, 6, 30), FormatStyle.SHORT, DateFormat.SHORT, Locale.UK}, + {LocalDate.of(2012, 6, 30), FormatStyle.SHORT, DateFormat.SHORT, Locale.US}, + {LocalDate.of(2012, 6, 30), FormatStyle.SHORT, DateFormat.SHORT, Locale.FRANCE}, + {LocalDate.of(2012, 6, 30), FormatStyle.SHORT, DateFormat.SHORT, Locale.JAPAN}, + + {LocalDate.of(2012, 6, 30), FormatStyle.MEDIUM, DateFormat.MEDIUM, Locale.UK}, + {LocalDate.of(2012, 6, 30), FormatStyle.MEDIUM, DateFormat.MEDIUM, Locale.US}, + {LocalDate.of(2012, 6, 30), FormatStyle.MEDIUM, DateFormat.MEDIUM, Locale.FRANCE}, + {LocalDate.of(2012, 6, 30), FormatStyle.MEDIUM, DateFormat.MEDIUM, Locale.JAPAN}, + + {LocalDate.of(2012, 6, 30), FormatStyle.LONG, DateFormat.LONG, Locale.UK}, + {LocalDate.of(2012, 6, 30), FormatStyle.LONG, DateFormat.LONG, Locale.US}, + {LocalDate.of(2012, 6, 30), FormatStyle.LONG, DateFormat.LONG, Locale.FRANCE}, + {LocalDate.of(2012, 6, 30), FormatStyle.LONG, DateFormat.LONG, Locale.JAPAN}, + + {LocalDate.of(2012, 6, 30), FormatStyle.FULL, DateFormat.FULL, Locale.UK}, + {LocalDate.of(2012, 6, 30), FormatStyle.FULL, DateFormat.FULL, Locale.US}, + {LocalDate.of(2012, 6, 30), FormatStyle.FULL, DateFormat.FULL, Locale.FRANCE}, + {LocalDate.of(2012, 6, 30), FormatStyle.FULL, DateFormat.FULL, Locale.JAPAN}, + }; + } + + @SuppressWarnings("deprecated") + @Test(dataProvider="date") + public void test_date_print(LocalDate date, FormatStyle dateStyle, int dateStyleOld, Locale locale) { + DateFormat old = DateFormat.getDateInstance(dateStyleOld, locale); + Date oldDate = new Date(date.getYear() - 1900, date.getMonthValue() - 1, date.getDayOfMonth()); + String text = old.format(oldDate); + + DateTimeFormatter f = builder.appendLocalized(dateStyle, null).toFormatter(locale); + String formatted = f.format(date); + assertEquals(formatted, text); + } + + @SuppressWarnings("deprecated") + @Test(dataProvider="date") + public void test_date_parse(LocalDate date, FormatStyle dateStyle, int dateStyleOld, Locale locale) { + DateFormat old = DateFormat.getDateInstance(dateStyleOld, locale); + Date oldDate = new Date(date.getYear() - 1900, date.getMonthValue() - 1, date.getDayOfMonth()); + String text = old.format(oldDate); + + DateTimeFormatter f = builder.appendLocalized(dateStyle, null).toFormatter(locale); + TemporalAccessor parsed = f.parse(text, pos); + assertEquals(pos.getIndex(), text.length()); + assertEquals(pos.getErrorIndex(), -1); + assertEquals(LocalDate.from(parsed), date); + } + + //----------------------------------------------------------------------- + @DataProvider(name="time") + Object[][] data_time() { + return new Object[][] { + {LocalTime.of(11, 30), FormatStyle.SHORT, DateFormat.SHORT, Locale.UK}, + {LocalTime.of(11, 30), FormatStyle.SHORT, DateFormat.SHORT, Locale.US}, + {LocalTime.of(11, 30), FormatStyle.SHORT, DateFormat.SHORT, Locale.FRANCE}, + {LocalTime.of(11, 30), FormatStyle.SHORT, DateFormat.SHORT, Locale.JAPAN}, + + {LocalTime.of(11, 30), FormatStyle.MEDIUM, DateFormat.MEDIUM, Locale.UK}, + {LocalTime.of(11, 30), FormatStyle.MEDIUM, DateFormat.MEDIUM, Locale.US}, + {LocalTime.of(11, 30), FormatStyle.MEDIUM, DateFormat.MEDIUM, Locale.FRANCE}, + {LocalTime.of(11, 30), FormatStyle.MEDIUM, DateFormat.MEDIUM, Locale.JAPAN}, + + // these localized patterns include "z" which isn't available from LocalTime +// {LocalTime.of(11, 30), FormatStyle.LONG, DateFormat.LONG, Locale.UK}, +// {LocalTime.of(11, 30), FormatStyle.LONG, DateFormat.LONG, Locale.US}, +// {LocalTime.of(11, 30), FormatStyle.LONG, DateFormat.LONG, Locale.FRANCE}, +// {LocalTime.of(11, 30), FormatStyle.LONG, DateFormat.LONG, Locale.JAPAN}, +// +// {LocalTime.of(11, 30), FormatStyle.FULL, DateFormat.FULL, Locale.UK}, +// {LocalTime.of(11, 30), FormatStyle.FULL, DateFormat.FULL, Locale.US}, +// {LocalTime.of(11, 30), FormatStyle.FULL, DateFormat.FULL, Locale.FRANCE}, +// {LocalTime.of(11, 30), FormatStyle.FULL, DateFormat.FULL, Locale.JAPAN}, + }; + } + + @SuppressWarnings("deprecated") + @Test(dataProvider="time") + public void test_time_print(LocalTime time, FormatStyle timeStyle, int timeStyleOld, Locale locale) { + DateFormat old = DateFormat.getTimeInstance(timeStyleOld, locale); + Date oldDate = new Date(1970, 0, 0, time.getHour(), time.getMinute(), time.getSecond()); + String text = old.format(oldDate); + + DateTimeFormatter f = builder.appendLocalized(null, timeStyle).toFormatter(locale); + String formatted = f.format(time); + assertEquals(formatted, text); + } + + @SuppressWarnings("deprecated") + @Test(dataProvider="time") + public void test_time_parse(LocalTime time, FormatStyle timeStyle, int timeStyleOld, Locale locale) { + DateFormat old = DateFormat.getTimeInstance(timeStyleOld, locale); + Date oldDate = new Date(1970, 0, 0, time.getHour(), time.getMinute(), time.getSecond()); + String text = old.format(oldDate); + + DateTimeFormatter f = builder.appendLocalized(null, timeStyle).toFormatter(locale); + TemporalAccessor parsed = f.parse(text, pos); + assertEquals(pos.getIndex(), text.length()); + assertEquals(pos.getErrorIndex(), -1); + assertEquals(LocalTime.from(parsed), time); + } + +} diff --git a/jdk/test/java/time/tck/java/time/format/TCKOffsetPrinterParser.java b/jdk/test/java/time/tck/java/time/format/TCKOffsetPrinterParser.java new file mode 100644 index 00000000000..0ebc718c1e3 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKOffsetPrinterParser.java @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.format; + +import static org.testng.Assert.assertEquals; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test DateTimeFormatterBuilder.appendOffset(). + */ +@Test +public class TCKOffsetPrinterParser { + + private static final ZoneOffset OFFSET_UTC = ZoneOffset.UTC; + private static final ZoneOffset OFFSET_P0100 = ZoneOffset.ofHours(1); + private static final ZoneOffset OFFSET_P0123 = ZoneOffset.ofHoursMinutes(1, 23); + private static final ZoneOffset OFFSET_P0023 = ZoneOffset.ofHoursMinutes(0, 23); + private static final ZoneOffset OFFSET_P012345 = ZoneOffset.ofHoursMinutesSeconds(1, 23, 45); + private static final ZoneOffset OFFSET_P000045 = ZoneOffset.ofHoursMinutesSeconds(0, 0, 45); + private static final ZoneOffset OFFSET_M0100 = ZoneOffset.ofHours(-1); + private static final ZoneOffset OFFSET_M0123 = ZoneOffset.ofHoursMinutes(-1, -23); + private static final ZoneOffset OFFSET_M0023 = ZoneOffset.ofHoursMinutes(0, -23); + private static final ZoneOffset OFFSET_M012345 = ZoneOffset.ofHoursMinutesSeconds(-1, -23, -45); + private static final ZoneOffset OFFSET_M000045 = ZoneOffset.ofHoursMinutesSeconds(0, 0, -45); + private static final LocalDateTime DT_2012_06_30_12_30_40 = LocalDateTime.of(2012, 6, 30, 12, 30, 40); + + private DateTimeFormatterBuilder builder; + + @BeforeMethod + public void setUp() { + builder = new DateTimeFormatterBuilder(); + } + + //----------------------------------------------------------------------- + @DataProvider(name="print") + Object[][] data_print() { + return new Object[][] { + {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01"}, + {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+01"}, + {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "Z"}, + {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+01"}, + {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_P000045, "Z"}, + {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01"}, + {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-01"}, + {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "Z"}, + {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-01"}, + {"+HH", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "Z"}, + + {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01"}, + {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+0123"}, + {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+0023"}, + {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+0123"}, + {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_P000045, "Z"}, + {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01"}, + {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-0123"}, + {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-0023"}, + {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-0123"}, + {"+HHmm", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "Z"}, + + {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+0100"}, + {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+0123"}, + {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+0023"}, + {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+0123"}, + {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_P000045, "Z"}, + {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-0100"}, + {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-0123"}, + {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-0023"}, + {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-0123"}, + {"+HHMM", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "Z"}, + + {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01:00"}, + {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+01:23"}, + {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+00:23"}, + {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+01:23"}, + {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_P000045, "Z"}, + {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01:00"}, + {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-01:23"}, + {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-00:23"}, + {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-01:23"}, + {"+HH:MM", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "Z"}, + + {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+0100"}, + {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+0123"}, + {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+0023"}, + {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+012345"}, + {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_P000045, "+000045"}, + {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-0100"}, + {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-0123"}, + {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-0023"}, + {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-012345"}, + {"+HHMMss", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-000045"}, + + {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01:00"}, + {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+01:23"}, + {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+00:23"}, + {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+01:23:45"}, + {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"}, + {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01:00"}, + {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-01:23"}, + {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-00:23"}, + {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-01:23:45"}, + {"+HH:MM:ss", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"}, + + {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+010000"}, + {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+012300"}, + {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+002300"}, + {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+012345"}, + {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-000045"}, + {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-010000"}, + {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-012300"}, + {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-002300"}, + {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-012345"}, + {"+HHMMSS", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-000045"}, + + {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_P0100, "+01:00:00"}, + {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_P0123, "+01:23:00"}, + {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_P0023, "+00:23:00"}, + {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_P012345, "+01:23:45"}, + {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"}, + {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0100, "-01:00:00"}, + {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0123, "-01:23:00"}, + {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M0023, "-00:23:00"}, + {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M012345, "-01:23:45"}, + {"+HH:MM:SS", "Z", DT_2012_06_30_12_30_40, OFFSET_M000045, "-00:00:45"}, + }; + } + + @Test(dataProvider="print") + public void test_print(String offsetPattern, String noOffset, LocalDateTime ldt, ZoneId zone, String expected) { + ZonedDateTime zdt = ldt.atZone(zone); + builder.appendOffset(offsetPattern, noOffset); + String output = builder.toFormatter().format(zdt); + assertEquals(output, expected); + } + + //----------------------------------------------------------------------- + @Test(dataProvider="print") + public void test_print_pattern_X(String offsetPattern, String noOffset, LocalDateTime ldt, ZoneId zone, String expected) { + String pattern = null; + if (offsetPattern.equals("+HHmm") && noOffset.equals("Z")) { + pattern = "X"; + } else if (offsetPattern.equals("+HHMM") && noOffset.equals("Z")) { + pattern = "XX"; + } else if (offsetPattern.equals("+HH:MM") && noOffset.equals("Z")) { + pattern = "XXX"; + } else if (offsetPattern.equals("+HHMMss") && noOffset.equals("Z")) { + pattern = "XXXX"; + } else if (offsetPattern.equals("+HH:MM:ss") && noOffset.equals("Z")) { + pattern = "XXXXX"; + } + if (pattern != null) { + ZonedDateTime zdt = ldt.atZone(zone); + builder.appendPattern(pattern); + String output = builder.toFormatter().format(zdt); + assertEquals(output, expected); + } + } + + @Test(dataProvider="print") + public void test_print_pattern_x(String offsetPattern, String noOffset, LocalDateTime ldt, ZoneId zone, String expected) { + String pattern = null; + String zero = null; + if (offsetPattern.equals("+HHmm") && noOffset.equals("Z")) { + pattern = "x"; + zero = "+00"; + } else if (offsetPattern.equals("+HHMM") && noOffset.equals("Z")) { + pattern = "xx"; + zero = "+0000"; + } else if (offsetPattern.equals("+HH:MM") && noOffset.equals("Z")) { + pattern = "xxx"; + zero = "+00:00"; + } else if (offsetPattern.equals("+HHMMss") && noOffset.equals("Z")) { + pattern = "xxxx"; + zero = "+0000"; + } else if (offsetPattern.equals("+HH:MM:ss") && noOffset.equals("Z")) { + pattern = "xxxxx"; + zero = "+00:00"; + } + if (pattern != null) { + ZonedDateTime zdt = ldt.atZone(zone); + builder.appendPattern(pattern); + String output = builder.toFormatter().format(zdt); + assertEquals(output, (expected.equals("Z") ? zero : expected)); + } + } + + @Test(dataProvider="print") + public void test_print_pattern_Z(String offsetPattern, String noOffset, LocalDateTime ldt, ZoneId zone, String expected) { + String pattern = null; + if (offsetPattern.equals("+HHMM") && noOffset.equals("Z")) { + ZonedDateTime zdt = ldt.atZone(zone); + DateTimeFormatter f1 = new DateTimeFormatterBuilder().appendPattern("Z").toFormatter(); + String output1 = f1.format(zdt); + assertEquals(output1, (expected.equals("Z") ? "+0000" : expected)); + + DateTimeFormatter f2 = new DateTimeFormatterBuilder().appendPattern("ZZ").toFormatter(); + String output2 = f2.format(zdt); + assertEquals(output2, (expected.equals("Z") ? "+0000" : expected)); + + DateTimeFormatter f3 = new DateTimeFormatterBuilder().appendPattern("ZZZ").toFormatter(); + String output3 = f3.format(zdt); + assertEquals(output3, (expected.equals("Z") ? "+0000" : expected)); + } + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_print_pattern_X6rejected() { + builder.appendPattern("XXXXXX"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_print_pattern_x6rejected() { + builder.appendPattern("xxxxxx"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_print_pattern_Z4rejected() { + builder.appendPattern("ZZZZ"); + } + +} diff --git a/jdk/test/java/time/tck/java/time/format/TCKPadPrinterParser.java b/jdk/test/java/time/tck/java/time/format/TCKPadPrinterParser.java new file mode 100644 index 00000000000..d6641f65e63 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKPadPrinterParser.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.format; + +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.text.ParsePosition; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.SignStyle; +import java.time.temporal.TemporalAccessor; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test padding behavior of formatter. + */ +@Test +public class TCKPadPrinterParser { + + private DateTimeFormatterBuilder builder; + private ParsePosition pos; + + @BeforeMethod + public void setUp() { + builder = new DateTimeFormatterBuilder(); + pos = new ParsePosition(0); + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=IndexOutOfBoundsException.class) + public void test_parse_negativePosition() { + builder.padNext(3, '-').appendLiteral('Z'); + builder.toFormatter().parseUnresolved("--Z", new ParsePosition(-1)); + } + + @Test(expectedExceptions=IndexOutOfBoundsException.class) + public void test_parse_offEndPosition() { + builder.padNext(3, '-').appendLiteral('Z'); + builder.toFormatter().parseUnresolved("--Z", new ParsePosition(4)); + } + + //----------------------------------------------------------------------- + @DataProvider(name="parseStrict") + Object[][] data_parseStrict() { + return new Object[][] { + {"222", 3, -1, 222}, + {"222X", 3, -1, 222}, + {"#22", 3, -1, 22}, + {"#22X", 3, -1, 22}, + {"##2", 3, -1, 2}, + {"##2X", 3, -1, 2}, + {"##22", 3, -1, 2}, + {"-22", 3, -1, -22}, + {"#-2", 3, -1, -2}, + {"3", 0, 0, null}, + {"3X", 0, 0, null}, + {"#3", 0, 0, null}, + {"#3X", 0, 1, null}, + {"##A", 0, 2, null}, + {" 3", 0, 0, null}, + {"##", 0, 0, null}, + {"#", 0, 0, null}, + {"", 0, 0, null}, + }; + } + + @Test(dataProvider="parseStrict") + public void test_parseStrict(String text, int expectedIndex, int expectedErrorIndex, Number expectedMonth) { + builder.padNext(3, '#').appendValue(MONTH_OF_YEAR, 1, 3, SignStyle.NORMAL); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text, pos); + assertEquals(pos.getIndex(), expectedIndex); + assertEquals(pos.getErrorIndex(), expectedErrorIndex); + if (expectedMonth != null) { + assertEquals(parsed.isSupported(MONTH_OF_YEAR), true); + assertEquals(parsed.getLong(MONTH_OF_YEAR), expectedMonth.longValue()); + } else { + assertEquals(parsed, null); + } + } + + //----------------------------------------------------------------------- + @DataProvider(name="parseLenient") + Object[][] data_parseLenient() { + return new Object[][] { + {"222", 3, -1, 222}, + {"222X", 3, -1, 222}, + {"#22", 3, -1, 22}, + {"#22X", 3, -1, 22}, + {"##2", 3, -1, 2}, + {"##2X", 3, -1, 2}, + {"##22", 3, -1, 2}, + {"-22", 3, -1, -22}, + {"#-2", 3, -1, -2}, + {"3", 1, -1, 3}, + {"3X", 1, -1, 3}, + {"33", 2, -1, 33}, + {"33X", 2, -1, 33}, + {"#3", 2, -1, 3}, + {"#3X", 2, -1, 3}, + {"##A", 0, 2, null}, + {" 1", 0, 0, null}, + {"##", 0, 2, null}, + {"#", 0, 1, null}, + {"", 0, 0, null}, + }; + } + + @Test(dataProvider="parseLenient") + public void test_parseLenient(String text, int expectedIndex, int expectedErrorIndex, Number expectedMonth) { + builder.parseLenient().padNext(3, '#').appendValue(MONTH_OF_YEAR, 1, 3, SignStyle.NORMAL); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text, pos); + assertEquals(pos.getIndex(), expectedIndex); + assertEquals(pos.getErrorIndex(), expectedErrorIndex); + if (expectedMonth != null) { + assertEquals(parsed.isSupported(MONTH_OF_YEAR), true); + assertEquals(parsed.getLong(MONTH_OF_YEAR), expectedMonth.longValue()); + } else { + assertEquals(parsed, null); + } + } + + //----------------------------------------------------------------------- + @Test + public void test_parse_decoratedStartsWithPad() { + builder.padNext(8, '-').appendLiteral("-HELLO-"); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved("--HELLO-", pos); + assertEquals(pos.getIndex(), 0); + assertEquals(pos.getErrorIndex(), 2); + assertEquals(parsed, null); + } + + @Test + public void test_parse_decoratedStartsWithPad_number() { + builder.padNext(3, '-').appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved("--2", pos); + assertEquals(pos.getIndex(), 3); + assertEquals(pos.getErrorIndex(), -1); + assertEquals(parsed.isSupported(MONTH_OF_YEAR), true); + assertEquals(parsed.getLong(MONTH_OF_YEAR), 2L); // +2, not -2 + } + + //----------------------------------------------------------------------- + @Test + public void test_parse_decoratedEmpty_strict() { + builder.padNext(4, '-').optionalStart().appendValue(DAY_OF_MONTH).optionalEnd(); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved("----", pos); + assertEquals(pos.getIndex(), 4); + assertEquals(pos.getErrorIndex(), -1); + assertNotNull(parsed); + } + + @Test + public void test_parse_decoratedEmpty_lenient() { + builder.parseLenient().padNext(4, '-').optionalStart().appendValue(DAY_OF_MONTH).optionalEnd(); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved("----", pos); + assertEquals(pos.getIndex(), 4); + assertEquals(pos.getErrorIndex(), -1); + assertNotNull(parsed); + } + +} diff --git a/jdk/test/java/time/tck/java/time/format/TCKZoneIdPrinterParser.java b/jdk/test/java/time/tck/java/time/format/TCKZoneIdPrinterParser.java new file mode 100644 index 00000000000..e346742dea3 --- /dev/null +++ b/jdk/test/java/time/tck/java/time/format/TCKZoneIdPrinterParser.java @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2010-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package tck.java.time.format; + +import static org.testng.Assert.assertEquals; + +import java.text.ParsePosition; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.Queries; +import java.time.temporal.TemporalAccessor; +import java.util.Locale; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test DateTimeFormatterBuilder.appendZoneId(). + */ +@Test +public class TCKZoneIdPrinterParser { + + private static final ZoneOffset OFFSET_UTC = ZoneOffset.UTC; + private static final ZoneOffset OFFSET_P0123 = ZoneOffset.ofHoursMinutes(1, 23); + private static final ZoneId EUROPE_PARIS = ZoneId.of("Europe/Paris"); + private static final ZoneId AMERICA_NEW_YORK = ZoneId.of("America/New_York"); + private static final LocalDateTime DT_2012_06_30_12_30_40 = LocalDateTime.of(2012, 6, 30, 12, 30, 40); + + private DateTimeFormatterBuilder builder; + private ParsePosition pos; + + @BeforeMethod + public void setUp() { + builder = new DateTimeFormatterBuilder(); + pos = new ParsePosition(0); + } + + //----------------------------------------------------------------------- + @DataProvider(name="print") + Object[][] data_print() { + return new Object[][] { + {DT_2012_06_30_12_30_40, EUROPE_PARIS, "Europe/Paris"}, + {DT_2012_06_30_12_30_40, AMERICA_NEW_YORK, "America/New_York"}, + {DT_2012_06_30_12_30_40, OFFSET_UTC, "Z"}, + {DT_2012_06_30_12_30_40, OFFSET_P0123, "+01:23"}, + }; + } + + @Test(dataProvider="print") + public void test_print(LocalDateTime ldt, ZoneId zone, String expected) { + ZonedDateTime zdt = ldt.atZone(zone); + builder.appendZoneId(); + String output = builder.toFormatter().format(zdt); + assertEquals(output, expected); + } + + @Test(dataProvider="print") + public void test_print_pattern_VV(LocalDateTime ldt, ZoneId zone, String expected) { + ZonedDateTime zdt = ldt.atZone(zone); + builder.appendPattern("VV"); + String output = builder.toFormatter().format(zdt); + assertEquals(output, expected); + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_print_pattern_V1rejected() { + builder.appendPattern("V"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_print_pattern_V3rejected() { + builder.appendPattern("VVV"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_print_pattern_V4rejected() { + builder.appendPattern("VVVV"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_print_pattern_V5rejected() { + builder.appendPattern("VVVVV"); + } + + //----------------------------------------------------------------------- + @DataProvider(name="parseSuccess") + Object[][] data_parseSuccess() { + return new Object[][] { + {"Z", 1, -1, ZoneOffset.UTC}, + {"UTC", 3, -1, ZoneOffset.UTC}, + {"UT", 2, -1, ZoneOffset.UTC}, + {"GMT", 3, -1, ZoneOffset.UTC}, + {"UTC0", 4, -1, ZoneOffset.UTC}, + {"UT0", 3, -1, ZoneOffset.UTC}, + {"GMT0", 4, -1, ZoneOffset.UTC}, + + {"+00:00", 6, -1, ZoneOffset.UTC}, + {"UTC+00:00", 9, -1, ZoneOffset.UTC}, + {"UT+00:00", 8, -1, ZoneOffset.UTC}, + {"GMT+00:00", 9, -1, ZoneOffset.UTC}, + {"-00:00", 6, -1, ZoneOffset.UTC}, + {"UTC-00:00", 9, -1, ZoneOffset.UTC}, + {"UT-00:00", 8, -1, ZoneOffset.UTC}, + {"GMT-00:00", 9, -1, ZoneOffset.UTC}, + + {"+01:30", 6, -1, ZoneOffset.ofHoursMinutes(1, 30)}, + {"UTC+01:30", 9, -1, ZoneOffset.ofHoursMinutes(1, 30)}, + {"UT+02:30", 8, -1, ZoneOffset.ofHoursMinutes(2, 30)}, + {"GMT+03:30", 9, -1, ZoneOffset.ofHoursMinutes(3, 30)}, + {"-01:30", 6, -1, ZoneOffset.ofHoursMinutes(-1, -30)}, + {"UTC-01:30", 9, -1, ZoneOffset.ofHoursMinutes(-1, -30)}, + {"UT-02:30", 8, -1, ZoneOffset.ofHoursMinutes(-2, -30)}, + {"GMT-03:30", 9, -1, ZoneOffset.ofHoursMinutes(-3, -30)}, + + // fallback to UTC + {"UTC-01:WW", 3, -1, ZoneOffset.UTC}, + {"UT-02:WW", 2, -1, ZoneOffset.UTC}, + {"GMT-03:WW", 3, -1, ZoneOffset.UTC}, + {"Z0", 1, -1, ZoneOffset.UTC}, + {"UTC1", 3, -1, ZoneOffset.UTC}, + + // Z not parsed as zero + {"UTCZ", 3, -1, ZoneOffset.UTC}, + {"UTZ", 2, -1, ZoneOffset.UTC}, + {"GMTZ", 3, -1, ZoneOffset.UTC}, + + // fail to parse + {"", 0, 0, null}, + {"A", 0, 0, null}, + {"UZ", 0, 0, null}, + {"GMA", 0, 0, null}, + {"0", 0, 0, null}, + {"+", 0, 0, null}, + {"-", 0, 0, null}, + + // zone IDs + {"Europe/London", 13, -1, ZoneId.of("Europe/London")}, + {"America/New_York", 16, -1, ZoneId.of("America/New_York")}, + {"America/Bogusville", 0, 0, null}, + }; + } + + @Test(dataProvider="parseSuccess") + public void test_parseSuccess_plain(String text, int expectedIndex, int expectedErrorIndex, ZoneId expected) { + builder.appendZoneId(); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text, pos); + assertEquals(pos.getErrorIndex(), expectedErrorIndex); + assertEquals(pos.getIndex(), expectedIndex); + if (expected != null) { + assertEquals(parsed.query(Queries.zoneId()), expected); + assertEquals(parsed.query(Queries.offset()), null); + assertEquals(parsed.query(Queries.zone()), expected); + } else { + assertEquals(parsed, null); + } + } + + @Test(dataProvider="parseSuccess") + public void test_parseSuccess_prefix(String text, int expectedIndex, int expectedErrorIndex, ZoneId expected) { + builder.appendZoneId(); + pos.setIndex(3); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved("XXX" + text, pos); + assertEquals(pos.getErrorIndex(), expectedErrorIndex >= 0 ? expectedErrorIndex + 3 : expectedErrorIndex); + assertEquals(pos.getIndex(), expectedIndex + 3); + if (expected != null) { + assertEquals(parsed.query(Queries.zoneId()), expected); + assertEquals(parsed.query(Queries.offset()), null); + assertEquals(parsed.query(Queries.zone()), expected); + } else { + assertEquals(parsed, null); + } + } + + @Test(dataProvider="parseSuccess") + public void test_parseSuccess_suffix(String text, int expectedIndex, int expectedErrorIndex, ZoneId expected) { + builder.appendZoneId(); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text + "XXX", pos); + assertEquals(pos.getErrorIndex(), expectedErrorIndex); + assertEquals(pos.getIndex(), expectedIndex); + if (expected != null) { + assertEquals(parsed.query(Queries.zoneId()), expected); + assertEquals(parsed.query(Queries.offset()), null); + assertEquals(parsed.query(Queries.zone()), expected); + } else { + assertEquals(parsed, null); + } + } + + @Test(dataProvider="parseSuccess") + public void test_parseSuccess_caseSensitive(String text, int expectedIndex, int expectedErrorIndex, ZoneId expected) { + builder.parseCaseSensitive().appendZoneId(); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text.toLowerCase(Locale.ENGLISH), pos); + if (text.matches("[^A-Z]*[A-Z].*")) { // if input has letters + assertEquals(pos.getErrorIndex() >= 0, true); + assertEquals(pos.getIndex(), 0); + assertEquals(parsed, null); + } else { + // case sensitive made no difference + assertEquals(pos.getIndex(), expectedIndex); + assertEquals(pos.getErrorIndex(), expectedErrorIndex); + if (expected != null) { + assertEquals(parsed.query(Queries.zoneId()), expected); + assertEquals(parsed.query(Queries.offset()), null); + assertEquals(parsed.query(Queries.zone()), expected); + } else { + assertEquals(parsed, null); + } + } + } + + @Test(dataProvider="parseSuccess") + public void test_parseSuccess_caseInsensitive(String text, int expectedIndex, int expectedErrorIndex, ZoneId expected) { + builder.parseCaseInsensitive().appendZoneId(); + TemporalAccessor parsed = builder.toFormatter().parseUnresolved(text.toLowerCase(Locale.ENGLISH), pos); + assertEquals(pos.getErrorIndex(), expectedErrorIndex); + assertEquals(pos.getIndex(), expectedIndex); + if (expected != null) { + assertEquals(parsed.query(Queries.zoneId()), expected); + assertEquals(parsed.query(Queries.offset()), null); + assertEquals(parsed.query(Queries.zone()), expected); + } else { + assertEquals(parsed, null); + } + } + +} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKISOFields.java b/jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java similarity index 64% rename from jdk/test/java/time/tck/java/time/temporal/TCKISOFields.java rename to jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java index c3acbdb6f82..359aac1b0e6 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TCKISOFields.java +++ b/jdk/test/java/time/tck/java/time/temporal/TCKIsoFields.java @@ -56,9 +56,6 @@ */ package tck.java.time.temporal; -import java.time.format.DateTimeBuilder; -import java.time.temporal.*; - import static java.time.DayOfWeek.FRIDAY; import static java.time.DayOfWeek.MONDAY; import static java.time.DayOfWeek.SATURDAY; @@ -69,10 +66,13 @@ import static java.time.DayOfWeek.WEDNESDAY; import static java.time.temporal.ChronoField.DAY_OF_WEEK; import static java.time.temporal.ChronoField.YEAR; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; import java.time.DayOfWeek; import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.IsoFields; +import java.time.temporal.ValueRange; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -81,7 +81,7 @@ import org.testng.annotations.Test; * Test. */ @Test(groups={"tck"}) -public class TCKISOFields { +public class TCKIsoFields { @DataProvider(name="quarter") Object[][] data_quarter() { @@ -117,8 +117,8 @@ public class TCKISOFields { //----------------------------------------------------------------------- @Test(dataProvider="quarter") public void test_DOQ(LocalDate date, int doq, int qoy) { - assertEquals(ISOFields.DAY_OF_QUARTER.doGet(date), doq); - assertEquals(date.get(ISOFields.DAY_OF_QUARTER), doq); + assertEquals(IsoFields.DAY_OF_QUARTER.getFrom(date), doq); + assertEquals(date.get(IsoFields.DAY_OF_QUARTER), doq); } //----------------------------------------------------------------------- @@ -126,21 +126,61 @@ public class TCKISOFields { //----------------------------------------------------------------------- @Test(dataProvider="quarter") public void test_QOY(LocalDate date, int doq, int qoy) { - assertEquals(ISOFields.QUARTER_OF_YEAR.doGet(date), qoy); - assertEquals(date.get(ISOFields.QUARTER_OF_YEAR), qoy); + assertEquals(IsoFields.QUARTER_OF_YEAR.getFrom(date), qoy); + assertEquals(date.get(IsoFields.QUARTER_OF_YEAR), qoy); } //----------------------------------------------------------------------- - // builder + // parse quarters //----------------------------------------------------------------------- @Test(dataProvider="quarter") - public void test_builder_quarters(LocalDate date, int doq, int qoy) { - DateTimeBuilder builder = new DateTimeBuilder(); - builder.addFieldValue(ISOFields.DAY_OF_QUARTER, doq); - builder.addFieldValue(ISOFields.QUARTER_OF_YEAR, qoy); - builder.addFieldValue(YEAR, date.getYear()); - builder.resolve(); - assertEquals(builder.query(LocalDate::from), date); + public void test_parse_quarters(LocalDate date, int doq, int qoy) { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(YEAR).appendLiteral('-') + .appendValue(IsoFields.QUARTER_OF_YEAR).appendLiteral('-') + .appendValue(IsoFields.DAY_OF_QUARTER).toFormatter(); + LocalDate parsed = LocalDate.parse(date.getYear() + "-" + qoy + "-" + doq, f); + assertEquals(parsed, date); + } + + //----------------------------------------------------------------------- + // quarters between + //----------------------------------------------------------------------- + @DataProvider(name="quartersBetween") + Object[][] data_quartersBetween() { + return new Object[][] { + {LocalDate.of(2000, 1, 1), LocalDate.of(2000, 1, 1), 0}, + {LocalDate.of(2000, 1, 1), LocalDate.of(2000, 1, 2), 0}, + {LocalDate.of(2000, 1, 1), LocalDate.of(2000, 2, 1), 0}, + {LocalDate.of(2000, 1, 1), LocalDate.of(2000, 3, 1), 0}, + {LocalDate.of(2000, 1, 1), LocalDate.of(2000, 3, 31), 0}, + {LocalDate.of(2000, 1, 1), LocalDate.of(2000, 4, 1), 1}, + {LocalDate.of(2000, 1, 1), LocalDate.of(2000, 4, 2), 1}, + {LocalDate.of(2000, 1, 1), LocalDate.of(2000, 6, 30), 1}, + {LocalDate.of(2000, 1, 1), LocalDate.of(2000, 7, 1), 2}, + {LocalDate.of(2000, 1, 1), LocalDate.of(2000, 10, 1), 3}, + {LocalDate.of(2000, 1, 1), LocalDate.of(2000, 12, 31), 3}, + {LocalDate.of(2000, 1, 1), LocalDate.of(2001, 1, 1), 4}, + {LocalDate.of(2000, 1, 1), LocalDate.of(2002, 1, 1), 8}, + + {LocalDate.of(2000, 1, 1), LocalDate.of(1999, 12, 31), 0}, + {LocalDate.of(2000, 1, 1), LocalDate.of(1999, 10, 2), 0}, + {LocalDate.of(2000, 1, 1), LocalDate.of(1999, 10, 1), -1}, + {LocalDate.of(2000, 1, 1), LocalDate.of(1999, 7, 2), -1}, + {LocalDate.of(2000, 1, 1), LocalDate.of(1999, 7, 1), -2}, + {LocalDate.of(2000, 1, 1), LocalDate.of(1999, 4, 2), -2}, + {LocalDate.of(2000, 1, 1), LocalDate.of(1999, 4, 1), -3}, + {LocalDate.of(2000, 1, 1), LocalDate.of(1999, 1, 2), -3}, + {LocalDate.of(2000, 1, 1), LocalDate.of(1999, 1, 1), -4}, + {LocalDate.of(2000, 1, 1), LocalDate.of(1998, 12, 31), -4}, + {LocalDate.of(2000, 1, 1), LocalDate.of(1998, 10, 2), -4}, + {LocalDate.of(2000, 1, 1), LocalDate.of(1998, 10, 1), -5}, + }; + } + + @Test(dataProvider="quartersBetween") + public void test_quarters_between(LocalDate start, LocalDate end, long expected) { + assertEquals(IsoFields.QUARTER_YEARS.between(start, end), expected); } //----------------------------------------------------------------------- @@ -170,8 +210,8 @@ public class TCKISOFields { @Test(dataProvider="week") public void test_WOWBY(LocalDate date, DayOfWeek dow, int week, int wby) { assertEquals(date.getDayOfWeek(), dow); - assertEquals(ISOFields.WEEK_OF_WEEK_BASED_YEAR.doGet(date), week); - assertEquals(date.get(ISOFields.WEEK_OF_WEEK_BASED_YEAR), week); + assertEquals(IsoFields.WEEK_OF_WEEK_BASED_YEAR.getFrom(date), week); + assertEquals(date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR), week); } //----------------------------------------------------------------------- @@ -180,21 +220,21 @@ public class TCKISOFields { @Test(dataProvider="week") public void test_WBY(LocalDate date, DayOfWeek dow, int week, int wby) { assertEquals(date.getDayOfWeek(), dow); - assertEquals(ISOFields.WEEK_BASED_YEAR.doGet(date), wby); - assertEquals(date.get(ISOFields.WEEK_BASED_YEAR), wby); + assertEquals(IsoFields.WEEK_BASED_YEAR.getFrom(date), wby); + assertEquals(date.get(IsoFields.WEEK_BASED_YEAR), wby); } //----------------------------------------------------------------------- - // builder + // parse weeks //----------------------------------------------------------------------- @Test(dataProvider="week") - public void test_builder_weeks(LocalDate date, DayOfWeek dow, int week, int wby) { - DateTimeBuilder builder = new DateTimeBuilder(); - builder.addFieldValue(ISOFields.WEEK_BASED_YEAR, wby); - builder.addFieldValue(ISOFields.WEEK_OF_WEEK_BASED_YEAR, week); - builder.addFieldValue(DAY_OF_WEEK, dow.getValue()); - builder.resolve(); - assertEquals(builder.query(LocalDate::from), date); + public void test_parse_weeks(LocalDate date, DayOfWeek dow, int week, int wby) { + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(IsoFields.WEEK_BASED_YEAR).appendLiteral('-') + .appendValue(IsoFields.WEEK_OF_WEEK_BASED_YEAR).appendLiteral('-') + .appendValue(DAY_OF_WEEK).toFormatter(); + LocalDate parsed = LocalDate.parse(wby + "-" + week + "-" + dow.getValue(), f); + assertEquals(parsed, date); } //----------------------------------------------------------------------- @@ -220,11 +260,11 @@ public class TCKISOFields { wby++; } } - assertEquals(ISOFields.WEEK_OF_WEEK_BASED_YEAR.doRange(date), ValueRange.of(1, weekLen), "Failed on " + date + " " + date.getDayOfWeek()); - assertEquals(ISOFields.WEEK_OF_WEEK_BASED_YEAR.doGet(date), week, "Failed on " + date + " " + date.getDayOfWeek()); - assertEquals(date.get(ISOFields.WEEK_OF_WEEK_BASED_YEAR), week, "Failed on " + date + " " + date.getDayOfWeek()); - assertEquals(ISOFields.WEEK_BASED_YEAR.doGet(date), wby, "Failed on " + date + " " + date.getDayOfWeek()); - assertEquals(date.get(ISOFields.WEEK_BASED_YEAR), wby, "Failed on " + date + " " + date.getDayOfWeek()); + assertEquals(IsoFields.WEEK_OF_WEEK_BASED_YEAR.rangeRefinedBy(date), ValueRange.of(1, weekLen), "Failed on " + date + " " + date.getDayOfWeek()); + assertEquals(IsoFields.WEEK_OF_WEEK_BASED_YEAR.getFrom(date), week, "Failed on " + date + " " + date.getDayOfWeek()); + assertEquals(date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR), week, "Failed on " + date + " " + date.getDayOfWeek()); + assertEquals(IsoFields.WEEK_BASED_YEAR.getFrom(date), wby, "Failed on " + date + " " + date.getDayOfWeek()); + assertEquals(date.get(IsoFields.WEEK_BASED_YEAR), wby, "Failed on " + date + " " + date.getDayOfWeek()); date = date.plusDays(1); } } diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKJulianFields.java b/jdk/test/java/time/tck/java/time/temporal/TCKJulianFields.java index 81e8109c329..94399e0fdd8 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TCKJulianFields.java +++ b/jdk/test/java/time/tck/java/time/temporal/TCKJulianFields.java @@ -60,38 +60,30 @@ package tck.java.time.temporal; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoField; +import java.time.temporal.JulianFields; +import java.time.temporal.TemporalField; -import java.time.temporal.*; - - -import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; /** * Test. */ @Test -public class TCKJulianFields { +public class TCKJulianFields extends AbstractTCKTest { private static final LocalDate JAN01_1970 = LocalDate.of(1970, 1, 1); private static final LocalDate DEC31_1969 = LocalDate.of(1969, 12, 31); private static final LocalDate NOV12_1945 = LocalDate.of(1945, 11, 12); private static final LocalDate JAN01_0001 = LocalDate.of(1, 1, 1); - @BeforeMethod - public void setUp() { - } - //----------------------------------------------------------------------- @DataProvider(name="julian_fields") Object[][] julian_samples() { @@ -127,42 +119,33 @@ public class TCKJulianFields { }; } - @Test(dataProvider="samples", groups={"tck"}) + //----------------------------------------------------------------------- + @Test(dataProvider="julian_fields") + public void test_serializable(TemporalField field) throws IOException, ClassNotFoundException { + assertSerializable(field); + } + + //----------------------------------------------------------------------- + @Test(dataProvider="samples") public void test_samples_get(TemporalField field, LocalDate date, long expected) { assertEquals(date.getLong(field), expected); } - @Test(dataProvider="samples", groups={"tck"}) + @Test(dataProvider="samples") public void test_samples_set(TemporalField field, LocalDate date, long value) { - assertEquals(field.doWith(LocalDate.MAX, value), date); - assertEquals(field.doWith(LocalDate.MIN, value), date); - assertEquals(field.doWith(JAN01_1970, value), date); - assertEquals(field.doWith(DEC31_1969, value), date); - assertEquals(field.doWith(NOV12_1945, value), date); + assertEquals(field.adjustInto(LocalDate.MAX, value), date); + assertEquals(field.adjustInto(LocalDate.MIN, value), date); + assertEquals(field.adjustInto(JAN01_1970, value), date); + assertEquals(field.adjustInto(DEC31_1969, value), date); + assertEquals(field.adjustInto(NOV12_1945, value), date); } //----------------------------------------------------------------------- - // toString() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_toString() { - assertEquals(JulianFields.JULIAN_DAY.toString(), "JulianDay"); - assertEquals(JulianFields.MODIFIED_JULIAN_DAY.toString(), "ModifiedJulianDay"); - assertEquals(JulianFields.RATA_DIE.toString(), "RataDie"); - } - - @Test(groups = {"tck"},dataProvider="julian_fields") - public void test_JulianFieldsSingleton(TemporalField field) throws IOException, ClassNotFoundException { - try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos)) { - oos.writeObject(field); - - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream( - baos.toByteArray())); - TemporalField result = (TemporalField)ois.readObject(); - assertSame(result, field, "Deserialized object same as serialized."); - } - // Exceptions will be handled as failures by TestNG + @Test(dataProvider="samples") + public void test_samples_parse(TemporalField field, LocalDate date, long value) { + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(field).toFormatter(); + LocalDate parsed = LocalDate.parse(Long.toString(value), f); + assertEquals(parsed, date); } } diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKOffsetDate.java b/jdk/test/java/time/tck/java/time/temporal/TCKOffsetDate.java deleted file mode 100644 index 77720220d69..00000000000 --- a/jdk/test/java/time/tck/java/time/temporal/TCKOffsetDate.java +++ /dev/null @@ -1,1949 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file: - * -9 * Copyright (c) 2007-2012, Stephen Colebourne & Michael Nascimento Santos - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of JSR-310 nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tck.java.time.temporal; - -import static java.time.Month.DECEMBER; -import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH; -import static java.time.temporal.ChronoField.ALIGNED_DAY_OF_WEEK_IN_YEAR; -import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_MONTH; -import static java.time.temporal.ChronoField.ALIGNED_WEEK_OF_YEAR; -import static java.time.temporal.ChronoField.DAY_OF_MONTH; -import static java.time.temporal.ChronoField.DAY_OF_WEEK; -import static java.time.temporal.ChronoField.DAY_OF_YEAR; -import static java.time.temporal.ChronoField.EPOCH_DAY; -import static java.time.temporal.ChronoField.EPOCH_MONTH; -import static java.time.temporal.ChronoField.ERA; -import static java.time.temporal.ChronoField.MONTH_OF_YEAR; -import static java.time.temporal.ChronoField.OFFSET_SECONDS; -import static java.time.temporal.ChronoField.YEAR; -import static java.time.temporal.ChronoField.YEAR_OF_ERA; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import java.time.Clock; -import java.time.DateTimeException; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.Month; -import java.time.Period; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatters; -import java.time.format.DateTimeParseException; -import java.time.temporal.ChronoField; -import java.time.temporal.ChronoUnit; -import java.time.temporal.ISOChrono; -import java.time.temporal.JulianFields; -import java.time.temporal.OffsetDate; -import java.time.temporal.OffsetDateTime; -import java.time.temporal.Queries; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalAdder; -import java.time.temporal.TemporalAdjuster; -import java.time.temporal.TemporalField; -import java.time.temporal.TemporalSubtractor; -import java.time.temporal.Year; - -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import tck.java.time.AbstractDateTimeTest; -import test.java.time.MockSimplePeriod; - -/** - * Test OffsetDate. - */ -@Test -public class TCKOffsetDate extends AbstractDateTimeTest { - private static final ZoneOffset OFFSET_PONE = ZoneOffset.ofHours(1); - private static final ZoneOffset OFFSET_PTWO = ZoneOffset.ofHours(2); - - private OffsetDate TEST_2007_07_15_PONE; - - @BeforeMethod(groups={"tck","implementation"}) - public void setUp() { - TEST_2007_07_15_PONE = OffsetDate.of(LocalDate.of(2007, 7, 15), OFFSET_PONE); - } - - //----------------------------------------------------------------------- - @Override - protected List samples() { - TemporalAccessor[] array = {TEST_2007_07_15_PONE, OffsetDate.MIN, OffsetDate.MAX}; - return Arrays.asList(array); - } - - @Override - protected List validFields() { - TemporalField[] array = { - DAY_OF_WEEK, - ALIGNED_DAY_OF_WEEK_IN_MONTH, - ALIGNED_DAY_OF_WEEK_IN_YEAR, - DAY_OF_MONTH, - DAY_OF_YEAR, - EPOCH_DAY, - ALIGNED_WEEK_OF_MONTH, - ALIGNED_WEEK_OF_YEAR, - MONTH_OF_YEAR, - EPOCH_MONTH, - YEAR_OF_ERA, - YEAR, - ERA, - OFFSET_SECONDS, - JulianFields.JULIAN_DAY, - JulianFields.MODIFIED_JULIAN_DAY, - JulianFields.RATA_DIE, - }; - return Arrays.asList(array); - } - - @Override - protected List invalidFields() { - List list = new ArrayList<>(Arrays.asList(ChronoField.values())); - list.removeAll(validFields()); - return list; - } - - //----------------------------------------------------------------------- - @Test - public void test_serialization() throws ClassNotFoundException, IOException { - assertSerializable(TEST_2007_07_15_PONE); - assertSerializable(OffsetDate.MIN); - assertSerializable(OffsetDate.MAX); - } - - @Test - public void test_serialization_format() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(1); - } - byte[] bytes = baos.toByteArray(); - ByteArrayOutputStream baosDate = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baosDate) ) { - dos.writeByte(3); - dos.writeInt(2012); - dos.writeByte(9); - dos.writeByte(16); - } - byte[] bytesDate = baosDate.toByteArray(); - ByteArrayOutputStream baosOffset = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baosOffset) ) { - dos.writeByte(8); - dos.writeByte(4); // quarter hours stored: 3600 / 900 - } - byte[] bytesOffset = baosOffset.toByteArray(); - assertSerializedBySer(OffsetDate.of(LocalDate.of(2012, 9, 16), ZoneOffset.ofHours(1)), bytes, - bytesDate, bytesOffset); - } - - //----------------------------------------------------------------------- - // constants - //----------------------------------------------------------------------- - @Test - public void constant_MIN() { - check(OffsetDate.MIN, Year.MIN_VALUE, 1, 1, ZoneOffset.MAX); - } - - @Test - public void constant_MAX() { - check(OffsetDate.MAX, Year.MAX_VALUE, 12, 31, ZoneOffset.MIN); - } - - //----------------------------------------------------------------------- - // now() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void now() { - OffsetDate expected = OffsetDate.now(Clock.systemDefaultZone()); - OffsetDate test = OffsetDate.now(); - for (int i = 0; i < 100; i++) { - if (expected.equals(test)) { - return; - } - expected = OffsetDate.now(Clock.systemDefaultZone()); - test = OffsetDate.now(); - } - assertEquals(test, expected); - } - - @Test(groups={"tck"}) - public void now_Clock_allSecsInDay_utc() { - for (int i = 0; i < (2 * 24 * 60 * 60); i++) { - Instant instant = Instant.ofEpochSecond(i); - Clock clock = Clock.fixed(instant, ZoneOffset.UTC); - OffsetDate test = OffsetDate.now(clock); - check(test, 1970, 1, (i < 24 * 60 * 60 ? 1 : 2), ZoneOffset.UTC); - } - } - - @Test(groups={"tck"}) - public void now_Clock_allSecsInDay_beforeEpoch() { - for (int i =-1; i >= -(2 * 24 * 60 * 60); i--) { - Instant instant = Instant.ofEpochSecond(i); - Clock clock = Clock.fixed(instant, ZoneOffset.UTC); - OffsetDate test = OffsetDate.now(clock); - check(test, 1969, 12, (i >= -24 * 60 * 60 ? 31 : 30), ZoneOffset.UTC); - } - } - - @Test(groups={"tck"}) - public void now_Clock_offsets() { - Instant base = LocalDateTime.of(1970, 1, 1, 12, 0).toInstant(ZoneOffset.UTC); - for (int i = -9; i < 15; i++) { - ZoneOffset offset = ZoneOffset.ofHours(i); - Clock clock = Clock.fixed(base, offset); - OffsetDate test = OffsetDate.now(clock); - check(test, 1970, 1, (i >= 12 ? 2 : 1), offset); - } - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void now_Clock_nullZoneId() { - OffsetDate.now((ZoneId) null); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void now_Clock_nullClock() { - OffsetDate.now((Clock) null); - } - - //----------------------------------------------------------------------- - // factories - //----------------------------------------------------------------------- - private void check(OffsetDate test, int y, int mo, int d, ZoneOffset offset) { - assertEquals(test.getDate(), LocalDate.of(y, mo, d)); - assertEquals(test.getOffset(), offset); - - assertEquals(test.getYear(), y); - assertEquals(test.getMonth().getValue(), mo); - assertEquals(test.getDayOfMonth(), d); - - assertEquals(test, test); - assertEquals(test.hashCode(), test.hashCode()); - assertEquals(OffsetDate.of(LocalDate.of(y, mo, d), offset), test); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_of_intMonthInt() { - OffsetDate test = OffsetDate.of(LocalDate.of(2007, Month.JULY, 15), OFFSET_PONE); - check(test, 2007, 7, 15, OFFSET_PONE); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_of_ints() { - OffsetDate test = OffsetDate.of(LocalDate.of(2007, 7, 15), OFFSET_PONE); - check(test, 2007, 7, 15, OFFSET_PONE); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_of_intsMonthOffset() { - assertEquals(TEST_2007_07_15_PONE, OffsetDate.of(LocalDate.of(2007, Month.JULY, 15), OFFSET_PONE)); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void factory_of_intsMonthOffset_dayTooLow() { - OffsetDate.of(LocalDate.of(2007, Month.JANUARY, 0), OFFSET_PONE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void factory_of_intsMonthOffset_dayTooHigh() { - OffsetDate.of(LocalDate.of(2007, Month.JANUARY, 32), OFFSET_PONE); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void factory_of_intsMonthOffset_nullMonth() { - OffsetDate.of(LocalDate.of(2007, null, 30), OFFSET_PONE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void factory_of_intsMonthOffset_yearTooLow() { - OffsetDate.of(LocalDate.of(Integer.MIN_VALUE, Month.JANUARY, 1), OFFSET_PONE); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void factory_of_intsMonthOffset_nullOffset() { - OffsetDate.of(LocalDate.of(2007, Month.JANUARY, 30), null); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_of_intsOffset() { - OffsetDate test = OffsetDate.of(LocalDate.of(2007, 7, 15), OFFSET_PONE); - check(test, 2007, 7, 15, OFFSET_PONE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void factory_of_ints_dayTooLow() { - OffsetDate.of(LocalDate.of(2007, 1, 0), OFFSET_PONE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void factory_of_ints_dayTooHigh() { - OffsetDate.of(LocalDate.of(2007, 1, 32), OFFSET_PONE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void factory_of_ints_monthTooLow() { - OffsetDate.of(LocalDate.of(2007, 0, 1), OFFSET_PONE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void factory_of_ints_monthTooHigh() { - OffsetDate.of(LocalDate.of(2007, 13, 1), OFFSET_PONE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void factory_of_ints_yearTooLow() { - OffsetDate.of(LocalDate.of(Integer.MIN_VALUE, 1, 1), OFFSET_PONE); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void factory_of_ints_nullOffset() { - OffsetDate.of(LocalDate.of(2007, 1, 1), (ZoneOffset) null); - } - - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_of_LocalDateZoneOffset() { - LocalDate localDate = LocalDate.of(2008, 6, 30); - OffsetDate test = OffsetDate.of(localDate, OFFSET_PONE); - check(test, 2008, 6, 30, OFFSET_PONE); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void factory_of_LocalDateZoneOffset_nullDate() { - OffsetDate.of((LocalDate) null, OFFSET_PONE); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void factory_of_LocalDateZoneOffset_nullOffset() { - LocalDate localDate = LocalDate.of(2008, 6, 30); - OffsetDate.of(localDate, (ZoneOffset) null); - } - - //----------------------------------------------------------------------- - // from(TemporalAccessor) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_from_TemporalAccessor_OD() { - assertEquals(OffsetDate.from(TEST_2007_07_15_PONE), TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_from_TemporalAccessor_ZDT() { - ZonedDateTime base = LocalDateTime.of(2007, 7, 15, 17, 30).atZone(OFFSET_PONE); - assertEquals(OffsetDate.from(base), TEST_2007_07_15_PONE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_from_TemporalAccessor_invalid_noDerive() { - OffsetDate.from(LocalTime.of(12, 30)); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_from_TemporalAccessor_null() { - OffsetDate.from((TemporalAccessor) null); - } - - //----------------------------------------------------------------------- - // parse() - //----------------------------------------------------------------------- - @Test(dataProvider="sampleToString", groups={"tck"}) - public void factory_parse_validText(int y, int m, int d, String offsetId, String parsable) { - OffsetDate t = OffsetDate.parse(parsable); - assertNotNull(t, parsable); - assertEquals(t.getYear(), y, parsable); - assertEquals(t.getMonth().getValue(), m, parsable); - assertEquals(t.getDayOfMonth(), d, parsable); - assertEquals(t.getOffset(), ZoneOffset.of(offsetId)); - } - - @DataProvider(name="sampleBadParse") - Object[][] provider_sampleBadParse() { - return new Object[][]{ - {"2008/07/05"}, - {"10000-01-01"}, - {"2008-1-1"}, - {"2008--01"}, - {"ABCD-02-01"}, - {"2008-AB-01"}, - {"2008-02-AB"}, - {"-0000-02-01"}, - {"2008-02-01Y"}, - {"2008-02-01+19:00"}, - {"2008-02-01+01/00"}, - {"2008-02-01+1900"}, - {"2008-02-01+01:60"}, - {"2008-02-01+01:30:123"}, - {"2008-02-01"}, - {"2008-02-01+01:00[Europe/Paris]"}, - }; - } - - @Test(dataProvider="sampleBadParse", expectedExceptions=DateTimeParseException.class, groups={"tck"}) - public void factory_parse_invalidText(String unparsable) { - OffsetDate.parse(unparsable); - } - - @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) - public void factory_parse_illegalValue() { - OffsetDate.parse("2008-06-32+01:00"); - } - - @Test(expectedExceptions=DateTimeParseException.class, groups={"tck"}) - public void factory_parse_invalidValue() { - OffsetDate.parse("2008-06-31+01:00"); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void factory_parse_nullText() { - OffsetDate.parse((String) null); - } - - //----------------------------------------------------------------------- - // parse(DateTimeFormatter) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void factory_parse_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d XXX"); - OffsetDate test = OffsetDate.parse("2010 12 3 +01:00", f); - assertEquals(test, OffsetDate.of(LocalDate.of(2010, 12, 3), ZoneOffset.ofHours(1))); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void factory_parse_formatter_nullText() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d"); - OffsetDate.parse((String) null, f); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void factory_parse_formatter_nullFormatter() { - OffsetDate.parse("ANY", null); - } - - //----------------------------------------------------------------------- - // constructor - //----------------------------------------------------------------------- - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void constructor_nullDate() throws Throwable { - Constructor con = OffsetDate.class.getDeclaredConstructor(LocalDate.class, ZoneOffset.class); - con.setAccessible(true); - try { - con.newInstance(null, OFFSET_PONE); - } catch (InvocationTargetException ex) { - throw ex.getCause(); - } - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void constructor_nullOffset() throws Throwable { - Constructor con = OffsetDate.class.getDeclaredConstructor(LocalDate.class, ZoneOffset.class); - con.setAccessible(true); - try { - con.newInstance(LocalDate.of(2008, 6, 30), null); - } catch (InvocationTargetException ex) { - throw ex.getCause(); - } - } - - //----------------------------------------------------------------------- - // basics - //----------------------------------------------------------------------- - @DataProvider(name="sampleDates") - Object[][] provider_sampleDates() { - return new Object[][] { - {2008, 7, 5, OFFSET_PTWO}, - {2007, 7, 5, OFFSET_PONE}, - {2006, 7, 5, OFFSET_PTWO}, - {2005, 7, 5, OFFSET_PONE}, - {2004, 1, 1, OFFSET_PTWO}, - {-1, 1, 2, OFFSET_PONE}, - {999999, 11, 20, ZoneOffset.ofHoursMinutesSeconds(6, 9, 12)}, - }; - } - - @Test(dataProvider="sampleDates", groups={"tck"}) - public void test_get_OffsetDate(int y, int m, int d, ZoneOffset offset) { - LocalDate localDate = LocalDate.of(y, m, d); - OffsetDate a = OffsetDate.of(localDate, offset); - - assertEquals(a.getDate(), localDate); - assertEquals(a.getOffset(), offset); - assertEquals(a.toString(), localDate.toString() + offset.toString()); - assertEquals(a.getYear(), localDate.getYear()); - assertEquals(a.getMonth(), localDate.getMonth()); - assertEquals(a.getDayOfMonth(), localDate.getDayOfMonth()); - assertEquals(a.getDayOfYear(), localDate.getDayOfYear()); - assertEquals(a.getDayOfWeek(), localDate.getDayOfWeek()); - } - - //----------------------------------------------------------------------- - // get(TemporalField) - //----------------------------------------------------------------------- - @Test - public void test_get_TemporalField() { - OffsetDate test = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); - assertEquals(test.get(ChronoField.YEAR), 2008); - assertEquals(test.get(ChronoField.MONTH_OF_YEAR), 6); - assertEquals(test.get(ChronoField.DAY_OF_MONTH), 30); - assertEquals(test.get(ChronoField.DAY_OF_WEEK), 1); - assertEquals(test.get(ChronoField.DAY_OF_YEAR), 182); - - assertEquals(test.get(ChronoField.OFFSET_SECONDS), 3600); - } - - @Test - public void test_getLong_TemporalField() { - OffsetDate test = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); - assertEquals(test.getLong(ChronoField.YEAR), 2008); - assertEquals(test.getLong(ChronoField.MONTH_OF_YEAR), 6); - assertEquals(test.getLong(ChronoField.DAY_OF_MONTH), 30); - assertEquals(test.getLong(ChronoField.DAY_OF_WEEK), 1); - assertEquals(test.getLong(ChronoField.DAY_OF_YEAR), 182); - - assertEquals(test.getLong(ChronoField.OFFSET_SECONDS), 3600); - } - - //----------------------------------------------------------------------- - // query(TemporalQuery) - //----------------------------------------------------------------------- - @Test - public void test_query_chrono() { - assertEquals(TEST_2007_07_15_PONE.query(Queries.chrono()), ISOChrono.INSTANCE); - assertEquals(Queries.chrono().queryFrom(TEST_2007_07_15_PONE), ISOChrono.INSTANCE); - } - - @Test - public void test_query_zoneId() { - assertEquals(TEST_2007_07_15_PONE.query(Queries.zoneId()), null); - assertEquals(Queries.zoneId().queryFrom(TEST_2007_07_15_PONE), null); - } - - @Test - public void test_query_precision() { - assertEquals(TEST_2007_07_15_PONE.query(Queries.precision()), ChronoUnit.DAYS); - assertEquals(Queries.precision().queryFrom(TEST_2007_07_15_PONE), ChronoUnit.DAYS); - } - - @Test - public void test_query_offset() { - assertEquals(TEST_2007_07_15_PONE.query(Queries.offset()), OFFSET_PONE); - assertEquals(Queries.offset().queryFrom(TEST_2007_07_15_PONE), OFFSET_PONE); - } - - @Test - public void test_query_zone() { - assertEquals(TEST_2007_07_15_PONE.query(Queries.zone()), OFFSET_PONE); - assertEquals(Queries.zone().queryFrom(TEST_2007_07_15_PONE), OFFSET_PONE); - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_query_null() { - TEST_2007_07_15_PONE.query(null); - } - - //----------------------------------------------------------------------- - // withOffset() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_withOffset() { - OffsetDate base = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); - OffsetDate test = base.withOffset(OFFSET_PTWO); - assertEquals(test.getDate(), base.getDate()); - assertEquals(test.getOffset(), OFFSET_PTWO); - } - - @Test(groups={"tck"}) - public void test_withOffset_noChange() { - OffsetDate base = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); - OffsetDate test = base.withOffset(OFFSET_PONE); - assertEquals(test, base); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_withOffset_null() { - TEST_2007_07_15_PONE.withOffset(null); - } - - //----------------------------------------------------------------------- - // with(WithAdjuster) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_with_adjustment() { - final OffsetDate sample = OffsetDate.of(LocalDate.of(2012, 3, 4), OFFSET_PONE); - TemporalAdjuster adjuster = new TemporalAdjuster() { - @Override - public Temporal adjustInto(Temporal dateTime) { - return sample; - } - }; - assertEquals(TEST_2007_07_15_PONE.with(adjuster), sample); - } - - @Test(groups={"tck"}) - public void test_with_adjustment_LocalDate() { - OffsetDate test = TEST_2007_07_15_PONE.with(LocalDate.of(2008, 6, 30)); - assertEquals(test, OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_with_adjustment_OffsetDate() { - OffsetDate test = TEST_2007_07_15_PONE.with(OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO)); - assertEquals(test, OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO)); - } - - @Test(groups={"tck"}) - public void test_with_adjustment_ZoneOffset() { - OffsetDate test = TEST_2007_07_15_PONE.with(OFFSET_PTWO); - assertEquals(test, OffsetDate.of(LocalDate.of(2007, 7, 15), OFFSET_PTWO)); - } - - @Test(groups={"tck"}) - public void test_with_adjustment_Month() { - OffsetDate test = TEST_2007_07_15_PONE.with(DECEMBER); - assertEquals(test, OffsetDate.of(LocalDate.of(2007, 12, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_with_adjustment_offsetUnchanged() { - OffsetDate base = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); - OffsetDate test = base.with(Year.of(2008)); - assertEquals(test, base); - } - - @Test(groups={"tck"}) - public void test_with_adjustment_noChange() { - LocalDate date = LocalDate.of(2008, 6, 30); - OffsetDate base = OffsetDate.of(date, OFFSET_PONE); - OffsetDate test = base.with(date); - assertEquals(test, base); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_with_adjustment_null() { - TEST_2007_07_15_PONE.with((TemporalAdjuster) null); - } - - //----------------------------------------------------------------------- - // with(TemporalField, long) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_with_TemporalField() { - OffsetDate test = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); - assertEquals(test.with(ChronoField.YEAR, 2009), OffsetDate.of(LocalDate.of(2009, 6, 30), OFFSET_PONE)); - assertEquals(test.with(ChronoField.MONTH_OF_YEAR, 7), OffsetDate.of(LocalDate.of(2008, 7, 30), OFFSET_PONE)); - assertEquals(test.with(ChronoField.DAY_OF_MONTH, 1), OffsetDate.of(LocalDate.of(2008, 6, 1), OFFSET_PONE)); - assertEquals(test.with(ChronoField.DAY_OF_WEEK, 2), OffsetDate.of(LocalDate.of(2008, 7, 1), OFFSET_PONE)); - assertEquals(test.with(ChronoField.DAY_OF_YEAR, 183), OffsetDate.of(LocalDate.of(2008, 7, 1), OFFSET_PONE)); - - assertEquals(test.with(ChronoField.OFFSET_SECONDS, 7205), OffsetDate.of(LocalDate.of(2008, 6, 30), ZoneOffset.ofHoursMinutesSeconds(2, 0, 5))); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"} ) - public void test_with_TemporalField_null() { - TEST_2007_07_15_PONE.with((TemporalField) null, 0); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"} ) - public void test_with_TemporalField_invalidField() { - TEST_2007_07_15_PONE.with(ChronoField.AMPM_OF_DAY, 0); - } - - //----------------------------------------------------------------------- - // withYear() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_withYear_int_normal() { - OffsetDate t = TEST_2007_07_15_PONE.withYear(2008); - assertEquals(t, OffsetDate.of(LocalDate.of(2008, 7, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_withYear_int_noChange() { - OffsetDate t = TEST_2007_07_15_PONE.withYear(2007); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_withYear_int_invalid() { - TEST_2007_07_15_PONE.withYear(Year.MIN_VALUE - 1); - } - - @Test(groups={"tck"}) - public void test_withYear_int_adjustDay() { - OffsetDate t = OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PONE).withYear(2007); - OffsetDate expected = OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PONE); - assertEquals(t, expected); - } - - //----------------------------------------------------------------------- - // withMonth() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_withMonth_int_normal() { - OffsetDate t = TEST_2007_07_15_PONE.withMonth(1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 1, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_withMonth_int_noChange() { - OffsetDate t = TEST_2007_07_15_PONE.withMonth(7); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_withMonth_int_invalid() { - TEST_2007_07_15_PONE.withMonth(13); - } - - @Test(groups={"tck"}) - public void test_withMonth_int_adjustDay() { - OffsetDate t = OffsetDate.of(LocalDate.of(2007, 12, 31), OFFSET_PONE).withMonth(11); - OffsetDate expected = OffsetDate.of(LocalDate.of(2007, 11, 30), OFFSET_PONE); - assertEquals(t, expected); - } - - //----------------------------------------------------------------------- - // withDayOfMonth() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_withDayOfMonth_normal() { - OffsetDate t = TEST_2007_07_15_PONE.withDayOfMonth(1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 1), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_withDayOfMonth_noChange() { - OffsetDate t = TEST_2007_07_15_PONE.withDayOfMonth(15); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 15), OFFSET_PONE)); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_withDayOfMonth_invalidForMonth() { - OffsetDate.of(LocalDate.of(2007, 11, 30), OFFSET_PONE).withDayOfMonth(31); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_withDayOfMonth_invalidAlways() { - OffsetDate.of(LocalDate.of(2007, 11, 30), OFFSET_PONE).withDayOfMonth(32); - } - - //----------------------------------------------------------------------- - // withDayOfYear(int) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_withDayOfYear_normal() { - OffsetDate t = TEST_2007_07_15_PONE.withDayOfYear(33); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 2, 2), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_withDayOfYear_noChange() { - OffsetDate t = TEST_2007_07_15_PONE.withDayOfYear(31 + 28 + 31 + 30 + 31 + 30 + 15); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_withDayOfYear_illegal() { - TEST_2007_07_15_PONE.withDayOfYear(367); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_withDayOfYear_invalid() { - TEST_2007_07_15_PONE.withDayOfYear(366); - } - - //----------------------------------------------------------------------- - // plus(PlusAdjuster) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_plus_PlusAdjuster() { - MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); - OffsetDate t = TEST_2007_07_15_PONE.plus(period); - assertEquals(t, OffsetDate.of(LocalDate.of(2008, 2, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plus_PlusAdjuster_noChange() { - MockSimplePeriod period = MockSimplePeriod.of(0, ChronoUnit.MONTHS); - OffsetDate t = TEST_2007_07_15_PONE.plus(period); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_plus_PlusAdjuster_zero() { - OffsetDate t = TEST_2007_07_15_PONE.plus(Period.ZERO); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_plus_PlusAdjuster_null() { - TEST_2007_07_15_PONE.plus((TemporalAdder) null); - } - - //----------------------------------------------------------------------- - // plusYears() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_plusYears_long_normal() { - OffsetDate t = TEST_2007_07_15_PONE.plusYears(1); - assertEquals(t, OffsetDate.of(LocalDate.of(2008, 7, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusYears_long_negative() { - OffsetDate t = TEST_2007_07_15_PONE.plusYears(-1); - assertEquals(t, OffsetDate.of(LocalDate.of(2006, 7, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusYears_long_noChange() { - OffsetDate t = TEST_2007_07_15_PONE.plusYears(0); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_plusYears_long_adjustDay() { - OffsetDate t = OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PONE).plusYears(1); - OffsetDate expected = OffsetDate.of(LocalDate.of(2009, 2, 28), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(groups={"tck"}) - public void test_plusYears_long_big() { - long years = 20L + Year.MAX_VALUE; - OffsetDate test = OffsetDate.of(LocalDate.of(-40, 6, 1), OFFSET_PONE).plusYears(years); - assertEquals(test, OffsetDate.of(LocalDate.of((int) (-40L + years), 6, 1), OFFSET_PONE)); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_plusYears_long_invalidTooLarge() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 1, 1), OFFSET_PONE).plusYears(1); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_plusYears_long_invalidTooLargeMaxAddMax() { - OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE); - test.plusYears(Long.MAX_VALUE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_plusYears_long_invalidTooLargeMaxAddMin() { - OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE); - test.plusYears(Long.MIN_VALUE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_plusYears_long_invalidTooSmall() { - OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).plusYears(-1); - } - - //----------------------------------------------------------------------- - // plusMonths() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_plusMonths_long_normal() { - OffsetDate t = TEST_2007_07_15_PONE.plusMonths(1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 8, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusMonths_long_overYears() { - OffsetDate t = TEST_2007_07_15_PONE.plusMonths(25); - assertEquals(t, OffsetDate.of(LocalDate.of(2009, 8, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusMonths_long_negative() { - OffsetDate t = TEST_2007_07_15_PONE.plusMonths(-1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 6, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusMonths_long_negativeAcrossYear() { - OffsetDate t = TEST_2007_07_15_PONE.plusMonths(-7); - assertEquals(t, OffsetDate.of(LocalDate.of(2006, 12, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusMonths_long_negativeOverYears() { - OffsetDate t = TEST_2007_07_15_PONE.plusMonths(-31); - assertEquals(t, OffsetDate.of(LocalDate.of(2004, 12, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusMonths_long_noChange() { - OffsetDate t = TEST_2007_07_15_PONE.plusMonths(0); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_plusMonths_long_adjustDayFromLeapYear() { - OffsetDate t = OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PONE).plusMonths(12); - OffsetDate expected = OffsetDate.of(LocalDate.of(2009, 2, 28), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(groups={"tck"}) - public void test_plusMonths_long_adjustDayFromMonthLength() { - OffsetDate t = OffsetDate.of(LocalDate.of(2007, 3, 31), OFFSET_PONE).plusMonths(1); - OffsetDate expected = OffsetDate.of(LocalDate.of(2007, 4, 30), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(groups={"tck"}) - public void test_plusMonths_long_big() { - long months = 20L + Integer.MAX_VALUE; - OffsetDate test = OffsetDate.of(LocalDate.of(-40, 6, 1), OFFSET_PONE).plusMonths(months); - assertEquals(test, OffsetDate.of(LocalDate.of((int) (-40L + months / 12), 6 + (int) (months % 12), 1), OFFSET_PONE)); - } - - @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) - public void test_plusMonths_long_invalidTooLarge() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE).plusMonths(1); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_plusMonths_long_invalidTooLargeMaxAddMax() { - OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE); - test.plusMonths(Long.MAX_VALUE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_plusMonths_long_invalidTooLargeMaxAddMin() { - OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE); - test.plusMonths(Long.MIN_VALUE); - } - - @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) - public void test_plusMonths_long_invalidTooSmall() { - OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).plusMonths(-1); - } - - //----------------------------------------------------------------------- - // plusWeeks() - //----------------------------------------------------------------------- - @DataProvider(name="samplePlusWeeksSymmetry") - Object[][] provider_samplePlusWeeksSymmetry() { - return new Object[][] { - {OffsetDate.of(LocalDate.of(-1, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(-1, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(-1, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(-1, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(0, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(0, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(0, 2, 29), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(0, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(0, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2007, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2007, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2007, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2008, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2008, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2008, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2008, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2099, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2099, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2099, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2099, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2100, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2100, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2100, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2100, 12, 31), OFFSET_PTWO)}, - }; - } - - @Test(dataProvider="samplePlusWeeksSymmetry", groups={"tck"}) - public void test_plusWeeks_symmetry(OffsetDate reference) { - for (int weeks = 0; weeks < 365 * 8; weeks++) { - OffsetDate t = reference.plusWeeks(weeks).plusWeeks(-weeks); - assertEquals(t, reference); - - t = reference.plusWeeks(-weeks).plusWeeks(weeks); - assertEquals(t, reference); - } - } - - @Test(groups={"tck"}) - public void test_plusWeeks_normal() { - OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 22), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusWeeks_overMonths() { - OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(9); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 9, 16), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusWeeks_overYears() { - OffsetDate t = OffsetDate.of(LocalDate.of(2006, 7, 16), OFFSET_PONE).plusWeeks(52); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_plusWeeks_overLeapYears() { - OffsetDate t = TEST_2007_07_15_PONE.plusYears(-1).plusWeeks(104); - assertEquals(t, OffsetDate.of(LocalDate.of(2008, 7, 12), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusWeeks_negative() { - OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(-1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 8), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusWeeks_negativeAcrossYear() { - OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(-28); - assertEquals(t, OffsetDate.of(LocalDate.of(2006, 12, 31), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusWeeks_negativeOverYears() { - OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(-104); - assertEquals(t, OffsetDate.of(LocalDate.of(2005, 7, 17), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusWeeks_noChange() { - OffsetDate t = TEST_2007_07_15_PONE.plusWeeks(0); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_plusWeeks_maximum() { - OffsetDate t = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 24), OFFSET_PONE).plusWeeks(1); - OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(groups={"tck"}) - public void test_plusWeeks_minimum() { - OffsetDate t = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 8), OFFSET_PONE).plusWeeks(-1); - OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) - public void test_plusWeeks_invalidTooLarge() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 25), OFFSET_PONE).plusWeeks(1); - } - - @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) - public void test_plusWeeks_invalidTooSmall() { - OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 7), OFFSET_PONE).plusWeeks(-1); - } - - @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"}) - public void test_plusWeeks_invalidMaxMinusMax() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 25), OFFSET_PONE).plusWeeks(Long.MAX_VALUE); - } - - @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"}) - public void test_plusWeeks_invalidMaxMinusMin() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 25), OFFSET_PONE).plusWeeks(Long.MIN_VALUE); - } - - //----------------------------------------------------------------------- - // plusDays() - //----------------------------------------------------------------------- - @DataProvider(name="samplePlusDaysSymmetry") - Object[][] provider_samplePlusDaysSymmetry() { - return new Object[][] { - {OffsetDate.of(LocalDate.of(-1, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(-1, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(-1, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(-1, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(0, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(0, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(0, 2, 29), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(0, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(0, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2007, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2007, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2007, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2008, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2008, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2008, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2008, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2099, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2099, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2099, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2099, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2100, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2100, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2100, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2100, 12, 31), OFFSET_PTWO)}, - }; - } - - @Test(dataProvider="samplePlusDaysSymmetry", groups={"tck"}) - public void test_plusDays_symmetry(OffsetDate reference) { - for (int days = 0; days < 365 * 8; days++) { - OffsetDate t = reference.plusDays(days).plusDays(-days); - assertEquals(t, reference); - - t = reference.plusDays(-days).plusDays(days); - assertEquals(t, reference); - } - } - - @Test(groups={"tck"}) - public void test_plusDays_normal() { - OffsetDate t = TEST_2007_07_15_PONE.plusDays(1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 16), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusDays_overMonths() { - OffsetDate t = TEST_2007_07_15_PONE.plusDays(62); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 9, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusDays_overYears() { - OffsetDate t = OffsetDate.of(LocalDate.of(2006, 7, 14), OFFSET_PONE).plusDays(366); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_plusDays_overLeapYears() { - OffsetDate t = TEST_2007_07_15_PONE.plusYears(-1).plusDays(365 + 366); - assertEquals(t, OffsetDate.of(LocalDate.of(2008, 7, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusDays_negative() { - OffsetDate t = TEST_2007_07_15_PONE.plusDays(-1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 14), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusDays_negativeAcrossYear() { - OffsetDate t = TEST_2007_07_15_PONE.plusDays(-196); - assertEquals(t, OffsetDate.of(LocalDate.of(2006, 12, 31), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusDays_negativeOverYears() { - OffsetDate t = TEST_2007_07_15_PONE.plusDays(-730); - assertEquals(t, OffsetDate.of(LocalDate.of(2005, 7, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_plusDays_noChange() { - OffsetDate t = TEST_2007_07_15_PONE.plusDays(0); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_plusDays_maximum() { - OffsetDate t = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 30), OFFSET_PONE).plusDays(1); - OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(groups={"tck"}) - public void test_plusDays_minimum() { - OffsetDate t = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 2), OFFSET_PONE).plusDays(-1); - OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) - public void test_plusDays_invalidTooLarge() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE).plusDays(1); - } - - @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) - public void test_plusDays_invalidTooSmall() { - OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).plusDays(-1); - } - - @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) - public void test_plusDays_overflowTooLarge() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE).plusDays(Long.MAX_VALUE); - } - - @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) - public void test_plusDays_overflowTooSmall() { - OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).plusDays(Long.MIN_VALUE); - } - - //----------------------------------------------------------------------- - // minus(MinusAdjuster) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_minus_MinusAdjuster() { - MockSimplePeriod period = MockSimplePeriod.of(7, ChronoUnit.MONTHS); - OffsetDate t = TEST_2007_07_15_PONE.minus(period); - assertEquals(t, OffsetDate.of(LocalDate.of(2006, 12, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minus_MinusAdjuster_noChange() { - MockSimplePeriod period = MockSimplePeriod.of(0, ChronoUnit.MONTHS); - OffsetDate t = TEST_2007_07_15_PONE.minus(period); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_minus_MinusAdjuster_zero() { - OffsetDate t = TEST_2007_07_15_PONE.minus(Period.ZERO); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_plus_MinusAdjuster_null() { - TEST_2007_07_15_PONE.minus((TemporalSubtractor) null); - } - - //----------------------------------------------------------------------- - // minusYears() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_minusYears_long_normal() { - OffsetDate t = TEST_2007_07_15_PONE.minusYears(1); - assertEquals(t, OffsetDate.of(LocalDate.of(2006, 7, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusYears_long_negative() { - OffsetDate t = TEST_2007_07_15_PONE.minusYears(-1); - assertEquals(t, OffsetDate.of(LocalDate.of(2008, 7, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusYears_long_noChange() { - OffsetDate t = TEST_2007_07_15_PONE.minusYears(0); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_minusYears_long_adjustDay() { - OffsetDate t = OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PONE).minusYears(1); - OffsetDate expected = OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(groups={"tck"}) - public void test_minusYears_long_big() { - long years = 20L + Year.MAX_VALUE; - OffsetDate test = OffsetDate.of(LocalDate.of(40, 6, 1), OFFSET_PONE).minusYears(years); - assertEquals(test, OffsetDate.of(LocalDate.of((int) (40L - years), 6, 1), OFFSET_PONE)); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_minusYears_long_invalidTooLarge() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 1, 1), OFFSET_PONE).minusYears(-1); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_minusYears_long_invalidTooLargeMaxAddMax() { - OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE); - test.minusYears(Long.MAX_VALUE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_minusYears_long_invalidTooLargeMaxAddMin() { - OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE); - test.minusYears(Long.MIN_VALUE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_minusYears_long_invalidTooSmall() { - OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).minusYears(1); - } - - //----------------------------------------------------------------------- - // minusMonths() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_minusMonths_long_normal() { - OffsetDate t = TEST_2007_07_15_PONE.minusMonths(1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 6, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusMonths_long_overYears() { - OffsetDate t = TEST_2007_07_15_PONE.minusMonths(25); - assertEquals(t, OffsetDate.of(LocalDate.of(2005, 6, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusMonths_long_negative() { - OffsetDate t = TEST_2007_07_15_PONE.minusMonths(-1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 8, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusMonths_long_negativeAcrossYear() { - OffsetDate t = TEST_2007_07_15_PONE.minusMonths(-7); - assertEquals(t, OffsetDate.of(LocalDate.of(2008, 2, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusMonths_long_negativeOverYears() { - OffsetDate t = TEST_2007_07_15_PONE.minusMonths(-31); - assertEquals(t, OffsetDate.of(LocalDate.of(2010, 2, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusMonths_long_noChange() { - OffsetDate t = TEST_2007_07_15_PONE.minusMonths(0); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_minusMonths_long_adjustDayFromLeapYear() { - OffsetDate t = OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PONE).minusMonths(12); - OffsetDate expected = OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(groups={"tck"}) - public void test_minusMonths_long_adjustDayFromMonthLength() { - OffsetDate t = OffsetDate.of(LocalDate.of(2007, 3, 31), OFFSET_PONE).minusMonths(1); - OffsetDate expected = OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(groups={"tck"}) - public void test_minusMonths_long_big() { - long months = 20L + Integer.MAX_VALUE; - OffsetDate test = OffsetDate.of(LocalDate.of(40, 6, 1), OFFSET_PONE).minusMonths(months); - assertEquals(test, OffsetDate.of(LocalDate.of((int) (40L - months / 12), 6 - (int) (months % 12), 1), OFFSET_PONE)); - } - - @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) - public void test_minusMonths_long_invalidTooLarge() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE).minusMonths(-1); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_minusMonths_long_invalidTooLargeMaxAddMax() { - OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE); - test.minusMonths(Long.MAX_VALUE); - } - - @Test(expectedExceptions=DateTimeException.class, groups={"tck"}) - public void test_minusMonths_long_invalidTooLargeMaxAddMin() { - OffsetDate test = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 1), OFFSET_PONE); - test.minusMonths(Long.MIN_VALUE); - } - - @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) - public void test_minusMonths_long_invalidTooSmall() { - OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).minusMonths(1); - } - - //----------------------------------------------------------------------- - // minusWeeks() - //----------------------------------------------------------------------- - @DataProvider(name="sampleMinusWeeksSymmetry") - Object[][] provider_sampleMinusWeeksSymmetry() { - return new Object[][] { - {OffsetDate.of(LocalDate.of(-1, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(-1, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(-1, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(-1, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(0, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(0, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(0, 2, 29), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(0, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(0, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2007, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2007, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2007, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2008, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2008, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2008, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2008, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2099, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2099, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2099, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2099, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2100, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2100, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2100, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2100, 12, 31), OFFSET_PTWO)}, - }; - } - - @Test(dataProvider="sampleMinusWeeksSymmetry", groups={"tck"}) - public void test_minusWeeks_symmetry(OffsetDate reference) { - for (int weeks = 0; weeks < 365 * 8; weeks++) { - OffsetDate t = reference.minusWeeks(weeks).minusWeeks(-weeks); - assertEquals(t, reference); - - t = reference.minusWeeks(-weeks).minusWeeks(weeks); - assertEquals(t, reference); - } - } - - @Test(groups={"tck"}) - public void test_minusWeeks_normal() { - OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 8), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusWeeks_overMonths() { - OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(9); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 5, 13), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusWeeks_overYears() { - OffsetDate t = OffsetDate.of(LocalDate.of(2008, 7, 13), OFFSET_PONE).minusWeeks(52); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_minusWeeks_overLeapYears() { - OffsetDate t = TEST_2007_07_15_PONE.minusYears(-1).minusWeeks(104); - assertEquals(t, OffsetDate.of(LocalDate.of(2006, 7, 18), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusWeeks_negative() { - OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(-1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 22), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusWeeks_negativeAcrossYear() { - OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(-28); - assertEquals(t, OffsetDate.of(LocalDate.of(2008, 1, 27), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusWeeks_negativeOverYears() { - OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(-104); - assertEquals(t, OffsetDate.of(LocalDate.of(2009, 7, 12), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusWeeks_noChange() { - OffsetDate t = TEST_2007_07_15_PONE.minusWeeks(0); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_minusWeeks_maximum() { - OffsetDate t = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 24), OFFSET_PONE).minusWeeks(-1); - OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(groups={"tck"}) - public void test_minusWeeks_minimum() { - OffsetDate t = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 8), OFFSET_PONE).minusWeeks(1); - OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) - public void test_minusWeeks_invalidTooLarge() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 25), OFFSET_PONE).minusWeeks(-1); - } - - @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) - public void test_minusWeeks_invalidTooSmall() { - OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 7), OFFSET_PONE).minusWeeks(1); - } - - @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"}) - public void test_minusWeeks_invalidMaxMinusMax() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 25), OFFSET_PONE).minusWeeks(Long.MAX_VALUE); - } - - @Test(expectedExceptions={ArithmeticException.class}, groups={"tck"}) - public void test_minusWeeks_invalidMaxMinusMin() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 25), OFFSET_PONE).minusWeeks(Long.MIN_VALUE); - } - - //----------------------------------------------------------------------- - // minusDays() - //----------------------------------------------------------------------- - @DataProvider(name="sampleMinusDaysSymmetry") - Object[][] provider_sampleMinusDaysSymmetry() { - return new Object[][] { - {OffsetDate.of(LocalDate.of(-1, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(-1, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(-1, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(-1, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(0, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(0, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(0, 2, 29), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(0, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(0, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2007, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2007, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2007, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2007, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2008, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2008, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2008, 2, 29), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2008, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2008, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2099, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2099, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2099, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2099, 12, 31), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2100, 1, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2100, 2, 28), OFFSET_PTWO)}, - {OffsetDate.of(LocalDate.of(2100, 3, 1), OFFSET_PONE)}, - {OffsetDate.of(LocalDate.of(2100, 12, 31), OFFSET_PTWO)}, - }; - } - - @Test(dataProvider="sampleMinusDaysSymmetry", groups={"tck"}) - public void test_minusDays_symmetry(OffsetDate reference) { - for (int days = 0; days < 365 * 8; days++) { - OffsetDate t = reference.minusDays(days).minusDays(-days); - assertEquals(t, reference); - - t = reference.minusDays(-days).minusDays(days); - assertEquals(t, reference); - } - } - - @Test(groups={"tck"}) - public void test_minusDays_normal() { - OffsetDate t = TEST_2007_07_15_PONE.minusDays(1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 14), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusDays_overMonths() { - OffsetDate t = TEST_2007_07_15_PONE.minusDays(62); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 5, 14), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusDays_overYears() { - OffsetDate t = OffsetDate.of(LocalDate.of(2008, 7, 16), OFFSET_PONE).minusDays(367); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_minusDays_overLeapYears() { - OffsetDate t = TEST_2007_07_15_PONE.plusYears(2).minusDays(365 + 366); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_minusDays_negative() { - OffsetDate t = TEST_2007_07_15_PONE.minusDays(-1); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 7, 16), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusDays_negativeAcrossYear() { - OffsetDate t = TEST_2007_07_15_PONE.minusDays(-169); - assertEquals(t, OffsetDate.of(LocalDate.of(2007, 12, 31), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusDays_negativeOverYears() { - OffsetDate t = TEST_2007_07_15_PONE.minusDays(-731); - assertEquals(t, OffsetDate.of(LocalDate.of(2009, 7, 15), OFFSET_PONE)); - } - - @Test(groups={"tck"}) - public void test_minusDays_noChange() { - OffsetDate t = TEST_2007_07_15_PONE.minusDays(0); - assertEquals(t, TEST_2007_07_15_PONE); - } - - @Test(groups={"tck"}) - public void test_minusDays_maximum() { - OffsetDate t = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 30), OFFSET_PONE).minusDays(-1); - OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(groups={"tck"}) - public void test_minusDays_minimum() { - OffsetDate t = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 2), OFFSET_PONE).minusDays(1); - OffsetDate expected = OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE); - assertEquals(t, expected); - } - - @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) - public void test_minusDays_invalidTooLarge() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE).minusDays(-1); - } - - @Test(expectedExceptions={DateTimeException.class}, groups={"tck"}) - public void test_minusDays_invalidTooSmall() { - OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).minusDays(1); - } - - @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) - public void test_minusDays_overflowTooLarge() { - OffsetDate.of(LocalDate.of(Year.MAX_VALUE, 12, 31), OFFSET_PONE).minusDays(Long.MIN_VALUE); - } - - @Test(expectedExceptions=ArithmeticException.class, groups={"tck"}) - public void test_minusDays_overflowTooSmall() { - OffsetDate.of(LocalDate.of(Year.MIN_VALUE, 1, 1), OFFSET_PONE).minusDays(Long.MAX_VALUE); - } - - //----------------------------------------------------------------------- - // atTime() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_atTime_Local() { - OffsetDate t = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO); - assertEquals(t.atTime(LocalTime.of(11, 30)), - OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30), OFFSET_PTWO)); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_atTime_Local_nullLocalTime() { - OffsetDate t = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO); - t.atTime((LocalTime) null); - } - - //----------------------------------------------------------------------- - // getDate() - //----------------------------------------------------------------------- - @Test(dataProvider="sampleDates", groups={"tck"}) - public void test_getDate(int year, int month, int day, ZoneOffset offset) { - LocalDate t = LocalDate.of(year, month, day); - assertEquals(OffsetDate.of(LocalDate.of(year, month, day), offset).getDate(), t); - } - - //----------------------------------------------------------------------- - // compareTo() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_compareTo_date() { - OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 29), OFFSET_PONE); - OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); // a is before b due to date - assertEquals(a.compareTo(b) < 0, true); - assertEquals(b.compareTo(a) > 0, true); - assertEquals(a.compareTo(a) == 0, true); - assertEquals(b.compareTo(b) == 0, true); - assertEquals(a.atTime(LocalTime.MIDNIGHT).toInstant().compareTo(b.atTime(LocalTime.MIDNIGHT).toInstant()) < 0, true); - } - - @Test(groups={"tck"}) - public void test_compareTo_offset() { - OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO); - OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); // a is before b due to offset - assertEquals(a.compareTo(b) < 0, true); - assertEquals(b.compareTo(a) > 0, true); - assertEquals(a.compareTo(a) == 0, true); - assertEquals(b.compareTo(b) == 0, true); - assertEquals(a.atTime(LocalTime.MIDNIGHT).toInstant().compareTo(b.atTime(LocalTime.MIDNIGHT).toInstant()) < 0, true); - } - - @Test(groups={"tck"}) - public void test_compareTo_both() { - OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 29), OFFSET_PTWO); - OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); // a is before b on instant scale - assertEquals(a.compareTo(b) < 0, true); - assertEquals(b.compareTo(a) > 0, true); - assertEquals(a.compareTo(a) == 0, true); - assertEquals(b.compareTo(b) == 0, true); - assertEquals(a.atTime(LocalTime.MIDNIGHT).toInstant().compareTo(b.atTime(LocalTime.MIDNIGHT).toInstant()) < 0, true); - } - - @Test(groups={"tck"}) - public void test_compareTo_24hourDifference() { - OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 29), ZoneOffset.ofHours(-12)); - OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 30), ZoneOffset.ofHours(12)); // a is before b despite being same time-line time - assertEquals(a.compareTo(b) < 0, true); - assertEquals(b.compareTo(a) > 0, true); - assertEquals(a.compareTo(a) == 0, true); - assertEquals(b.compareTo(b) == 0, true); - assertEquals(a.atTime(LocalTime.MIDNIGHT).toInstant().compareTo(b.atTime(LocalTime.MIDNIGHT).toInstant()) == 0, true); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_compareTo_null() { - OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); - a.compareTo(null); - } - - @Test(expectedExceptions=ClassCastException.class, groups={"tck"}) - @SuppressWarnings({"unchecked", "rawtypes"}) - public void compareToNonOffsetDate() { - Comparable c = TEST_2007_07_15_PONE; - c.compareTo(new Object()); - } - - //----------------------------------------------------------------------- - // isAfter() / isBefore() / isEqual() - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_isBeforeIsAfterIsEqual1() { - OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 29), OFFSET_PONE); - OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); // a is before b due to time - assertEquals(a.isBefore(b), true); - assertEquals(a.isEqual(b), false); - assertEquals(a.isAfter(b), false); - - assertEquals(b.isBefore(a), false); - assertEquals(b.isEqual(a), false); - assertEquals(b.isAfter(a), true); - - assertEquals(a.isBefore(a), false); - assertEquals(b.isBefore(b), false); - - assertEquals(a.isEqual(a), true); - assertEquals(b.isEqual(b), true); - - assertEquals(a.isAfter(a), false); - assertEquals(b.isAfter(b), false); - } - - @Test(groups={"tck"}) - public void test_isBeforeIsAfterIsEqual2() { - OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PTWO); - OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); // a is before b due to offset - assertEquals(a.isBefore(b), true); - assertEquals(a.isEqual(b), false); - assertEquals(a.isAfter(b), false); - - assertEquals(b.isBefore(a), false); - assertEquals(b.isEqual(a), false); - assertEquals(b.isAfter(a), true); - - assertEquals(a.isBefore(a), false); - assertEquals(b.isBefore(b), false); - - assertEquals(a.isEqual(a), true); - assertEquals(b.isEqual(b), true); - - assertEquals(a.isAfter(a), false); - assertEquals(b.isAfter(b), false); - } - - @Test(groups={"tck"}) - public void test_isBeforeIsAfterIsEqual_instantComparison() { - OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), ZoneOffset.ofHours(12)); - OffsetDate b = OffsetDate.of(LocalDate.of(2008, 6, 29), ZoneOffset.ofHours(-12)); // a is same instant as b - assertEquals(a.isBefore(b), false); - assertEquals(a.isEqual(b), true); - assertEquals(a.isAfter(b), false); - - assertEquals(b.isBefore(a), false); - assertEquals(b.isEqual(a), true); - assertEquals(b.isAfter(a), false); - - assertEquals(a.isBefore(a), false); - assertEquals(b.isBefore(b), false); - - assertEquals(a.isEqual(a), true); - assertEquals(b.isEqual(b), true); - - assertEquals(a.isAfter(a), false); - assertEquals(b.isAfter(b), false); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_isBefore_null() { - OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); - a.isBefore(null); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_isAfter_null() { - OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); - a.isAfter(null); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_isEqual_null() { - OffsetDate a = OffsetDate.of(LocalDate.of(2008, 6, 30), OFFSET_PONE); - a.isEqual(null); - } - - //----------------------------------------------------------------------- - // equals() / hashCode() - //----------------------------------------------------------------------- - @Test(dataProvider="sampleDates", groups={"tck"}) - public void test_equals_true(int y, int m, int d, ZoneOffset offset) { - OffsetDate a = OffsetDate.of(LocalDate.of(y, m, d), offset); - OffsetDate b = OffsetDate.of(LocalDate.of(y, m, d), offset); - assertEquals(a.equals(b), true); - assertEquals(a.hashCode() == b.hashCode(), true); - } - @Test(dataProvider="sampleDates", groups={"tck"}) - public void test_equals_false_year_differs(int y, int m, int d, ZoneOffset offset) { - OffsetDate a = OffsetDate.of(LocalDate.of(y, m, d), offset); - OffsetDate b = OffsetDate.of(LocalDate.of(y + 1, m, d), offset); - assertEquals(a.equals(b), false); - } - - @Test(dataProvider="sampleDates", groups={"tck"}) - public void test_equals_false_month_differs(int y, int m, int d, ZoneOffset offset) { - OffsetDate a = OffsetDate.of(LocalDate.of(y, m, d), offset); - OffsetDate b = OffsetDate.of(LocalDate.of(y, m + 1, d), offset); - assertEquals(a.equals(b), false); - } - - @Test(dataProvider="sampleDates", groups={"tck"}) - public void test_equals_false_day_differs(int y, int m, int d, ZoneOffset offset) { - OffsetDate a = OffsetDate.of(LocalDate.of(y, m, d), offset); - OffsetDate b = OffsetDate.of(LocalDate.of(y, m, d + 1), offset); - assertEquals(a.equals(b), false); - } - - @Test(dataProvider="sampleDates", groups={"tck"}) - public void test_equals_false_offset_differs(int y, int m, int d, ZoneOffset ignored) { - OffsetDate a = OffsetDate.of(LocalDate.of(y, m, d), OFFSET_PONE); - OffsetDate b = OffsetDate.of(LocalDate.of(y, m, d), OFFSET_PTWO); - assertEquals(a.equals(b), false); - } - - @Test(groups={"tck"}) - public void test_equals_itself_true() { - assertEquals(TEST_2007_07_15_PONE.equals(TEST_2007_07_15_PONE), true); - } - - @Test(groups={"tck"}) - public void test_equals_string_false() { - assertEquals(TEST_2007_07_15_PONE.equals("2007-07-15"), false); - } - - //----------------------------------------------------------------------- - // toString() - //----------------------------------------------------------------------- - @DataProvider(name="sampleToString") - Object[][] provider_sampleToString() { - return new Object[][] { - {2008, 7, 5, "Z", "2008-07-05Z"}, - {2008, 7, 5, "+00", "2008-07-05Z"}, - {2008, 7, 5, "+0000", "2008-07-05Z"}, - {2008, 7, 5, "+00:00", "2008-07-05Z"}, - {2008, 7, 5, "+000000", "2008-07-05Z"}, - {2008, 7, 5, "+00:00:00", "2008-07-05Z"}, - {2008, 7, 5, "-00", "2008-07-05Z"}, - {2008, 7, 5, "-0000", "2008-07-05Z"}, - {2008, 7, 5, "-00:00", "2008-07-05Z"}, - {2008, 7, 5, "-000000", "2008-07-05Z"}, - {2008, 7, 5, "-00:00:00", "2008-07-05Z"}, - {2008, 7, 5, "+01", "2008-07-05+01:00"}, - {2008, 7, 5, "+0100", "2008-07-05+01:00"}, - {2008, 7, 5, "+01:00", "2008-07-05+01:00"}, - {2008, 7, 5, "+010000", "2008-07-05+01:00"}, - {2008, 7, 5, "+01:00:00", "2008-07-05+01:00"}, - {2008, 7, 5, "+0130", "2008-07-05+01:30"}, - {2008, 7, 5, "+01:30", "2008-07-05+01:30"}, - {2008, 7, 5, "+013000", "2008-07-05+01:30"}, - {2008, 7, 5, "+01:30:00", "2008-07-05+01:30"}, - {2008, 7, 5, "+013040", "2008-07-05+01:30:40"}, - {2008, 7, 5, "+01:30:40", "2008-07-05+01:30:40"}, - }; - } - - @Test(dataProvider="sampleToString", groups={"tck"}) - public void test_toString(int y, int m, int d, String offsetId, String expected) { - OffsetDate t = OffsetDate.of(LocalDate.of(y, m, d), ZoneOffset.of(offsetId)); - String str = t.toString(); - assertEquals(str, expected); - } - - //----------------------------------------------------------------------- - // toString(DateTimeFormatter) - //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_toString_formatter() { - DateTimeFormatter f = DateTimeFormatters.pattern("y M d"); - String t = OffsetDate.of(LocalDate.of(2010, 12, 3), OFFSET_PONE).toString(f); - assertEquals(t, "2010 12 3"); - } - - @Test(expectedExceptions=NullPointerException.class, groups={"tck"}) - public void test_toString_formatter_null() { - OffsetDate.of(LocalDate.of(2010, 12, 3), OFFSET_PONE).toString(null); - } - -} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKSimplePeriod.java b/jdk/test/java/time/tck/java/time/temporal/TCKSimplePeriod.java deleted file mode 100644 index d67e6aae297..00000000000 --- a/jdk/test/java/time/tck/java/time/temporal/TCKSimplePeriod.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file: - * - * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of JSR-310 nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package tck.java.time.temporal; - -import static java.time.temporal.ChronoUnit.DAYS; -import static java.time.temporal.ChronoUnit.MONTHS; -import static java.time.temporal.ChronoUnit.NANOS; -import static java.time.temporal.ChronoUnit.SECONDS; -import static java.time.temporal.ChronoUnit.YEARS; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; - -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import java.time.LocalDate; -import java.time.Period; -import java.time.temporal.ISOFields; -import java.time.temporal.SimplePeriod; -import java.time.temporal.TemporalUnit; - -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; -import tck.java.time.AbstractTCKTest; - -/** - * Test. - */ -@Test -public class TCKSimplePeriod extends AbstractTCKTest { - - private static final SimplePeriod TEST_12_MONTHS = SimplePeriod.of(12, MONTHS); - - //----------------------------------------------------------------------- - @Test(dataProvider="samples") - public void test_serialization(long amount, TemporalUnit unit) throws ClassNotFoundException, IOException { - SimplePeriod test = SimplePeriod.of(amount, unit); - assertSerializable(test); - } - - @Test - public void test_serialization_format_zoneOffset() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (DataOutputStream dos = new DataOutputStream(baos) ) { - dos.writeByte(10); - dos.writeLong(12); - } - byte[] bytes = baos.toByteArray(); - assertSerializedBySer(TEST_12_MONTHS, bytes, new byte[0]); - } - - //----------------------------------------------------------------------- - // of(long, TenmporalUnit) - //----------------------------------------------------------------------- - @DataProvider(name="samples") - Object[][] data_samples() { - return new Object[][] { - {0, YEARS}, - {1, YEARS}, - {-1, YEARS}, - {2, MONTHS}, - {-2, MONTHS}, - {43, ISOFields.WEEK_BASED_YEARS}, - {Long.MAX_VALUE, NANOS}, - {Long.MIN_VALUE, NANOS}, - }; - } - - @Test(dataProvider="samples") - public void factory_of(long amount, TemporalUnit unit) { - SimplePeriod test = SimplePeriod.of(amount, unit); - assertEquals(test.getAmount(), amount); - assertEquals(test.getUnit(), unit); - } - - //----------------------------------------------------------------------- - // addTo() - //----------------------------------------------------------------------- - @DataProvider(name="addTo") - Object[][] data_addTo() { - return new Object[][] { - {SimplePeriod.of(0, DAYS), date(2012, 6, 30), date(2012, 6, 30)}, - - {SimplePeriod.of(1, DAYS), date(2012, 6, 30), date(2012, 7, 1)}, - {SimplePeriod.of(-1, DAYS), date(2012, 6, 30), date(2012, 6, 29)}, - - {SimplePeriod.of(2, DAYS), date(2012, 6, 30), date(2012, 7, 2)}, - {SimplePeriod.of(-2, DAYS), date(2012, 6, 30), date(2012, 6, 28)}, - - {SimplePeriod.of(3, MONTHS), date(2012, 5, 31), date(2012, 8, 31)}, - {SimplePeriod.of(4, MONTHS), date(2012, 5, 31), date(2012, 9, 30)}, - {SimplePeriod.of(-3, MONTHS), date(2012, 5, 31), date(2012, 2, 29)}, - {SimplePeriod.of(-4, MONTHS), date(2012, 5, 31), date(2012, 1, 31)}, - }; - } - - @Test(dataProvider="addTo") - public void test_addTo(SimplePeriod period, LocalDate baseDate, LocalDate expected) { - assertEquals(period.addTo(baseDate), expected); - } - - @Test(dataProvider="addTo") - public void test_addTo_usingLocalDatePlus(SimplePeriod period, LocalDate baseDate, LocalDate expected) { - assertEquals(baseDate.plus(period), expected); - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_addTo_nullZero() { - SimplePeriod.of(0, DAYS).addTo(null); - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_addTo_nullNonZero() { - SimplePeriod.of(2, DAYS).addTo(null); - } - - //----------------------------------------------------------------------- - // subtractFrom() - //----------------------------------------------------------------------- - @DataProvider(name="subtractFrom") - Object[][] data_subtractFrom() { - return new Object[][] { - {SimplePeriod.of(0, DAYS), date(2012, 6, 30), date(2012, 6, 30)}, - - {SimplePeriod.of(1, DAYS), date(2012, 6, 30), date(2012, 6, 29)}, - {SimplePeriod.of(-1, DAYS), date(2012, 6, 30), date(2012, 7, 1)}, - - {SimplePeriod.of(2, DAYS), date(2012, 6, 30), date(2012, 6, 28)}, - {SimplePeriod.of(-2, DAYS), date(2012, 6, 30), date(2012, 7, 2)}, - - {SimplePeriod.of(3, MONTHS), date(2012, 5, 31), date(2012, 2, 29)}, - {SimplePeriod.of(4, MONTHS), date(2012, 5, 31), date(2012, 1, 31)}, - {SimplePeriod.of(-3, MONTHS), date(2012, 5, 31), date(2012, 8, 31)}, - {SimplePeriod.of(-4, MONTHS), date(2012, 5, 31), date(2012, 9, 30)}, - }; - } - - @Test(dataProvider="subtractFrom") - public void test_subtractFrom(SimplePeriod period, LocalDate baseDate, LocalDate expected) { - assertEquals(period.subtractFrom(baseDate), expected); - } - - @Test(dataProvider="subtractFrom") - public void test_subtractFrom_usingLocalDateMinus(SimplePeriod period, LocalDate baseDate, LocalDate expected) { - assertEquals(baseDate.minus(period), expected); - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_subtractFrom_nullZero() { - SimplePeriod.of(0, DAYS).subtractFrom(null); - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_subtractFrom_nullNonZero() { - SimplePeriod.of(2, DAYS).subtractFrom(null); - } - - //----------------------------------------------------------------------- - // abs() - //----------------------------------------------------------------------- - @Test(dataProvider="samples") - public void test_abs(long amount, TemporalUnit unit) { - SimplePeriod test = SimplePeriod.of(amount, unit); - if (amount >= 0) { - assertSame(test.abs(), test); // spec requires assertSame - } else if (amount == Long.MIN_VALUE) { - // ignore, separately tested - } else { - assertEquals(test.abs(), SimplePeriod.of(-amount, unit)); - } - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_abs_minValue() { - SimplePeriod.of(Long.MIN_VALUE, SECONDS).abs(); - } - - //----------------------------------------------------------------------- - // equals() / hashCode() - //----------------------------------------------------------------------- - @Test(dataProvider="samples") - public void test_equals(long amount, TemporalUnit unit) { - SimplePeriod test1 = SimplePeriod.of(amount, unit); - SimplePeriod test2 = SimplePeriod.of(amount, unit); - assertEquals(test1, test2); - } - - @Test(dataProvider="samples") - public void test_equals_self(long amount, TemporalUnit unit) { - SimplePeriod test = SimplePeriod.of(amount, unit); - assertEquals(test.equals(test), true); - } - - public void test_equals_null() { - assertEquals(TEST_12_MONTHS.equals(null), false); - } - - public void test_equals_otherClass() { - Period test = Period.of(1, 2, 3, 4, 5, 6); - assertEquals(test.equals(""), false); - } - - //----------------------------------------------------------------------- - public void test_hashCode() { - SimplePeriod test5 = SimplePeriod.of(5, DAYS); - SimplePeriod test6 = SimplePeriod.of(6, DAYS); - SimplePeriod test5M = SimplePeriod.of(5, MONTHS); - SimplePeriod test5Y = SimplePeriod.of(5, YEARS); - assertEquals(test5.hashCode() == test5.hashCode(), true); - assertEquals(test5.hashCode() == test6.hashCode(), false); - assertEquals(test5.hashCode() == test5M.hashCode(), false); - assertEquals(test5.hashCode() == test5Y.hashCode(), false); - } - - //----------------------------------------------------------------------- - // toString() - //----------------------------------------------------------------------- - @Test(dataProvider="samples") - public void test_toString(long amount, TemporalUnit unit) { - SimplePeriod test = SimplePeriod.of(amount, unit); - assertEquals(test.toString(), amount + " " + unit.getName()); - } - - private static LocalDate date(int y, int m, int d) { - return LocalDate.of(y, m, d); - } - -} diff --git a/jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java b/jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java index 9119a70fa65..76789cd00a2 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java +++ b/jdk/test/java/time/tck/java/time/temporal/TCKWeekFields.java @@ -56,310 +56,349 @@ */ package tck.java.time.temporal; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.fail; - -import static java.time.temporal.ChronoField.DAY_OF_WEEK; import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; import static java.time.temporal.ChronoField.DAY_OF_YEAR; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.YEAR; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - import java.time.DayOfWeek; import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.TemporalField; -import java.time.format.DateTimeBuilder; import java.time.temporal.ValueRange; import java.time.temporal.WeekFields; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import tck.java.time.AbstractTCKTest; /** * Test WeekFields. */ @Test -public class TCKWeekFields { +public class TCKWeekFields extends AbstractTCKTest { - @Test(groups={"tck"}) - public void test_WeekFieldsOf() { - for (DayOfWeek dow : DayOfWeek.values()) { - for (int minDays = 1; minDays <= 7; minDays++) { - WeekFields week = WeekFields.of(dow, minDays); - assertEquals(week.getFirstDayOfWeek(), dow, "Incorrect firstDayOfWeek"); - assertEquals(week.getMinimalDaysInFirstWeek(), minDays, "Incorrect MinimalDaysInFirstWeek"); - } - } + @Test(dataProvider="weekFields") + public void test_of_DayOfWeek_int_singleton(DayOfWeek firstDayOfWeek, int minDays) { + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + assertEquals(week.getFirstDayOfWeek(), firstDayOfWeek, "Incorrect firstDayOfWeek"); + assertEquals(week.getMinimalDaysInFirstWeek(), minDays, "Incorrect MinimalDaysInFirstWeek"); + assertSame(WeekFields.of(firstDayOfWeek, minDays), week); } - @Test(groups={"tck"}) - public void test_DayOfWeek() { + //----------------------------------------------------------------------- + @Test + public void test_dayOfWeekField_simpleGet() { + LocalDate date = LocalDate.of(2000, 1, 10); // Known to be ISO Monday + assertEquals(date.get(WeekFields.ISO.dayOfWeek()), 1); + assertEquals(date.get(WeekFields.of(DayOfWeek.MONDAY, 1).dayOfWeek()), 1); + assertEquals(date.get(WeekFields.of(DayOfWeek.MONDAY, 7).dayOfWeek()), 1); + assertEquals(date.get(WeekFields.SUNDAY_START.dayOfWeek()), 2); + assertEquals(date.get(WeekFields.of(DayOfWeek.SUNDAY, 1).dayOfWeek()), 2); + assertEquals(date.get(WeekFields.of(DayOfWeek.SUNDAY, 7).dayOfWeek()), 2); + assertEquals(date.get(WeekFields.of(DayOfWeek.SATURDAY, 1).dayOfWeek()), 3); + assertEquals(date.get(WeekFields.of(DayOfWeek.FRIDAY, 1).dayOfWeek()), 4); + assertEquals(date.get(WeekFields.of(DayOfWeek.TUESDAY, 1).dayOfWeek()), 7); + } + + @Test + public void test_dayOfWeekField_simpleSet() { + LocalDate date = LocalDate.of(2000, 1, 10); // Known to be ISO Monday + assertEquals(date.with(WeekFields.ISO.dayOfWeek(), 2), LocalDate.of(2000, 1, 11)); + assertEquals(date.with(WeekFields.ISO.dayOfWeek(), 7), LocalDate.of(2000, 1, 16)); + + assertEquals(date.with(WeekFields.SUNDAY_START.dayOfWeek(), 3), LocalDate.of(2000, 1, 11)); + assertEquals(date.with(WeekFields.SUNDAY_START.dayOfWeek(), 7), LocalDate.of(2000, 1, 15)); + + assertEquals(date.with(WeekFields.of(DayOfWeek.SATURDAY, 1).dayOfWeek(), 4), LocalDate.of(2000, 1, 11)); + assertEquals(date.with(WeekFields.of(DayOfWeek.TUESDAY, 1).dayOfWeek(), 1), LocalDate.of(2000, 1, 4)); + } + + @Test(dataProvider="weekFields") + public void test_dayOfWeekField(DayOfWeek firstDayOfWeek, int minDays) { LocalDate day = LocalDate.of(2000, 1, 10); // Known to be ISO Monday - for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) { - for (int minDays = 1; minDays <= 7; minDays++) { - WeekFields week = WeekFields.of(firstDayOfWeek, minDays); - TemporalField f = week.dayOfWeek(); - //System.out.printf(" Week: %s; field: %s%n", week, f); + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField f = week.dayOfWeek(); + //System.out.printf(" Week: %s; field: %s%n", week, f); - for (int i = 1; i <= 7; i++) { - //System.out.printf(" ISO Dow: %s, WeekDOW ordinal: %s%n", day.getDayOfWeek(), day.get(f)); - assertEquals(day.get(f), (7 + day.getDayOfWeek().getValue() - firstDayOfWeek.getValue()) % 7 + 1); - day = day.plusDays(1); - } - } + for (int i = 1; i <= 7; i++) { + //System.out.printf(" ISO Dow: %s, WeekDOW ordinal: %s%n", day.getDayOfWeek(), day.get(f)); + assertEquals(day.get(f), (7 + day.getDayOfWeek().getValue() - firstDayOfWeek.getValue()) % 7 + 1); + day = day.plusDays(1); } } - @Test(groups={"tck"}) - public void test_WeekOfMonth() { - for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) { - for (int minDays = 1; minDays <= 7; minDays++) { - LocalDate day = LocalDate.of(2012, 12, 31); // Known to be ISO Monday - WeekFields week = WeekFields.of(firstDayOfWeek, minDays); - TemporalField dowField = week.dayOfWeek(); - TemporalField womField = week.weekOfMonth(); - //System.err.printf("%n Week: %s; dowField: %s, domField: %s%n", week, dowField, womField); + @Test(dataProvider="weekFields") + public void test_weekOfMonthField(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate day = LocalDate.of(2012, 12, 31); // Known to be ISO Monday + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField dowField = week.dayOfWeek(); + TemporalField womField = week.weekOfMonth(); + //System.err.printf("%n Week: %s; dowField: %s, domField: %s%n", week, dowField, womField); - DayOfWeek isoDOW = day.getDayOfWeek(); - int dow = (7 + isoDOW.getValue() - firstDayOfWeek.getValue()) % 7 + 1; + DayOfWeek isoDOW = day.getDayOfWeek(); + int dow = (7 + isoDOW.getValue() - firstDayOfWeek.getValue()) % 7 + 1; - for (int i = 1; i <= 15; i++) { - int actualDOW = day.get(dowField); - int actualWOM = day.get(womField); + for (int i = 1; i <= 15; i++) { + int actualDOW = day.get(dowField); + int actualWOM = day.get(womField); - // Verify that the combination of day of week and week of month can be used - // to reconstruct the same date. - LocalDate day1 = day.withDayOfMonth(1); - int offset = - (day1.get(dowField) - 1); - //System.err.printf(" refDay: %s%n", day1.plusDays(offset)); - int week1 = day1.get(womField); - if (week1 == 0) { - // week of the 1st is partial; start with first full week - offset += 7; - } - //System.err.printf(" refDay2: %s, offset: %d, week1: %d%n", day1.plusDays(offset), offset, week1); - offset += actualDOW - 1; - //System.err.printf(" refDay3: %s%n", day1.plusDays(offset)); - offset += (actualWOM - 1) * 7; - //System.err.printf(" refDay4: %s%n", day1.plusDays(offset)); - LocalDate result = day1.plusDays(offset); - - if (!day.equals(result)) { - System.err.printf("FAIL ISO Dow: %s, offset: %s, actualDOW: %s, actualWOM: %s, expected: %s, result: %s%n", - day.getDayOfWeek(), offset, actualDOW, actualWOM, day, result); - } - assertEquals(result, day, "Incorrect dayOfWeek or weekOfMonth: " - + String.format("%s, ISO Dow: %s, offset: %s, actualDOW: %s, actualWOM: %s, expected: %s, result: %s%n", - week, day.getDayOfWeek(), offset, actualDOW, actualWOM, day, result)); - day = day.plusDays(1); - } + // Verify that the combination of day of week and week of month can be used + // to reconstruct the same date. + LocalDate day1 = day.withDayOfMonth(1); + int offset = - (day1.get(dowField) - 1); + //System.err.printf(" refDay: %s%n", day1.plusDays(offset)); + int week1 = day1.get(womField); + if (week1 == 0) { + // week of the 1st is partial; start with first full week + offset += 7; } + //System.err.printf(" refDay2: %s, offset: %d, week1: %d%n", day1.plusDays(offset), offset, week1); + offset += actualDOW - 1; + //System.err.printf(" refDay3: %s%n", day1.plusDays(offset)); + offset += (actualWOM - 1) * 7; + //System.err.printf(" refDay4: %s%n", day1.plusDays(offset)); + LocalDate result = day1.plusDays(offset); + + if (!day.equals(result)) { + System.err.printf("FAIL ISO Dow: %s, offset: %s, actualDOW: %s, actualWOM: %s, expected: %s, result: %s%n", + day.getDayOfWeek(), offset, actualDOW, actualWOM, day, result); + } + assertEquals(result, day, "Incorrect dayOfWeek or weekOfMonth: " + + String.format("%s, ISO Dow: %s, offset: %s, actualDOW: %s, actualWOM: %s, expected: %s, result: %s%n", + week, day.getDayOfWeek(), offset, actualDOW, actualWOM, day, result)); + day = day.plusDays(1); } } - @Test(groups={"tck"}) - public void test_WeekOfYear() { - for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) { - for (int minDays = 1; minDays <= 7; minDays++) { - LocalDate day = LocalDate.of(2012, 12, 31); // Known to be ISO Monday - WeekFields week = WeekFields.of(firstDayOfWeek, minDays); - TemporalField dowField = week.dayOfWeek(); - TemporalField woyField = week.weekOfYear(); - //System.err.printf("%n Year: %s; dowField: %s, woyField: %s%n", week, dowField, woyField); + @Test(dataProvider="weekFields") + public void test_weekOfYearField(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate day = LocalDate.of(2012, 12, 31); // Known to be ISO Monday + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField dowField = week.dayOfWeek(); + TemporalField woyField = week.weekOfYear(); + //System.err.printf("%n Year: %s; dowField: %s, woyField: %s%n", week, dowField, woyField); - DayOfWeek isoDOW = day.getDayOfWeek(); - int dow = (7 + isoDOW.getValue() - firstDayOfWeek.getValue()) % 7 + 1; + DayOfWeek isoDOW = day.getDayOfWeek(); + int dow = (7 + isoDOW.getValue() - firstDayOfWeek.getValue()) % 7 + 1; - for (int i = 1; i <= 15; i++) { - int actualDOW = day.get(dowField); - int actualWOY = day.get(woyField); + for (int i = 1; i <= 15; i++) { + int actualDOW = day.get(dowField); + int actualWOY = day.get(woyField); - // Verify that the combination of day of week and week of month can be used - // to reconstruct the same date. - LocalDate day1 = day.withDayOfYear(1); - int offset = - (day1.get(dowField) - 1); - //System.err.printf(" refDay: %s%n", day1.plusDays(offset)); - int week1 = day1.get(woyField); - if (week1 == 0) { - // week of the 1st is partial; start with first full week - offset += 7; - } - //System.err.printf(" refDay2: %s, offset: %d, week1: %d%n", day1.plusDays(offset), offset, week1); - offset += actualDOW - 1; - //System.err.printf(" refDay3: %s%n", day1.plusDays(offset)); - offset += (actualWOY - 1) * 7; - //System.err.printf(" refDay4: %s%n", day1.plusDays(offset)); - LocalDate result = day1.plusDays(offset); - - - if (!day.equals(result)) { - System.err.printf("FAIL ISO Dow: %s, offset: %s, actualDOW: %s, actualWOY: %s, expected: %s, result: %s%n", - day.getDayOfWeek(), offset, actualDOW, actualWOY, day, result); - } - assertEquals(result, day, "Incorrect dayOfWeek or weekOfYear " - + String.format("%s, ISO Dow: %s, offset: %s, actualDOW: %s, actualWOM: %s, expected: %s, result: %s%n", - week, day.getDayOfWeek(), offset, actualDOW, actualWOY, day, result)); - day = day.plusDays(1); - } + // Verify that the combination of day of week and week of month can be used + // to reconstruct the same date. + LocalDate day1 = day.withDayOfYear(1); + int offset = - (day1.get(dowField) - 1); + //System.err.printf(" refDay: %s%n", day1.plusDays(offset)); + int week1 = day1.get(woyField); + if (week1 == 0) { + // week of the 1st is partial; start with first full week + offset += 7; } + //System.err.printf(" refDay2: %s, offset: %d, week1: %d%n", day1.plusDays(offset), offset, week1); + offset += actualDOW - 1; + //System.err.printf(" refDay3: %s%n", day1.plusDays(offset)); + offset += (actualWOY - 1) * 7; + //System.err.printf(" refDay4: %s%n", day1.plusDays(offset)); + LocalDate result = day1.plusDays(offset); + + + if (!day.equals(result)) { + System.err.printf("FAIL ISO Dow: %s, offset: %s, actualDOW: %s, actualWOY: %s, expected: %s, result: %s%n", + day.getDayOfWeek(), offset, actualDOW, actualWOY, day, result); + } + assertEquals(result, day, "Incorrect dayOfWeek or weekOfYear " + + String.format("%s, ISO Dow: %s, offset: %s, actualDOW: %s, actualWOM: %s, expected: %s, result: %s%n", + week, day.getDayOfWeek(), offset, actualDOW, actualWOY, day, result)); + day = day.plusDays(1); } } - @Test(groups={"tck"}) - public void test_fieldRanges() { - for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) { - for (int minDays = 1; minDays <= 7; minDays++) { - WeekFields weekDef = WeekFields.of(firstDayOfWeek, minDays); - TemporalField dowField = weekDef.dayOfWeek(); - TemporalField womField = weekDef.weekOfMonth(); - TemporalField woyField = weekDef.weekOfYear(); + @Test(dataProvider="weekFields") + public void test_fieldRanges(DayOfWeek firstDayOfWeek, int minDays) { + WeekFields weekDef = WeekFields.of(firstDayOfWeek, minDays); + TemporalField womField = weekDef.weekOfMonth(); + TemporalField woyField = weekDef.weekOfYear(); - LocalDate day = LocalDate.of(2012, 11, 30); - LocalDate endDay = LocalDate.of(2013, 1, 2); - while (day.isBefore(endDay)) { - LocalDate last = day.with(DAY_OF_MONTH, day.lengthOfMonth()); - int lastWOM = last.get(womField); - LocalDate first = day.with(DAY_OF_MONTH, 1); - int firstWOM = first.get(womField); - ValueRange rangeWOM = day.range(womField); - assertEquals(rangeWOM.getMinimum(), firstWOM, - "Range min should be same as WeekOfMonth for first day of month: " - + first + ", " + weekDef); - assertEquals(rangeWOM.getMaximum(), lastWOM, - "Range max should be same as WeekOfMonth for last day of month: " - + last + ", " + weekDef); + LocalDate day = LocalDate.of(2012, 11, 30); + LocalDate endDay = LocalDate.of(2013, 1, 2); + while (day.isBefore(endDay)) { + LocalDate last = day.with(DAY_OF_MONTH, day.lengthOfMonth()); + int lastWOM = last.get(womField); + LocalDate first = day.with(DAY_OF_MONTH, 1); + int firstWOM = first.get(womField); + ValueRange rangeWOM = day.range(womField); + assertEquals(rangeWOM.getMinimum(), firstWOM, + "Range min should be same as WeekOfMonth for first day of month: " + + first + ", " + weekDef); + assertEquals(rangeWOM.getMaximum(), lastWOM, + "Range max should be same as WeekOfMonth for last day of month: " + + last + ", " + weekDef); - last = day.with(DAY_OF_YEAR, day.lengthOfYear()); - int lastWOY = last.get(woyField); - first = day.with(DAY_OF_YEAR, 1); - int firstWOY = first.get(woyField); - ValueRange rangeWOY = day.range(woyField); - assertEquals(rangeWOY.getMinimum(), firstWOY, - "Range min should be same as WeekOfYear for first day of Year: " - + day + ", " + weekDef); - assertEquals(rangeWOY.getMaximum(), lastWOY, - "Range max should be same as WeekOfYear for last day of Year: " - + day + ", " + weekDef); + last = day.with(DAY_OF_YEAR, day.lengthOfYear()); + int lastWOY = last.get(woyField); + first = day.with(DAY_OF_YEAR, 1); + int firstWOY = first.get(woyField); + ValueRange rangeWOY = day.range(woyField); + assertEquals(rangeWOY.getMinimum(), firstWOY, + "Range min should be same as WeekOfYear for first day of Year: " + + day + ", " + weekDef); + assertEquals(rangeWOY.getMaximum(), lastWOY, + "Range max should be same as WeekOfYear for last day of Year: " + + day + ", " + weekDef); - day = day.plusDays(1); - } - } + day = day.plusDays(1); } } //----------------------------------------------------------------------- // withDayOfWeek() //----------------------------------------------------------------------- - @Test(groups = {"tck"}) - public void test_withDayOfWeek() { - for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) { - for (int minDays = 1; minDays <= 7; minDays++) { - LocalDate day = LocalDate.of(2012, 12, 15); // Safely in the middle of a month - WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + @Test(dataProvider="weekFields") + public void test_withDayOfWeek(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate day = LocalDate.of(2012, 12, 15); // Safely in the middle of a month + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField dowField = week.dayOfWeek(); + TemporalField womField = week.weekOfMonth(); + TemporalField woyField = week.weekOfYear(); - TemporalField dowField = week.dayOfWeek(); - TemporalField womField = week.weekOfMonth(); - TemporalField woyField = week.weekOfYear(); - int wom = day.get(womField); - int woy = day.get(woyField); - for (int dow = 1; dow <= 7; dow++) { - LocalDate result = day.with(dowField, dow); - if (result.get(dowField) != dow) { - System.err.printf(" DOW actual: %d, expected: %d, week:%s%n", - result.get(dowField), dow, week); - } - if (result.get(womField) != wom) { - System.err.printf(" WOM actual: %d, expected: %d, week:%s%n", - result.get(womField), wom, week); - } - if (result.get(woyField) != woy) { - System.err.printf(" WOY actual: %d, expected: %d, week:%s%n", - result.get(woyField), woy, week); - } - assertEquals(result.get(dowField), dow, String.format("Incorrect new Day of week: %s", result)); - assertEquals(result.get(womField), wom, "Week of Month should not change"); - assertEquals(result.get(woyField), woy, "Week of Year should not change"); - } + int wom = day.get(womField); + int woy = day.get(woyField); + for (int dow = 1; dow <= 7; dow++) { + LocalDate result = day.with(dowField, dow); + if (result.get(dowField) != dow) { + System.err.printf(" DOW actual: %d, expected: %d, week:%s%n", + result.get(dowField), dow, week); } + if (result.get(womField) != wom) { + System.err.printf(" WOM actual: %d, expected: %d, week:%s%n", + result.get(womField), wom, week); + } + if (result.get(woyField) != woy) { + System.err.printf(" WOY actual: %d, expected: %d, week:%s%n", + result.get(woyField), woy, week); + } + assertEquals(result.get(dowField), dow, String.format("Incorrect new Day of week: %s", result)); + assertEquals(result.get(womField), wom, "Week of Month should not change"); + assertEquals(result.get(woyField), woy, "Week of Year should not change"); } } - @Test() - public void test_computedFieldResolver() { - // For all starting days of week, for all minDays, for two weeks in Dec 2012 - // Test that when supplied with partial values, that the resolver - // fills in the month - for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) { - for (int minDays = 1; minDays <= 7; minDays++) { - LocalDate day = LocalDate.of(2012, 12, 15); // Safely in the middle of a month - WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + //----------------------------------------------------------------------- + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWom(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate date = LocalDate.of(2012, 12, 15); + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField womField = week.weekOfMonth(); - TemporalField dowField = week.dayOfWeek(); - TemporalField womField = week.weekOfMonth(); - TemporalField woyField = week.weekOfYear(); - int wom = day.get(womField); - int woy = day.get(woyField); - for (int dow = 1; dow <= 15; dow++) { - // Test that with dayOfWeek and Week of month it computes the day of month - DateTimeBuilder builder = new DateTimeBuilder(); - builder.addFieldValue(YEAR, day.get(YEAR)); - builder.addFieldValue(MONTH_OF_YEAR, day.get(MONTH_OF_YEAR)); - builder.addFieldValue(DAY_OF_WEEK, day.get(DAY_OF_WEEK)); - builder.addFieldValue(dowField, day.get(dowField)); - builder.addFieldValue(womField, day.get(womField)); + for (int i = 1; i <= 60; i++) { + // Test that with dayOfWeek and Week of month it computes the date + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(YEAR).appendLiteral('-') + .appendValue(MONTH_OF_YEAR).appendLiteral('-') + .appendValue(womField).appendLiteral('-') + .appendValue(DAY_OF_WEEK).toFormatter(); + String str = date.getYear() + "-" + date.getMonthValue() + "-" + + date.get(womField) + "-" + date.get(DAY_OF_WEEK); + LocalDate parsed = LocalDate.parse(str, f); + assertEquals(parsed, date, " ::" + str + "::" + i); - boolean res1 = dowField.resolve(builder, day.get(dowField)); - boolean res2 = womField.resolve(builder, day.get(womField)); - assertEquals(day.get(DAY_OF_MONTH), day.get(DAY_OF_MONTH)); - assertEquals(day.get(DAY_OF_YEAR), day.get(DAY_OF_YEAR)); - - day = day.plusDays(1); - } - day = LocalDate.of(2012, 12, 15); // Safely in the middle of a month - for (int dow = 1; dow <= 15; dow++) { - // Test that with dayOfWeek and Week of year it computes the day of year - DateTimeBuilder builder = new DateTimeBuilder(); - builder.addFieldValue(YEAR, day.get(YEAR)); - builder.addFieldValue(DAY_OF_WEEK, day.get(DAY_OF_WEEK)); - builder.addFieldValue(dowField, day.get(dowField)); - builder.addFieldValue(woyField, day.get(woyField)); - - boolean res1 = dowField.resolve(builder, day.get(dowField)); - boolean res2 = woyField.resolve(builder, day.get(woyField)); - - assertEquals(day.get(DAY_OF_MONTH), day.get(DAY_OF_MONTH)); - assertEquals(day.get(DAY_OF_YEAR), day.get(DAY_OF_YEAR)); - - day = day.plusDays(1); - } - } + date = date.plusDays(1); } } - @Test(groups = {"tck"}) - public void test_WeekFieldsSingleton() throws IOException, ClassNotFoundException { - for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) { - for (int minDays = 1; minDays <= 7; minDays++) { - WeekFields weekDef = WeekFields.of(firstDayOfWeek, minDays); - WeekFields weekDef2 = WeekFields.of(firstDayOfWeek, minDays); - assertSame(weekDef2, weekDef, "WeekFields same parameters should be same instance"); - try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos)) { - oos.writeObject(weekDef); + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWomDow(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate date = LocalDate.of(2012, 12, 15); + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField dowField = week.dayOfWeek(); + TemporalField womField = week.weekOfMonth(); - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream( - baos.toByteArray())); - WeekFields result = (WeekFields)ois.readObject(); - assertSame(result, weekDef, "Deserialized object same as serialized."); - } - // Exceptions will be handled as failures by TestNG - } + for (int i = 1; i <= 15; i++) { + // Test that with dayOfWeek and Week of month it computes the date + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(YEAR).appendLiteral('-') + .appendValue(MONTH_OF_YEAR).appendLiteral('-') + .appendValue(womField).appendLiteral('-') + .appendValue(dowField).toFormatter(); + String str = date.getYear() + "-" + date.getMonthValue() + "-" + + date.get(womField) + "-" + date.get(dowField); + LocalDate parsed = LocalDate.parse(str, f); + assertEquals(parsed, date, " :: " + str + " " + i); + + date = date.plusDays(1); } } + + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWoy(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate date = LocalDate.of(2012, 12, 15); + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField woyField = week.weekOfYear(); + + for (int i = 1; i <= 60; i++) { + // Test that with dayOfWeek and Week of month it computes the date + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(YEAR).appendLiteral('-') + .appendValue(MONTH_OF_YEAR).appendLiteral('-') + .appendValue(woyField).appendLiteral('-') + .appendValue(DAY_OF_WEEK).toFormatter(); + String str = date.getYear() + "-" + date.getMonthValue() + "-" + + date.get(woyField) + "-" + date.get(DAY_OF_WEEK); + LocalDate parsed = LocalDate.parse(str, f); + assertEquals(parsed, date, " :: " + str + " " + i); + + date = date.plusDays(1); + } + } + + @Test(dataProvider="weekFields") + public void test_parse_resolve_localizedWoyDow(DayOfWeek firstDayOfWeek, int minDays) { + LocalDate date = LocalDate.of(2012, 12, 15); + WeekFields week = WeekFields.of(firstDayOfWeek, minDays); + TemporalField dowField = week.dayOfWeek(); + TemporalField woyField = week.weekOfYear(); + + for (int i = 1; i <= 60; i++) { + // Test that with dayOfWeek and Week of month it computes the date + DateTimeFormatter f = new DateTimeFormatterBuilder() + .appendValue(YEAR).appendLiteral('-') + .appendValue(MONTH_OF_YEAR).appendLiteral('-') + .appendValue(woyField).appendLiteral('-') + .appendValue(dowField).toFormatter(); + String str = date.getYear() + "-" + date.getMonthValue() + "-" + + date.get(woyField) + "-" + date.get(dowField); + LocalDate parsed = LocalDate.parse(str, f); + assertEquals(parsed, date, " :: " + str + " " + i); + + date = date.plusDays(1); + } + } + + //----------------------------------------------------------------------- + @Test(dataProvider="weekFields") + public void test_serializable_singleton(DayOfWeek firstDayOfWeek, int minDays) throws IOException, ClassNotFoundException { + WeekFields weekDef = WeekFields.of(firstDayOfWeek, minDays); + assertSerializableSame(weekDef); // spec state singleton + } + + //----------------------------------------------------------------------- + @DataProvider(name="weekFields") + Object[][] data_weekFields() { + Object[][] objects = new Object[49][]; + int i = 0; + for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) { + for (int minDays = 1; minDays <= 7; minDays++) { + objects[i++] = new Object[] {firstDayOfWeek, minDays}; + } + } + return objects; + } + } diff --git a/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDate.java b/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDate.java index 95caf573a68..6d156839dc8 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDate.java +++ b/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDate.java @@ -63,27 +63,23 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.time.Duration; +import java.time.LocalDate; +import java.time.chrono.Chronology; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.IsoChronology; +import java.time.temporal.ChronoUnit; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalUnit; +import java.time.temporal.ValueRange; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.time.Duration; -import java.time.LocalDate; -import java.time.temporal.Chrono; -import java.time.temporal.ChronoLocalDate; -import java.time.temporal.ChronoUnit; -import java.time.temporal.SimplePeriod; -import java.time.temporal.Temporal; -import java.time.temporal.TemporalAccessor; -import java.time.format.DateTimeBuilder; -import java.time.temporal.TemporalAdder; -import java.time.temporal.TemporalAdjuster; -import java.time.temporal.TemporalField; -import java.time.temporal.TemporalSubtractor; -import java.time.temporal.ValueRange; -import java.time.temporal.TemporalUnit; -import java.time.temporal.ISOChrono; - import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -98,19 +94,19 @@ public class TestChronoLocalDate { // regular data factory for names and descriptions of ISO calendar //----------------------------------------------------------------------- @DataProvider(name = "calendars") - Chrono[][] data_of_calendars() { - return new Chrono[][]{ - {ISOChrono.INSTANCE}, + Chronology[][] data_of_calendars() { + return new Chronology[][]{ + {IsoChronology.INSTANCE}, }; } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badWithAdjusterChrono(Chrono chrono) { + public void test_badWithAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); - ChronoLocalDate date = chrono.date(refDate); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; - ChronoLocalDate date2 = chrono2.date(refDate); + ChronoLocalDate date = chrono.date(refDate); + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; + ChronoLocalDate date2 = chrono2.date(refDate); TemporalAdjuster adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { @@ -121,20 +117,20 @@ public class TestChronoLocalDate { } } else { // Same chronology, - ChronoLocalDate result = date.with(adjuster); + ChronoLocalDate result = date.with(adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badPlusAdjusterChrono(Chrono chrono) { + public void test_badPlusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); - ChronoLocalDate date = chrono.date(refDate); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; - ChronoLocalDate date2 = chrono2.date(refDate); - TemporalAdder adjuster = new FixedAdjuster(date2); + ChronoLocalDate date = chrono.date(refDate); + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; + ChronoLocalDate date2 = chrono2.date(refDate); + TemporalAmount adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { date.plus(adjuster); @@ -144,20 +140,20 @@ public class TestChronoLocalDate { } } else { // Same chronology, - ChronoLocalDate result = date.plus(adjuster); + ChronoLocalDate result = date.plus(adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badMinusAdjusterChrono(Chrono chrono) { + public void test_badMinusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); - ChronoLocalDate date = chrono.date(refDate); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; - ChronoLocalDate date2 = chrono2.date(refDate); - TemporalSubtractor adjuster = new FixedAdjuster(date2); + ChronoLocalDate date = chrono.date(refDate); + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; + ChronoLocalDate date2 = chrono2.date(refDate); + TemporalAmount adjuster = new FixedAdjuster(date2); if (chrono != chrono2) { try { date.minus(adjuster); @@ -167,19 +163,19 @@ public class TestChronoLocalDate { } } else { // Same chronology, - ChronoLocalDate result = date.minus(adjuster); + ChronoLocalDate result = date.minus(adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badPlusTemporalUnitChrono(Chrono chrono) { + public void test_badPlusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); - ChronoLocalDate date = chrono.date(refDate); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; - ChronoLocalDate date2 = chrono2.date(refDate); + ChronoLocalDate date = chrono.date(refDate); + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; + ChronoLocalDate date2 = chrono2.date(refDate); TemporalUnit adjuster = new FixedTemporalUnit(date2); if (chrono != chrono2) { try { @@ -191,19 +187,19 @@ public class TestChronoLocalDate { } } else { // Same chronology, - ChronoLocalDate result = date.plus(1, adjuster); + ChronoLocalDate result = date.plus(1, adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badMinusTemporalUnitChrono(Chrono chrono) { + public void test_badMinusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); - ChronoLocalDate date = chrono.date(refDate); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; - ChronoLocalDate date2 = chrono2.date(refDate); + ChronoLocalDate date = chrono.date(refDate); + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; + ChronoLocalDate date2 = chrono2.date(refDate); TemporalUnit adjuster = new FixedTemporalUnit(date2); if (chrono != chrono2) { try { @@ -215,19 +211,19 @@ public class TestChronoLocalDate { } } else { // Same chronology, - ChronoLocalDate result = date.minus(1, adjuster); + ChronoLocalDate result = date.minus(1, adjuster); assertEquals(result, date2, "WithAdjuster failed to replace date"); } } } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badTemporalFieldChrono(Chrono chrono) { + public void test_badTemporalFieldChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); - ChronoLocalDate date = chrono.date(refDate); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; - ChronoLocalDate date2 = chrono2.date(refDate); + ChronoLocalDate date = chrono.date(refDate); + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; + ChronoLocalDate date2 = chrono2.date(refDate); TemporalField adjuster = new FixedTemporalField(date2); if (chrono != chrono2) { try { @@ -239,7 +235,7 @@ public class TestChronoLocalDate { } } else { // Same chronology, - ChronoLocalDate result = date.with(adjuster, 1); + ChronoLocalDate result = date.with(adjuster, 1); assertEquals(result, date2, "TemporalField doWith() failed to replace date"); } } @@ -249,10 +245,10 @@ public class TestChronoLocalDate { // isBefore, isAfter, isEqual, DATE_COMPARATOR //----------------------------------------------------------------------- @Test(groups={"tck"}, dataProvider="calendars") - public void test_date_comparisons(Chrono chrono) { - List> dates = new ArrayList<>(); + public void test_date_comparisons(Chronology chrono) { + List dates = new ArrayList<>(); - ChronoLocalDate date = chrono.date(LocalDate.of(1900, 1, 1)); + ChronoLocalDate date = chrono.date(LocalDate.of(1900, 1, 1)); // Insert dates in order, no duplicates dates.add(date.minus(1000, ChronoUnit.YEARS)); @@ -272,18 +268,18 @@ public class TestChronoLocalDate { dates.add(date.plus(1000, ChronoUnit.YEARS)); // Check these dates against the corresponding dates for every calendar - for (Chrono[] clist : data_of_calendars()) { - List> otherDates = new ArrayList<>(); - Chrono chrono2 = clist[0]; - for (ChronoLocalDate d : dates) { + for (Chronology[] clist : data_of_calendars()) { + List otherDates = new ArrayList<>(); + Chronology chrono2 = clist[0]; + for (ChronoLocalDate d : dates) { otherDates.add(chrono2.date(d)); } // Now compare the sequence of original dates with the sequence of converted dates for (int i = 0; i < dates.size(); i++) { - ChronoLocalDate a = dates.get(i); + ChronoLocalDate a = dates.get(i); for (int j = 0; j < otherDates.size(); j++) { - ChronoLocalDate b = otherDates.get(j); + ChronoLocalDate b = otherDates.get(j); int cmp = ChronoLocalDate.DATE_COMPARATOR.compare(a, b); if (i < j) { assertTrue(cmp < 0, a + " compare " + b); @@ -307,8 +303,8 @@ public class TestChronoLocalDate { } public void test_date_comparator_checkGenerics_ISO() { - List> dates = new ArrayList<>(); - ChronoLocalDate date = LocalDate.of(1900, 1, 1); + List dates = new ArrayList<>(); + LocalDate date = LocalDate.of(1900, 1, 1); // Insert dates in order, no duplicates dates.add(date.minus(10, ChronoUnit.YEARS)); @@ -323,7 +319,7 @@ public class TestChronoLocalDate { dates.add(date.plus(1, ChronoUnit.YEARS)); dates.add(date.plus(10, ChronoUnit.YEARS)); - List> copy = new ArrayList<>(dates); + List copy = new ArrayList<>(dates); Collections.shuffle(copy); Collections.sort(copy, ChronoLocalDate.DATE_COMPARATOR); assertEquals(copy, dates); @@ -358,9 +354,9 @@ public class TestChronoLocalDate { // Test Serialization of ISO via chrono API //----------------------------------------------------------------------- @Test( groups={"tck"}, dataProvider="calendars") - public > void test_ChronoSerialization(C chrono) throws Exception { + public void test_ChronoSerialization(Chronology chrono) throws Exception { LocalDate ref = LocalDate.of(2000, 1, 5); - ChronoLocalDate orginal = chrono.date(ref); + ChronoLocalDate orginal = chrono.date(ref); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(baos); out.writeObject(orginal); @@ -368,7 +364,7 @@ public class TestChronoLocalDate { ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bais); @SuppressWarnings("unchecked") - ChronoLocalDate ser = (ChronoLocalDate) in.readObject(); + ChronoLocalDate ser = (ChronoLocalDate) in.readObject(); assertEquals(ser, orginal, "deserialized date is wrong"); } @@ -376,7 +372,7 @@ public class TestChronoLocalDate { * FixedAdjusted returns a fixed Temporal in all adjustments. * Construct an adjuster with the Temporal that should be returned from adjust. */ - static class FixedAdjuster implements TemporalAdjuster, TemporalAdder, TemporalSubtractor { + static class FixedAdjuster implements TemporalAdjuster, TemporalAmount { private Temporal datetime; FixedAdjuster(Temporal datetime) { @@ -398,11 +394,21 @@ public class TestChronoLocalDate { return datetime; } + @Override + public long get(TemporalUnit unit) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getUnits() { + throw new UnsupportedOperationException("Not supported yet."); + } + } /** * FixedTemporalUnit returns a fixed Temporal in all adjustments. - * Construct an FixedTemporalUnit with the Temporal that should be returned from doPlus. + * Construct an FixedTemporalUnit with the Temporal that should be returned from addTo. */ static class FixedTemporalUnit implements TemporalUnit { private Temporal temporal; @@ -427,25 +433,25 @@ public class TestChronoLocalDate { } @Override - public boolean isSupported(Temporal temporal) { + public boolean isSupportedBy(Temporal temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override - public R doPlus(R dateTime, long periodToAdd) { + public R addTo(R temporal, long amount) { return (R) this.temporal; } @Override - public SimplePeriod between(R dateTime1, R dateTime2) { + public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException("Not supported yet."); } } /** * FixedTemporalField returns a fixed Temporal in all adjustments. - * Construct an FixedTemporalField with the Temporal that should be returned from doWith. + * Construct an FixedTemporalField with the Temporal that should be returned from adjustInto. */ static class FixedTemporalField implements TemporalField { private Temporal temporal; @@ -474,30 +480,24 @@ public class TestChronoLocalDate { } @Override - public boolean doIsSupported(TemporalAccessor temporal) { + public boolean isSupportedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public ValueRange doRange(TemporalAccessor temporal) { + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public long doGet(TemporalAccessor temporal) { + public long getFrom(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override - public R doWith(R temporal, long newValue) { + public R adjustInto(R temporal, long newValue) { return (R) this.temporal; } - - @Override - public boolean resolve(DateTimeBuilder builder, long value) { - throw new UnsupportedOperationException("Not supported yet."); - } - } } diff --git a/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDateTime.java b/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDateTime.java index c51be6c69b8..46335cedb4f 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDateTime.java +++ b/jdk/test/java/time/tck/java/time/temporal/TestChronoLocalDateTime.java @@ -63,31 +63,28 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.List; - import java.time.Duration; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.time.temporal.Chrono; -import java.time.temporal.ChronoLocalDateTime; +import java.time.chrono.HijrahChronology; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.MinguoChronology; +import java.time.chrono.ThaiBuddhistChronology; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; import java.time.temporal.ChronoUnit; -import java.time.temporal.SimplePeriod; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; -import java.time.format.DateTimeBuilder; -import java.time.temporal.TemporalAdder; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; -import java.time.temporal.TemporalSubtractor; -import java.time.temporal.ValueRange; import java.time.temporal.TemporalUnit; -import java.time.temporal.ISOChrono; -import java.time.calendar.HijrahChrono; -import java.time.calendar.JapaneseChrono; -import java.time.calendar.MinguoChrono; -import java.time.calendar.ThaiBuddhistChrono; +import java.time.temporal.ValueRange; +import java.util.ArrayList; +import java.util.List; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -103,21 +100,21 @@ public class TestChronoLocalDateTime { // regular data factory for names and descriptions of available calendars //----------------------------------------------------------------------- @DataProvider(name = "calendars") - Chrono[][] data_of_calendars() { - return new Chrono[][]{ - {HijrahChrono.INSTANCE}, - {ISOChrono.INSTANCE}, - {JapaneseChrono.INSTANCE}, - {MinguoChrono.INSTANCE}, - {ThaiBuddhistChrono.INSTANCE}}; + Chronology[][] data_of_calendars() { + return new Chronology[][]{ + {HijrahChronology.INSTANCE}, + {IsoChronology.INSTANCE}, + {JapaneseChronology.INSTANCE}, + {MinguoChronology.INSTANCE}, + {ThaiBuddhistChronology.INSTANCE}}; } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badWithAdjusterChrono(Chrono chrono) { + public void test_badWithAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); TemporalAdjuster adjuster = new FixedAdjuster(cdt2); if (chrono != chrono2) { @@ -137,13 +134,13 @@ public class TestChronoLocalDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badPlusAdjusterChrono(Chrono chrono) { + public void test_badPlusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); - TemporalAdder adjuster = new FixedAdjuster(cdt2); + TemporalAmount adjuster = new FixedAdjuster(cdt2); if (chrono != chrono2) { try { cdt.plus(adjuster); @@ -161,13 +158,13 @@ public class TestChronoLocalDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badMinusAdjusterChrono(Chrono chrono) { + public void test_badMinusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); - TemporalSubtractor adjuster = new FixedAdjuster(cdt2); + TemporalAmount adjuster = new FixedAdjuster(cdt2); if (chrono != chrono2) { try { cdt.minus(adjuster); @@ -185,11 +182,11 @@ public class TestChronoLocalDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badPlusTemporalUnitChrono(Chrono chrono) { + public void test_badPlusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); TemporalUnit adjuster = new FixedTemporalUnit(cdt2); if (chrono != chrono2) { @@ -209,11 +206,11 @@ public class TestChronoLocalDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badMinusTemporalUnitChrono(Chrono chrono) { + public void test_badMinusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); TemporalUnit adjuster = new FixedTemporalUnit(cdt2); if (chrono != chrono2) { @@ -233,11 +230,11 @@ public class TestChronoLocalDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badTemporalFieldChrono(Chrono chrono) { + public void test_badTemporalFieldChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoLocalDateTime cdt = chrono.date(refDate).atTime(LocalTime.NOON); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoLocalDateTime cdt2 = chrono2.date(refDate).atTime(LocalTime.NOON); TemporalField adjuster = new FixedTemporalField(cdt2); if (chrono != chrono2) { @@ -260,7 +257,7 @@ public class TestChronoLocalDateTime { // isBefore, isAfter, isEqual //----------------------------------------------------------------------- @Test(groups={"tck"}, dataProvider="calendars") - public void test_datetime_comparisons(Chrono chrono) { + public void test_datetime_comparisons(Chronology chrono) { List> dates = new ArrayList<>(); ChronoLocalDateTime date = chrono.date(LocalDate.of(1900, 1, 1)).atTime(LocalTime.MIN); @@ -287,11 +284,11 @@ public class TestChronoLocalDateTime { dates.add(date.plus(100, ChronoUnit.YEARS)); // Check these dates against the corresponding dates for every calendar - for (Chrono[] clist : data_of_calendars()) { + for (Chronology[] clist : data_of_calendars()) { List> otherDates = new ArrayList<>(); - Chrono chrono2 = clist[0]; + Chronology chrono2 = clist[0]; for (ChronoLocalDateTime d : dates) { - otherDates.add(chrono2.date(d).atTime(d.getTime())); + otherDates.add(chrono2.date(d).atTime(d.toLocalTime())); } // Now compare the sequence of original dates with the sequence of converted dates @@ -325,9 +322,9 @@ public class TestChronoLocalDateTime { // Test Serialization of ISO via chrono API //----------------------------------------------------------------------- @Test( groups={"tck"}, dataProvider="calendars") - public > void test_ChronoLocalDateTimeSerialization(C chrono) throws Exception { + public void test_ChronoLocalDateTimeSerialization(Chronology chrono) throws Exception { LocalDateTime ref = LocalDate.of(2000, 1, 5).atTime(12, 1, 2, 3); - ChronoLocalDateTime orginal = chrono.date(ref).atTime(ref.getTime()); + ChronoLocalDateTime orginal = chrono.date(ref).atTime(ref.toLocalTime()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(baos); out.writeObject(orginal); @@ -335,7 +332,7 @@ public class TestChronoLocalDateTime { ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bais); @SuppressWarnings("unchecked") - ChronoLocalDateTime ser = (ChronoLocalDateTime) in.readObject(); + ChronoLocalDateTime ser = (ChronoLocalDateTime) in.readObject(); assertEquals(ser, orginal, "deserialized date is wrong"); } @@ -343,7 +340,7 @@ public class TestChronoLocalDateTime { * FixedAdjusted returns a fixed Temporal in all adjustments. * Construct an adjuster with the Temporal that should be returned from adjust. */ - static class FixedAdjuster implements TemporalAdjuster, TemporalAdder, TemporalSubtractor { + static class FixedAdjuster implements TemporalAdjuster, TemporalAmount { private Temporal datetime; FixedAdjuster(Temporal datetime) { @@ -365,11 +362,21 @@ public class TestChronoLocalDateTime { return datetime; } + @Override + public long get(TemporalUnit unit) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getUnits() { + throw new UnsupportedOperationException("Not supported yet."); + } + } /** * FixedTemporalUnit returns a fixed Temporal in all adjustments. - * Construct an FixedTemporalUnit with the Temporal that should be returned from doPlus. + * Construct an FixedTemporalUnit with the Temporal that should be returned from addTo. */ static class FixedTemporalUnit implements TemporalUnit { private Temporal temporal; @@ -394,25 +401,25 @@ public class TestChronoLocalDateTime { } @Override - public boolean isSupported(Temporal temporal) { + public boolean isSupportedBy(Temporal temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override - public R doPlus(R dateTime, long periodToAdd) { + public R addTo(R temporal, long amount) { return (R) this.temporal; } @Override - public SimplePeriod between(R dateTime1, R dateTime2) { + public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException("Not supported yet."); } } /** * FixedTemporalField returns a fixed Temporal in all adjustments. - * Construct an FixedTemporalField with the Temporal that should be returned from doWith. + * Construct an FixedTemporalField with the Temporal that should be returned from adjustInto. */ static class FixedTemporalField implements TemporalField { private Temporal temporal; @@ -441,30 +448,24 @@ public class TestChronoLocalDateTime { } @Override - public boolean doIsSupported(TemporalAccessor temporal) { + public boolean isSupportedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public ValueRange doRange(TemporalAccessor temporal) { + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public long doGet(TemporalAccessor temporal) { + public long getFrom(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override - public R doWith(R temporal, long newValue) { + public R adjustInto(R temporal, long newValue) { return (R) this.temporal; } - - @Override - public boolean resolve(DateTimeBuilder builder, long value) { - throw new UnsupportedOperationException("Not supported yet."); - } - } } diff --git a/jdk/test/java/time/tck/java/time/temporal/TestChronoZonedDateTime.java b/jdk/test/java/time/tck/java/time/temporal/TestChronoZonedDateTime.java index e89725bb3d3..c97a0181003 100644 --- a/jdk/test/java/time/tck/java/time/temporal/TestChronoZonedDateTime.java +++ b/jdk/test/java/time/tck/java/time/temporal/TestChronoZonedDateTime.java @@ -63,33 +63,30 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.List; - import java.time.Duration; import java.time.LocalDate; import java.time.LocalTime; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; -import java.time.temporal.Chrono; +import java.time.chrono.HijrahChronology; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.MinguoChronology; +import java.time.chrono.ThaiBuddhistChronology; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ChronoZonedDateTime; +import java.time.chrono.Chronology; +import java.time.chrono.IsoChronology; import java.time.temporal.ChronoUnit; -import java.time.temporal.ChronoZonedDateTime; -import java.time.temporal.SimplePeriod; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; -import java.time.format.DateTimeBuilder; -import java.time.temporal.TemporalAdder; import java.time.temporal.TemporalAdjuster; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalField; -import java.time.temporal.TemporalSubtractor; -import java.time.temporal.ValueRange; -import java.time.temporal.ISOChrono; import java.time.temporal.TemporalUnit; -import java.time.calendar.HijrahChrono; -import java.time.calendar.JapaneseChrono; -import java.time.calendar.MinguoChrono; -import java.time.calendar.ThaiBuddhistChrono; +import java.time.temporal.ValueRange; +import java.util.ArrayList; +import java.util.List; import org.testng.Assert; import org.testng.annotations.DataProvider; @@ -105,22 +102,22 @@ public class TestChronoZonedDateTime { // regular data factory for names and descriptions of available calendars //----------------------------------------------------------------------- @DataProvider(name = "calendars") - Chrono[][] data_of_calendars() { - return new Chrono[][]{ - {HijrahChrono.INSTANCE}, - {ISOChrono.INSTANCE}, - {JapaneseChrono.INSTANCE}, - {MinguoChrono.INSTANCE}, - {ThaiBuddhistChrono.INSTANCE}, + Chronology[][] data_of_calendars() { + return new Chronology[][]{ + {HijrahChronology.INSTANCE}, + {IsoChronology.INSTANCE}, + {JapaneseChronology.INSTANCE}, + {MinguoChronology.INSTANCE}, + {ThaiBuddhistChronology.INSTANCE}, }; } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badWithAdjusterChrono(Chrono chrono) { + public void test_badWithAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoZonedDateTime czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoZonedDateTime czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); TemporalAdjuster adjuster = new FixedAdjuster(czdt2); if (chrono != chrono2) { @@ -139,13 +136,13 @@ public class TestChronoZonedDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badPlusAdjusterChrono(Chrono chrono) { + public void test_badPlusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoZonedDateTime czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoZonedDateTime czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); - TemporalAdder adjuster = new FixedAdjuster(czdt2); + TemporalAmount adjuster = new FixedAdjuster(czdt2); if (chrono != chrono2) { try { czdt.plus(adjuster); @@ -163,13 +160,13 @@ public class TestChronoZonedDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badMinusAdjusterChrono(Chrono chrono) { + public void test_badMinusAdjusterChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoZonedDateTime czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoZonedDateTime czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); - TemporalSubtractor adjuster = new FixedAdjuster(czdt2); + TemporalAmount adjuster = new FixedAdjuster(czdt2); if (chrono != chrono2) { try { czdt.minus(adjuster); @@ -187,11 +184,11 @@ public class TestChronoZonedDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badPlusTemporalUnitChrono(Chrono chrono) { + public void test_badPlusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoZonedDateTime czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoZonedDateTime czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); TemporalUnit adjuster = new FixedTemporalUnit(czdt2); if (chrono != chrono2) { @@ -211,11 +208,11 @@ public class TestChronoZonedDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badMinusTemporalUnitChrono(Chrono chrono) { + public void test_badMinusTemporalUnitChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoZonedDateTime czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoZonedDateTime czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); TemporalUnit adjuster = new FixedTemporalUnit(czdt2); if (chrono != chrono2) { @@ -235,11 +232,11 @@ public class TestChronoZonedDateTime { } @Test(groups={"tck"}, dataProvider="calendars") - public void test_badTemporalFieldChrono(Chrono chrono) { + public void test_badTemporalFieldChrono(Chronology chrono) { LocalDate refDate = LocalDate.of(1900, 1, 1); ChronoZonedDateTime czdt = chrono.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); - for (Chrono[] clist : data_of_calendars()) { - Chrono chrono2 = clist[0]; + for (Chronology[] clist : data_of_calendars()) { + Chronology chrono2 = clist[0]; ChronoZonedDateTime czdt2 = chrono2.date(refDate).atTime(LocalTime.NOON).atZone(ZoneOffset.UTC); TemporalField adjuster = new FixedTemporalField(czdt2); if (chrono != chrono2) { @@ -259,10 +256,10 @@ public class TestChronoZonedDateTime { } //----------------------------------------------------------------------- - // isBefore, isAfter, isEqual, INSTANT_COMPARATOR test a Chrono against the other Chronos + // isBefore, isAfter, isEqual, INSTANT_COMPARATOR test a Chronology against the other Chronos //----------------------------------------------------------------------- @Test(groups={"tck"}, dataProvider="calendars") - public void test_zonedDateTime_comparisons(Chrono chrono) { + public void test_zonedDateTime_comparisons(Chronology chrono) { List> dates = new ArrayList<>(); ChronoZonedDateTime date = chrono.date(LocalDate.of(1900, 1, 1)) @@ -291,11 +288,11 @@ public class TestChronoZonedDateTime { dates.add(date.plus(100, ChronoUnit.YEARS)); // Check these dates against the corresponding dates for every calendar - for (Chrono[] clist : data_of_calendars()) { + for (Chronology[] clist : data_of_calendars()) { List> otherDates = new ArrayList<>(); - Chrono chrono2 = ISOChrono.INSTANCE; //clist[0]; + Chronology chrono2 = IsoChronology.INSTANCE; //clist[0]; for (ChronoZonedDateTime d : dates) { - otherDates.add(chrono2.date(d).atTime(d.getTime()).atZone(d.getZone())); + otherDates.add(chrono2.date(d).atTime(d.toLocalTime()).atZone(d.getZone())); } // Now compare the sequence of original dates with the sequence of converted dates @@ -329,9 +326,9 @@ public class TestChronoZonedDateTime { // Test Serialization of ISO via chrono API //----------------------------------------------------------------------- @Test( groups={"tck"}, dataProvider="calendars") - public > void test_ChronoZonedDateTimeSerialization(C chrono) throws Exception { + public void test_ChronoZonedDateTimeSerialization(Chronology chrono) throws Exception { ZonedDateTime ref = LocalDate.of(2000, 1, 5).atTime(12, 1, 2, 3).atZone(ZoneId.of("GMT+01:23")); - ChronoZonedDateTime orginal = chrono.date(ref).atTime(ref.getTime()).atZone(ref.getZone()); + ChronoZonedDateTime orginal = chrono.date(ref).atTime(ref.toLocalTime()).atZone(ref.getZone()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(baos); out.writeObject(orginal); @@ -339,7 +336,7 @@ public class TestChronoZonedDateTime { ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream in = new ObjectInputStream(bais); @SuppressWarnings("unchecked") - ChronoZonedDateTime ser = (ChronoZonedDateTime) in.readObject(); + ChronoZonedDateTime ser = (ChronoZonedDateTime) in.readObject(); assertEquals(ser, orginal, "deserialized date is wrong"); } @@ -348,7 +345,7 @@ public class TestChronoZonedDateTime { * FixedAdjusted returns a fixed Temporal in all adjustments. * Construct an adjuster with the Temporal that should be returned from adjust. */ - static class FixedAdjuster implements TemporalAdjuster, TemporalAdder, TemporalSubtractor { + static class FixedAdjuster implements TemporalAdjuster, TemporalAmount { private Temporal datetime; FixedAdjuster(Temporal datetime) { @@ -370,11 +367,21 @@ public class TestChronoZonedDateTime { return datetime; } + @Override + public long get(TemporalUnit unit) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getUnits() { + throw new UnsupportedOperationException("Not supported yet."); + } + } /** * FixedTemporalUnit returns a fixed Temporal in all adjustments. - * Construct an FixedTemporalUnit with the Temporal that should be returned from doPlus. + * Construct an FixedTemporalUnit with the Temporal that should be returned from addTo. */ static class FixedTemporalUnit implements TemporalUnit { private Temporal temporal; @@ -399,25 +406,25 @@ public class TestChronoZonedDateTime { } @Override - public boolean isSupported(Temporal temporal) { + public boolean isSupportedBy(Temporal temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override - public R doPlus(R dateTime, long periodToAdd) { + public R addTo(R temporal, long amount) { return (R) this.temporal; } @Override - public SimplePeriod between(R dateTime1, R dateTime2) { + public long between(Temporal temporal1, Temporal temporal2) { throw new UnsupportedOperationException("Not supported yet."); } } /** * FixedTemporalField returns a fixed Temporal in all adjustments. - * Construct an FixedTemporalField with the Temporal that should be returned from doWith. + * Construct an FixedTemporalField with the Temporal that should be returned from adjustInto. */ static class FixedTemporalField implements TemporalField { private Temporal temporal; @@ -446,30 +453,24 @@ public class TestChronoZonedDateTime { } @Override - public boolean doIsSupported(TemporalAccessor temporal) { + public boolean isSupportedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public ValueRange doRange(TemporalAccessor temporal) { + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @Override - public long doGet(TemporalAccessor temporal) { + public long getFrom(TemporalAccessor temporal) { throw new UnsupportedOperationException("Not supported yet."); } @SuppressWarnings("unchecked") @Override - public R doWith(R temporal, long newValue) { + public R adjustInto(R temporal, long newValue) { return (R) this.temporal; } - - @Override - public boolean resolve(DateTimeBuilder builder, long value) { - throw new UnsupportedOperationException("Not supported yet."); - } - } } diff --git a/jdk/test/java/time/tck/java/time/zone/TCKFixedZoneRules.java b/jdk/test/java/time/tck/java/time/zone/TCKFixedZoneRules.java index 08617bae23b..3cf6053a2da 100644 --- a/jdk/test/java/time/tck/java/time/zone/TCKFixedZoneRules.java +++ b/jdk/test/java/time/tck/java/time/zone/TCKFixedZoneRules.java @@ -59,9 +59,6 @@ */ package tck.java.time.zone; -import java.time.zone.*; -import test.java.time.zone.*; - import static org.testng.Assert.assertEquals; import java.io.ByteArrayInputStream; @@ -75,7 +72,10 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; import java.time.ZoneOffset; +import java.time.zone.ZoneOffsetTransition; +import java.time.zone.ZoneOffsetTransitionRule; import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition; +import java.time.zone.ZoneRules; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; diff --git a/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.java b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.java index 36dc4ba0800..f98b82f1f18 100644 --- a/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.java +++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransition.java @@ -59,19 +59,15 @@ */ package tck.java.time.zone; -import java.time.temporal.Year; -import java.time.zone.*; - import static java.time.temporal.ChronoUnit.HOURS; import static org.testng.Assert.assertEquals; -import java.io.IOException; - import tck.java.time.AbstractTCKTest; import java.time.Duration; import java.time.LocalDateTime; import java.time.ZoneOffset; - +import java.time.Year; +import java.time.zone.ZoneOffsetTransition; import org.testng.annotations.Test; /** diff --git a/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java index f98d7141b16..c98ddf02102 100644 --- a/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java +++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java @@ -59,22 +59,16 @@ */ package tck.java.time.zone; -import java.time.ZoneId; -import java.time.zone.*; -import test.java.time.zone.*; - import static org.testng.Assert.assertEquals; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; - import tck.java.time.AbstractTCKTest; import java.time.DayOfWeek; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; import java.time.ZoneOffset; +import java.time.zone.ZoneOffsetTransition; +import java.time.zone.ZoneOffsetTransitionRule; import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition; import org.testng.annotations.Test; diff --git a/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java b/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java index 294e2e07cb2..5feac51ecac 100644 --- a/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java +++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneRules.java @@ -59,9 +59,6 @@ */ package tck.java.time.zone; -import java.time.temporal.Year; -import java.time.zone.*; - import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; @@ -81,10 +78,14 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.Month; +import java.time.Year; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.zone.ZoneOffsetTransition; +import java.time.zone.ZoneOffsetTransitionRule; import java.time.zone.ZoneOffsetTransitionRule.TimeDefinition; +import java.time.zone.ZoneRules; import org.testng.annotations.Test; @@ -142,7 +143,7 @@ public class TCKZoneRules { Instant instant = old.toInstant(); ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(0, -1, -15); assertEquals(test.getOffset(instant), offset); - checkOffset(test, old.getDateTime(), offset, 1); + checkOffset(test, old.toLocalDateTime(), offset, 1); assertEquals(test.getStandardOffset(instant), offset); assertEquals(test.getDaylightSavings(instant), Duration.ZERO); assertEquals(test.isDaylightSavings(instant), false); @@ -522,7 +523,7 @@ public class TCKZoneRules { Instant instant = old.toInstant(); ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(0, 9, 21); assertEquals(test.getOffset(instant), offset); - checkOffset(test, old.getDateTime(), offset, 1); + checkOffset(test, old.toLocalDateTime(), offset, 1); assertEquals(test.getStandardOffset(instant), offset); assertEquals(test.getDaylightSavings(instant), Duration.ZERO); assertEquals(test.isDaylightSavings(instant), false); @@ -672,13 +673,13 @@ public class TCKZoneRules { ZonedDateTime zdt = createZDT(1840, 1, 1, ZoneOffset.UTC); while (zdt.getYear() < 2010) { Instant instant = zdt.toInstant(); - if (zdt.getDate().isBefore(LocalDate.of(1911, 3, 11))) { + if (zdt.toLocalDate().isBefore(LocalDate.of(1911, 3, 11))) { assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHoursMinutesSeconds(0, 9, 21)); - } else if (zdt.getDate().isBefore(LocalDate.of(1940, 6, 14))) { + } else if (zdt.toLocalDate().isBefore(LocalDate.of(1940, 6, 14))) { assertEquals(test.getStandardOffset(instant), OFFSET_ZERO); - } else if (zdt.getDate().isBefore(LocalDate.of(1944, 8, 25))) { + } else if (zdt.toLocalDate().isBefore(LocalDate.of(1944, 8, 25))) { assertEquals(test.getStandardOffset(instant), OFFSET_PONE); - } else if (zdt.getDate().isBefore(LocalDate.of(1945, 9, 16))) { + } else if (zdt.toLocalDate().isBefore(LocalDate.of(1945, 9, 16))) { assertEquals(test.getStandardOffset(instant), OFFSET_ZERO); } else { assertEquals(test.getStandardOffset(instant), OFFSET_PONE); @@ -705,7 +706,7 @@ public class TCKZoneRules { Instant instant = old.toInstant(); ZoneOffset offset = ZoneOffset.of("-04:56:02"); assertEquals(test.getOffset(instant), offset); - checkOffset(test, old.getDateTime(), offset, 1); + checkOffset(test, old.toLocalDateTime(), offset, 1); assertEquals(test.getStandardOffset(instant), offset); assertEquals(test.getDaylightSavings(instant), Duration.ZERO); assertEquals(test.isDaylightSavings(instant), false); @@ -878,7 +879,7 @@ public class TCKZoneRules { ZonedDateTime dateTime = createZDT(1860, 1, 1, ZoneOffset.UTC); while (dateTime.getYear() < 2010) { Instant instant = dateTime.toInstant(); - if (dateTime.getDate().isBefore(LocalDate.of(1883, 11, 18))) { + if (dateTime.toLocalDate().isBefore(LocalDate.of(1883, 11, 18))) { assertEquals(test.getStandardOffset(instant), ZoneOffset.of("-04:56:02")); } else { assertEquals(test.getStandardOffset(instant), ZoneOffset.ofHours(-5)); diff --git a/jdk/test/java/time/tck/java/time/zone/TCKZoneRulesProvider.java b/jdk/test/java/time/tck/java/time/zone/TCKZoneRulesProvider.java index 2d245f66115..a8081268ee4 100644 --- a/jdk/test/java/time/tck/java/time/zone/TCKZoneRulesProvider.java +++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneRulesProvider.java @@ -59,8 +59,7 @@ */ package tck.java.time.zone; -import java.time.zone.*; -import test.java.time.zone.*; +import java.time.ZoneId; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -73,6 +72,9 @@ import java.util.Set; import java.util.TreeMap; import java.time.ZoneOffset; +import java.time.zone.ZoneRules; +import java.time.zone.ZoneRulesException; +import java.time.zone.ZoneRulesProvider; import org.testng.annotations.Test; @@ -87,7 +89,7 @@ public class TCKZoneRulesProvider { //----------------------------------------------------------------------- // getAvailableZoneIds() //----------------------------------------------------------------------- - @Test(groups={"tck"}) + @Test public void test_getAvailableGroupIds() { Set zoneIds = ZoneRulesProvider.getAvailableZoneIds(); assertEquals(zoneIds.contains("Europe/London"), true); @@ -98,34 +100,48 @@ public class TCKZoneRulesProvider { } //----------------------------------------------------------------------- - // getRules(String) + // getRules(String, boolean) //----------------------------------------------------------------------- - @Test(groups={"tck"}) - public void test_getRules_String() { - ZoneRules rules = ZoneRulesProvider.getRules("Europe/London"); + @Test + public void test_getRules_StringBoolean() { + ZoneRules rules = ZoneRulesProvider.getRules("Europe/London", false); assertNotNull(rules); - ZoneRules rules2 = ZoneRulesProvider.getRules("Europe/London"); + ZoneRules rules2 = ZoneRulesProvider.getRules("Europe/London", false); assertEquals(rules2, rules); } - @Test(groups={"tck"}, expectedExceptions=ZoneRulesException.class) - public void test_getRules_String_unknownId() { - ZoneRulesProvider.getRules("Europe/Lon"); + @Test(expectedExceptions=ZoneRulesException.class) + public void test_getRules_StringBoolean_unknownId() { + ZoneRulesProvider.getRules("Europe/Lon", false); } - @Test(groups={"tck"}, expectedExceptions=NullPointerException.class) - public void test_getRules_String_null() { - ZoneRulesProvider.getRules(null); + @Test(expectedExceptions=NullPointerException.class) + public void test_getRules_StringBoolean_null() { + ZoneRulesProvider.getRules(null, false); + } + + @Test + public void test_getRules_StringBoolean_dynamic() { + MockDynamicProvider dynamicProvider = new MockDynamicProvider(); + ZoneRulesProvider.registerProvider(dynamicProvider); + + assertEquals(dynamicProvider.count, 0); + ZoneRules rules1 = ZoneId.of("DynamicLocation").getRules(); + assertEquals(dynamicProvider.count, 2); + assertEquals(rules1, dynamicProvider.BASE); + ZoneRules rules2 = ZoneId.of("DynamicLocation").getRules(); + assertEquals(dynamicProvider.count, 4); + assertEquals(rules2, dynamicProvider.ALTERNATE); } //----------------------------------------------------------------------- // getVersions(String) //----------------------------------------------------------------------- - @Test(groups={"tck"}) + @Test public void test_getVersions_String() { NavigableMap versions = ZoneRulesProvider.getVersions("Europe/London"); assertTrue(versions.size() >= 1); - ZoneRules rules = ZoneRulesProvider.getRules("Europe/London"); + ZoneRules rules = ZoneRulesProvider.getRules("Europe/London", false); assertEquals(versions.lastEntry().getValue(), rules); NavigableMap copy = new TreeMap<>(versions); @@ -135,12 +151,12 @@ public class TCKZoneRulesProvider { assertEquals(versions2, copy); } - @Test(groups={"tck"}, expectedExceptions=ZoneRulesException.class) + @Test(expectedExceptions=ZoneRulesException.class) public void test_getVersions_String_unknownId() { ZoneRulesProvider.getVersions("Europe/Lon"); } - @Test(groups={"tck"}, expectedExceptions=NullPointerException.class) + @Test(expectedExceptions=NullPointerException.class) public void test_getVersions_String_null() { ZoneRulesProvider.getVersions(null); } @@ -148,7 +164,7 @@ public class TCKZoneRulesProvider { //----------------------------------------------------------------------- // refresh() //----------------------------------------------------------------------- - @Test(groups={"tck"}) + @Test public void test_refresh() { assertEquals(ZoneRulesProvider.refresh(), false); } @@ -164,8 +180,7 @@ public class TCKZoneRulesProvider { assertEquals(pre.contains("FooLocation"), false); Set post = ZoneRulesProvider.getAvailableZoneIds(); assertEquals(post.contains("FooLocation"), true); - - assertEquals(ZoneRulesProvider.getRules("FooLocation"), ZoneOffset.of("+01:45").getRules()); + assertEquals(ZoneRulesProvider.getRules("FooLocation", false), ZoneOffset.of("+01:45").getRules()); } static class MockTempProvider extends ZoneRulesProvider { @@ -175,17 +190,13 @@ public class TCKZoneRulesProvider { return new HashSet(Collections.singleton("FooLocation")); } @Override - protected ZoneRulesProvider provideBind(String zoneId) { - return this; - } - @Override protected NavigableMap provideVersions(String zoneId) { NavigableMap result = new TreeMap<>(); result.put("BarVersion", rules); return result; } @Override - protected ZoneRules provideRules(String zoneId) { + protected ZoneRules provideRules(String zoneId, boolean forCaching) { if (zoneId.equals("FooLocation")) { return rules; } @@ -193,4 +204,31 @@ public class TCKZoneRulesProvider { } } + static class MockDynamicProvider extends ZoneRulesProvider { + final ZoneRules BASE = ZoneOffset.of("+01:15").getRules(); + final ZoneRules ALTERNATE = ZoneOffset.of("+01:30").getRules(); + int count = 0; + @Override + public Set provideZoneIds() { + return new HashSet<>(Collections.singleton("DynamicLocation")); + } + @Override + protected NavigableMap provideVersions(String zoneId) { + NavigableMap result = new TreeMap<>(); + result.put("DynamicVersion1", BASE); + if (count > 2) { + result.put("DynamicVersion2", ALTERNATE); + } + return result; + } + @Override + protected ZoneRules provideRules(String zoneId, boolean forCaching) { + count++; + if (zoneId.equals("DynamicLocation")) { + return (forCaching ? null : (count > 2 ? ALTERNATE : BASE)); + } + throw new ZoneRulesException("Invalid"); + } + } + } diff --git a/jdk/test/java/time/test/java/time/MockSimplePeriod.java b/jdk/test/java/time/test/java/time/MockSimplePeriod.java index 1c5d8726bed..662c8b12100 100644 --- a/jdk/test/java/time/test/java/time/MockSimplePeriod.java +++ b/jdk/test/java/time/test/java/time/MockSimplePeriod.java @@ -68,15 +68,16 @@ import static java.time.temporal.ChronoUnit.SECONDS; import java.util.Objects; import java.time.temporal.Temporal; -import java.time.temporal.TemporalSubtractor; -import java.time.temporal.TemporalAdder; +import java.time.temporal.TemporalAmount; +import java.time.temporal.TemporalAmount; import java.time.temporal.TemporalUnit; +import java.util.List; /** * Mock period of time measured using a single unit, such as {@code 3 Days}. */ public final class MockSimplePeriod - implements TemporalAdder, TemporalSubtractor, Comparable { + implements TemporalAmount, Comparable { /** * A constant for a period of zero, measured in days. @@ -119,6 +120,16 @@ public final class MockSimplePeriod this.unit = unit; } + @Override + public long get(TemporalUnit unit) { + throw new UnsupportedOperationException("Not supported yet."); + } + + @Override + public List getUnits() { + throw new UnsupportedOperationException("Not supported yet."); + } + //----------------------------------------------------------------------- public long getAmount() { return amount; diff --git a/jdk/test/java/time/test/java/time/TestDuration.java b/jdk/test/java/time/test/java/time/TestDuration.java index 2b2d8105003..786bfc0f05f 100644 --- a/jdk/test/java/time/test/java/time/TestDuration.java +++ b/jdk/test/java/time/test/java/time/TestDuration.java @@ -218,18 +218,12 @@ public class TestDuration extends AbstractTest { Duration b = durations[j]; if (i < j) { assertEquals(a.compareTo(b)< 0, true, a + " <=> " + b); - assertEquals(a.isLessThan(b), true, a + " <=> " + b); - assertEquals(a.isGreaterThan(b), false, a + " <=> " + b); assertEquals(a.equals(b), false, a + " <=> " + b); } else if (i > j) { assertEquals(a.compareTo(b) > 0, true, a + " <=> " + b); - assertEquals(a.isLessThan(b), false, a + " <=> " + b); - assertEquals(a.isGreaterThan(b), true, a + " <=> " + b); assertEquals(a.equals(b), false, a + " <=> " + b); } else { assertEquals(a.compareTo(b), 0, a + " <=> " + b); - assertEquals(a.isLessThan(b), false, a + " <=> " + b); - assertEquals(a.isGreaterThan(b), false, a + " <=> " + b); assertEquals(a.equals(b), true, a + " <=> " + b); } } diff --git a/jdk/test/java/time/test/java/time/TestLocalDateTime.java b/jdk/test/java/time/test/java/time/TestLocalDateTime.java index d850be50715..90c3927406f 100644 --- a/jdk/test/java/time/test/java/time/TestLocalDateTime.java +++ b/jdk/test/java/time/test/java/time/TestLocalDateTime.java @@ -124,15 +124,15 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_withYear_int_noChange() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withYear(2007); - assertSame(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate()); - assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime()); + assertSame(t.toLocalDate(), TEST_2007_07_15_12_30_40_987654321.toLocalDate()); + assertSame(t.toLocalTime(), TEST_2007_07_15_12_30_40_987654321.toLocalTime()); } @Test(groups={"implementation"}) public void test_withMonth_int_noChange() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.withMonth(7); - assertSame(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate()); - assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime()); + assertSame(t.toLocalDate(), TEST_2007_07_15_12_30_40_987654321.toLocalDate()); + assertSame(t.toLocalTime(), TEST_2007_07_15_12_30_40_987654321.toLocalTime()); } @Test(groups={"implementation"}) @@ -156,13 +156,13 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_withHour_toMidnight() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(1, 0)).withHour(0); - assertSame(t.getTime(), LocalTime.MIDNIGHT); + assertSame(t.toLocalTime(), LocalTime.MIDNIGHT); } @Test(groups={"implementation"}) public void test_withHour_toMidday() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(1, 0)).withHour(12); - assertSame(t.getTime(), LocalTime.NOON); + assertSame(t.toLocalTime(), LocalTime.NOON); } @Test(groups={"implementation"}) @@ -174,13 +174,13 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_withMinute_toMidnight() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(0, 1)).withMinute(0); - assertSame(t.getTime(), LocalTime.MIDNIGHT); + assertSame(t.toLocalTime(), LocalTime.MIDNIGHT); } @Test(groups={"implementation"}) public void test_withMinute_toMidday() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(12, 1)).withMinute(0); - assertSame(t.getTime(), LocalTime.NOON); + assertSame(t.toLocalTime(), LocalTime.NOON); } @Test(groups={"implementation"}) @@ -192,13 +192,13 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_withSecond_toMidnight() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(0, 0, 1)).withSecond(0); - assertSame(t.getTime(), LocalTime.MIDNIGHT); + assertSame(t.toLocalTime(), LocalTime.MIDNIGHT); } @Test(groups={"implementation"}) public void test_withSecond_toMidday() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(12, 0, 1)).withSecond(0); - assertSame(t.getTime(), LocalTime.NOON); + assertSame(t.toLocalTime(), LocalTime.NOON); } @Test(groups={"implementation"}) @@ -210,13 +210,13 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_withNanoOfSecond_toMidnight() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(0, 0, 0, 1)).withNano(0); - assertSame(t.getTime(), LocalTime.MIDNIGHT); + assertSame(t.toLocalTime(), LocalTime.MIDNIGHT); } @Test(groups={"implementation"}) public void test_withNanoOfSecond_toMidday() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(12, 0, 0, 1)).withNano(0); - assertSame(t.getTime(), LocalTime.NOON); + assertSame(t.toLocalTime(), LocalTime.NOON); } @Test(groups={"implementation"}) @@ -270,13 +270,13 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_plusHours_toMidnight() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(23, 0)).plusHours(1); - assertSame(t.getTime(), LocalTime.MIDNIGHT); + assertSame(t.toLocalTime(), LocalTime.MIDNIGHT); } @Test(groups={"implementation"}) public void test_plusHours_toMidday() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(11, 0)).plusHours(1); - assertSame(t.getTime(), LocalTime.NOON); + assertSame(t.toLocalTime(), LocalTime.NOON); } @Test(groups={"implementation"}) @@ -288,19 +288,19 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_plusMinutes_noChange_oneDay_same() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusMinutes(24 * 60); - assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime()); + assertSame(t.toLocalTime(), TEST_2007_07_15_12_30_40_987654321.toLocalTime()); } @Test(groups={"implementation"}) public void test_plusMinutes_toMidnight() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(23, 59)).plusMinutes(1); - assertSame(t.getTime(), LocalTime.MIDNIGHT); + assertSame(t.toLocalTime(), LocalTime.MIDNIGHT); } @Test(groups={"implementation"}) public void test_plusMinutes_toMidday() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(11, 59)).plusMinutes(1); - assertSame(t.getTime(), LocalTime.NOON); + assertSame(t.toLocalTime(), LocalTime.NOON); } @Test(groups={"implementation"}) @@ -312,19 +312,19 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_plusSeconds_noChange_oneDay_same() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusSeconds(24 * 60 * 60); - assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime()); + assertSame(t.toLocalTime(), TEST_2007_07_15_12_30_40_987654321.toLocalTime()); } @Test(groups={"implementation"}) public void test_plusSeconds_toMidnight() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(23, 59, 59)).plusSeconds(1); - assertSame(t.getTime(), LocalTime.MIDNIGHT); + assertSame(t.toLocalTime(), LocalTime.MIDNIGHT); } @Test(groups={"implementation"}) public void test_plusSeconds_toMidday() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(11, 59, 59)).plusSeconds(1); - assertSame(t.getTime(), LocalTime.NOON); + assertSame(t.toLocalTime(), LocalTime.NOON); } @Test(groups={"implementation"}) @@ -336,19 +336,19 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_plusNanos_noChange_oneDay_same() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.plusNanos(24 * 60 * 60 * 1000000000L); - assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime()); + assertSame(t.toLocalTime(), TEST_2007_07_15_12_30_40_987654321.toLocalTime()); } @Test(groups={"implementation"}) public void test_plusNanos_toMidnight() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(23, 59, 59, 999999999)).plusNanos(1); - assertSame(t.getTime(), LocalTime.MIDNIGHT); + assertSame(t.toLocalTime(), LocalTime.MIDNIGHT); } @Test(groups={"implementation"}) public void test_plusNanos_toMidday() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(11, 59, 59, 999999999)).plusNanos(1); - assertSame(t.getTime(), LocalTime.NOON); + assertSame(t.toLocalTime(), LocalTime.NOON); } @Test(groups={"implementation"}) @@ -402,13 +402,13 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_minusHours_toMidnight() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(1, 0)).minusHours(1); - assertSame(t.getTime(), LocalTime.MIDNIGHT); + assertSame(t.toLocalTime(), LocalTime.MIDNIGHT); } @Test(groups={"implementation"}) public void test_minusHours_toMidday() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(13, 0)).minusHours(1); - assertSame(t.getTime(), LocalTime.NOON); + assertSame(t.toLocalTime(), LocalTime.NOON); } @Test(groups={"implementation"}) @@ -420,19 +420,19 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_minusMinutes_noChange_oneDay_same() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusMinutes(24 * 60); - assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime()); + assertSame(t.toLocalTime(), TEST_2007_07_15_12_30_40_987654321.toLocalTime()); } @Test(groups={"implementation"}) public void test_minusMinutes_toMidnight() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(0, 1)).minusMinutes(1); - assertSame(t.getTime(), LocalTime.MIDNIGHT); + assertSame(t.toLocalTime(), LocalTime.MIDNIGHT); } @Test(groups={"implementation"}) public void test_minusMinutes_toMidday() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(12, 1)).minusMinutes(1); - assertSame(t.getTime(), LocalTime.NOON); + assertSame(t.toLocalTime(), LocalTime.NOON); } @Test(groups={"implementation"}) @@ -444,20 +444,20 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_minusSeconds_noChange_oneDay() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusSeconds(24 * 60 * 60); - assertEquals(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1)); - assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime()); + assertEquals(t.toLocalDate(), TEST_2007_07_15_12_30_40_987654321.toLocalDate().minusDays(1)); + assertSame(t.toLocalTime(), TEST_2007_07_15_12_30_40_987654321.toLocalTime()); } @Test(groups={"implementation"}) public void test_minusSeconds_toMidnight() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(0, 0, 1)).minusSeconds(1); - assertSame(t.getTime(), LocalTime.MIDNIGHT); + assertSame(t.toLocalTime(), LocalTime.MIDNIGHT); } @Test(groups={"implementation"}) public void test_minusSeconds_toMidday() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(12, 0, 1)).minusSeconds(1); - assertSame(t.getTime(), LocalTime.NOON); + assertSame(t.toLocalTime(), LocalTime.NOON); } @Test(groups={"implementation"}) @@ -469,40 +469,40 @@ public class TestLocalDateTime extends AbstractTest { @Test(groups={"implementation"}) public void test_minusNanos_noChange_oneDay() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.minusNanos(24 * 60 * 60 * 1000000000L); - assertEquals(t.getDate(), TEST_2007_07_15_12_30_40_987654321.getDate().minusDays(1)); - assertSame(t.getTime(), TEST_2007_07_15_12_30_40_987654321.getTime()); + assertEquals(t.toLocalDate(), TEST_2007_07_15_12_30_40_987654321.toLocalDate().minusDays(1)); + assertSame(t.toLocalTime(), TEST_2007_07_15_12_30_40_987654321.toLocalTime()); } @Test(groups={"implementation"}) public void test_minusNanos_toMidnight() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(0, 0, 0, 1)).minusNanos(1); - assertSame(t.getTime(), LocalTime.MIDNIGHT); + assertSame(t.toLocalTime(), LocalTime.MIDNIGHT); } @Test(groups={"implementation"}) public void test_minusNanos_toMidday() { LocalDateTime t = TEST_2007_07_15_12_30_40_987654321.with(LocalTime.of(12, 0, 0, 1)).minusNanos(1); - assertSame(t.getTime(), LocalTime.NOON); + assertSame(t.toLocalTime(), LocalTime.NOON); } //----------------------------------------------------------------------- - // getDate() + // toLocalDate() //----------------------------------------------------------------------- @Test(dataProvider="sampleDates", groups={"implementation"}) public void test_getDate(int year, int month, int day) { LocalDate d = LocalDate.of(year, month, day); LocalDateTime dt = LocalDateTime.of(d, LocalTime.MIDNIGHT); - assertSame(dt.getDate(), d); + assertSame(dt.toLocalDate(), d); } //----------------------------------------------------------------------- - // getTime() + // toLocalTime() //----------------------------------------------------------------------- @Test(dataProvider="sampleTimes", groups={"implementation"}) public void test_getTime(int h, int m, int s, int ns) { LocalTime t = LocalTime.of(h, m, s, ns); LocalDateTime dt = LocalDateTime.of(LocalDate.of(2011, 7, 30), t); - assertSame(dt.getTime(), t); + assertSame(dt.toLocalTime(), t); } void test_comparisons_LocalDateTime(LocalDate... localDates) { diff --git a/jdk/test/java/time/test/java/time/TestLocalTime.java b/jdk/test/java/time/test/java/time/TestLocalTime.java index 0a0b27796b1..47aa94a7ecd 100644 --- a/jdk/test/java/time/test/java/time/TestLocalTime.java +++ b/jdk/test/java/time/test/java/time/TestLocalTime.java @@ -167,15 +167,6 @@ public class TestLocalTime extends AbstractTest { } } - @Test(groups={"implementation"}) - public void factory_ofSecondOfDay7_long_int_singletons() { - for (int i = 0; i < 24; i++) { - LocalTime test1 = LocalTime.ofSecondOfDay(i * 60L * 60L, 0); - LocalTime test2 = LocalTime.of(i, 0); - assertSame(test1, test2); - } - } - @Test(groups={"implementation"}) public void factory_ofNanoOfDay_singletons() { for (int i = 0; i < 24; i++) { diff --git a/jdk/test/java/time/test/java/time/temporal/TestMonthDay.java b/jdk/test/java/time/test/java/time/TestMonthDay.java similarity index 98% rename from jdk/test/java/time/test/java/time/temporal/TestMonthDay.java rename to jdk/test/java/time/test/java/time/TestMonthDay.java index 002d4f7e286..ebfdc6de6e5 100644 --- a/jdk/test/java/time/test/java/time/temporal/TestMonthDay.java +++ b/jdk/test/java/time/test/java/time/TestMonthDay.java @@ -57,7 +57,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package test.java.time.temporal; +package test.java.time; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertSame; @@ -65,11 +65,10 @@ import static org.testng.Assert.assertTrue; import java.time.LocalDate; import java.time.Month; -import java.time.temporal.MonthDay; +import java.time.MonthDay; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import test.java.time.AbstractTest; /** * Test MonthDay. diff --git a/jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime.java b/jdk/test/java/time/test/java/time/TestOffsetDateTime.java similarity index 97% rename from jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime.java rename to jdk/test/java/time/test/java/time/TestOffsetDateTime.java index 9ee46725c8a..7766b5ffb3b 100644 --- a/jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime.java +++ b/jdk/test/java/time/test/java/time/TestOffsetDateTime.java @@ -57,7 +57,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package test.java.time.temporal; +package test.java.time; import static org.testng.Assert.assertSame; @@ -65,13 +65,11 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneOffset; -import java.time.temporal.OffsetDateTime; +import java.time.OffsetDateTime; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import test.java.time.AbstractTest; -import test.java.time.MockSimplePeriod; /** * Test OffsetDateTime. @@ -114,9 +112,9 @@ public class TestOffsetDateTime extends AbstractTest { OffsetDateTime a = OffsetDateTime.of(localDateTime, offset); assertSame(a.getOffset(), offset); - assertSame(a.getDate(), localDate); - assertSame(a.getTime(), localTime); - assertSame(a.getDateTime(), localDateTime); + assertSame(a.toLocalDate(), localDate); + assertSame(a.toLocalTime(), localTime); + assertSame(a.toLocalDateTime(), localDateTime); } //----------------------------------------------------------------------- @@ -126,7 +124,7 @@ public class TestOffsetDateTime extends AbstractTest { public void test_withOffsetSameLocal() { OffsetDateTime base = OffsetDateTime.of(LocalDate.of(2008, 6, 30), LocalTime.of(11, 30, 59), OFFSET_PONE); OffsetDateTime test = base.withOffsetSameLocal(OFFSET_PTWO); - assertSame(test.getDateTime(), base.getDateTime()); + assertSame(test.toLocalDateTime(), base.toLocalDateTime()); assertSame(test.getOffset(), OFFSET_PTWO); } diff --git a/jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime_instants.java b/jdk/test/java/time/test/java/time/TestOffsetDateTime_instants.java similarity index 98% rename from jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime_instants.java rename to jdk/test/java/time/test/java/time/TestOffsetDateTime_instants.java index 7922c37589f..86c887ac829 100644 --- a/jdk/test/java/time/test/java/time/temporal/TestOffsetDateTime_instants.java +++ b/jdk/test/java/time/test/java/time/TestOffsetDateTime_instants.java @@ -57,7 +57,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package test.java.time.temporal; +package test.java.time; import java.time.DateTimeException; import java.time.Instant; @@ -66,15 +66,15 @@ import java.time.LocalTime; import java.time.Month; import java.time.ZoneOffset; -import java.time.temporal.OffsetDateTime; -import java.time.temporal.Year; +import java.time.OffsetDateTime; +import java.time.Year; import static org.testng.Assert.assertEquals; import org.testng.annotations.Test; /** - * Test OffsetDate creation. + * Test OffsetDateTime creation. */ @Test public class TestOffsetDateTime_instants { @@ -243,7 +243,7 @@ public class TestOffsetDateTime_instants { try { OffsetDateTime test = OffsetDateTime.ofInstant(instant, ZoneOffset.UTC); assertEquals(test, expected); - if (expected.getDate().equals(maxDate) == false) { + if (expected.toLocalDate().equals(maxDate) == false) { expected = expected.plusDays(1); } } catch (RuntimeException|Error ex) { diff --git a/jdk/test/java/time/test/java/time/temporal/TestOffsetTime.java b/jdk/test/java/time/test/java/time/TestOffsetTime.java similarity index 96% rename from jdk/test/java/time/test/java/time/temporal/TestOffsetTime.java rename to jdk/test/java/time/test/java/time/TestOffsetTime.java index d6e9eff0b3f..41116a7c964 100644 --- a/jdk/test/java/time/test/java/time/temporal/TestOffsetTime.java +++ b/jdk/test/java/time/test/java/time/TestOffsetTime.java @@ -57,12 +57,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package test.java.time.temporal; +package test.java.time; -import java.time.temporal.OffsetTime; +import java.time.OffsetTime; import org.testng.annotations.Test; -import test.java.time.AbstractTest; /** * Test OffsetTime. diff --git a/jdk/test/java/time/test/java/time/TestPeriod.java b/jdk/test/java/time/test/java/time/TestPeriod.java index f7caf9e334b..6559947b145 100644 --- a/jdk/test/java/time/test/java/time/TestPeriod.java +++ b/jdk/test/java/time/test/java/time/TestPeriod.java @@ -59,35 +59,11 @@ */ package test.java.time; -import static java.time.temporal.ChronoUnit.DAYS; -import static java.time.temporal.ChronoUnit.HALF_DAYS; -import static java.time.temporal.ChronoUnit.HOURS; -import static java.time.temporal.ChronoUnit.MICROS; -import static java.time.temporal.ChronoUnit.MILLIS; -import static java.time.temporal.ChronoUnit.MINUTES; -import static java.time.temporal.ChronoUnit.MONTHS; -import static java.time.temporal.ChronoUnit.NANOS; -import static java.time.temporal.ChronoUnit.SECONDS; -import static java.time.temporal.ChronoUnit.YEARS; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; - -import java.time.DateTimeException; -import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalTime; -import java.time.Month; import java.time.Period; -import java.time.temporal.YearMonth; -import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /** @@ -96,39 +72,6 @@ import org.testng.annotations.Test; @Test public class TestPeriod extends AbstractTest { - //----------------------------------------------------------------------- - // basics - //----------------------------------------------------------------------- - public void test_interfaces() { - assertTrue(Serializable.class.isAssignableFrom(Period.class)); - } - - @DataProvider(name="serialization") - Object[][] data_serialization() { - return new Object[][] { - {Period.ZERO}, - {Period.of(0, DAYS)}, - {Period.of(1, DAYS)}, - {Period.of(1, 2, 3, 4, 5, 6)}, - }; - } - - @Test(dataProvider="serialization") - public void test_serialization(Period period) throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(period); - oos.close(); - - ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream( - baos.toByteArray())); - if (period.isZero()) { - assertSame(ois.readObject(), period); - } else { - assertEquals(ois.readObject(), period); - } - } - @Test public void test_immutable() { assertImmutable(Period.class); @@ -139,1437 +82,24 @@ public class TestPeriod extends AbstractTest { //----------------------------------------------------------------------- public void factory_zeroSingleton() { assertSame(Period.ZERO, Period.ZERO); - assertSame(Period.of(0, 0, 0, 0, 0, 0), Period.ZERO); - assertSame(Period.of(0, 0, 0, 0, 0, 0, 0), Period.ZERO); - assertSame(Period.ofDate(0, 0, 0), Period.ZERO); - assertSame(Period.ofTime(0, 0, 0), Period.ZERO); - assertSame(Period.ofTime(0, 0, 0, 0), Period.ZERO); - assertSame(Period.of(0, YEARS), Period.ZERO); - assertSame(Period.of(0, MONTHS), Period.ZERO); - assertSame(Period.of(0, DAYS), Period.ZERO); - assertSame(Period.of(0, HOURS), Period.ZERO); - assertSame(Period.of(0, MINUTES), Period.ZERO); - assertSame(Period.of(0, SECONDS), Period.ZERO); - assertSame(Period.of(0, NANOS), Period.ZERO); + assertSame(Period.ofYears(0), Period.ZERO); + assertSame(Period.ofMonths(0), Period.ZERO); + assertSame(Period.ofDays(0), Period.ZERO); + assertSame(Period.of(0, 0, 0), Period.ZERO); } //----------------------------------------------------------------------- - // of(PeriodProvider) - //----------------------------------------------------------------------- - public void factory_of_ints() { - assertPeriod(Period.of(1, 2, 3, 4, 5, 6), 1, 2, 3, 4, 5, 6, 0); - assertPeriod(Period.of(0, 2, 3, 4, 5, 6), 0, 2, 3, 4, 5, 6, 0); - assertPeriod(Period.of(1, 0, 0, 0, 0, 0), 1, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.of(0, 0, 0, 0, 0, 0), 0, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.of(-1, -2, -3, -4, -5, -6), -1, -2, -3, -4, -5, -6, 0); - } - - //----------------------------------------------------------------------- - // ofDate - //----------------------------------------------------------------------- - public void factory_ofDate_ints() { - assertPeriod(Period.ofDate(1, 2, 3), 1, 2, 3, 0, 0, 0, 0); - assertPeriod(Period.ofDate(0, 2, 3), 0, 2, 3, 0, 0, 0, 0); - assertPeriod(Period.ofDate(1, 0, 0), 1, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.ofDate(0, 0, 0), 0, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.ofDate(-1, -2, -3), -1, -2, -3, 0, 0, 0, 0); - } - - //----------------------------------------------------------------------- - // ofTime - //----------------------------------------------------------------------- - public void factory_ofTime_3ints() { - assertPeriod(Period.ofTime(1, 2, 3), 0, 0, 0, 1, 2, 3, 0); - assertPeriod(Period.ofTime(0, 2, 3), 0, 0, 0, 0, 2, 3, 0); - assertPeriod(Period.ofTime(1, 0, 0), 0, 0, 0, 1, 0, 0, 0); - assertPeriod(Period.ofTime(0, 0, 0), 0, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.ofTime(-1, -2, -3), 0, 0, 0, -1, -2, -3, 0); - } - - public void factory_ofTime_4ints() { - assertPeriod(Period.ofTime(1, 2, 3, 4), 0, 0, 0, 1, 2, 3, 4); - assertPeriod(Period.ofTime(0, 2, 3, 4), 0, 0, 0, 0, 2, 3, 4); - assertPeriod(Period.ofTime(1, 0, 0, 0), 0, 0, 0, 1, 0, 0, 0); - assertPeriod(Period.ofTime(0, 0, 0, 0), 0, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.ofTime(-1, -2, -3, -4), 0, 0, 0, -1, -2, -3, -4); - } - - //----------------------------------------------------------------------- - // of one field - //----------------------------------------------------------------------- - public void test_factory_of_intPeriodUnit() { - assertEquals(Period.of(1, YEARS), Period.of(1, YEARS)); - assertEquals(Period.of(2, MONTHS), Period.of(2, MONTHS)); - assertEquals(Period.of(3, DAYS), Period.of(3, DAYS)); - - assertEquals(Period.of(1, HALF_DAYS), Period.of(12, HOURS)); - assertEquals(Period.of(Integer.MAX_VALUE / (3600 * 8), HOURS), Period.of(Integer.MAX_VALUE / (3600 * 8), HOURS)); - assertEquals(Period.of(-1, MINUTES), Period.of(-1, MINUTES)); - assertEquals(Period.of(-2, SECONDS), Period.of(-2, SECONDS)); - assertEquals(Period.of(Integer.MIN_VALUE, NANOS), Period.of(Integer.MIN_VALUE, NANOS)); - assertEquals(Period.of(2, MILLIS), Period.of(2000000, NANOS)); - assertEquals(Period.of(2, MICROS), Period.of(2000, NANOS)); - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_factory_of_intPeriodUnit_null() { - Period.of(1, null); - } - - //----------------------------------------------------------------------- - public void factory_years() { - assertPeriod(Period.of(1, YEARS), 1, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.of(0, YEARS), 0, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.of(-1, YEARS), -1, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.of(Integer.MAX_VALUE, YEARS), Integer.MAX_VALUE, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.of(Integer.MIN_VALUE, YEARS), Integer.MIN_VALUE, 0, 0, 0, 0, 0, 0); - } - - public void factory_months() { - assertPeriod(Period.of(1, MONTHS), 0, 1, 0, 0, 0, 0, 0); - assertPeriod(Period.of(0, MONTHS), 0, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.of(-1, MONTHS), 0, -1, 0, 0, 0, 0, 0); - assertPeriod(Period.of(Integer.MAX_VALUE, MONTHS), 0, Integer.MAX_VALUE, 0, 0, 0, 0, 0); - assertPeriod(Period.of(Integer.MIN_VALUE, MONTHS), 0, Integer.MIN_VALUE, 0, 0, 0, 0, 0); - } - - public void factory_days() { - assertPeriod(Period.of(1, DAYS), 0, 0, 1, 0, 0, 0, 0); - assertPeriod(Period.of(0, DAYS), 0, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.of(-1, DAYS), 0, 0, -1, 0, 0, 0, 0); - assertPeriod(Period.of(Integer.MAX_VALUE, DAYS), 0, 0, Integer.MAX_VALUE, 0, 0, 0, 0); - assertPeriod(Period.of(Integer.MIN_VALUE, DAYS), 0, 0, Integer.MIN_VALUE, 0, 0, 0, 0); - } - - public void factory_hours() { - assertPeriod(Period.of(1, HOURS), 0, 0, 0, 1, 0, 0, 0); - assertPeriod(Period.of(0, HOURS), 0, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.of(-1, HOURS), 0, 0, 0, -1, 0, 0, 0); - assertPeriod(Period.of(Integer.MAX_VALUE / (3600 * 8), HOURS), 0, 0, 0, Integer.MAX_VALUE / (3600 * 8), 0, 0, 0); - assertPeriod(Period.of(Integer.MIN_VALUE / (3600 * 8), HOURS), 0, 0, 0, Integer.MIN_VALUE / (3600 * 8), 0, 0, 0); - } - - public void factory_minutes() { - assertPeriod(Period.of(1, MINUTES), 0, 0, 0, 0, 1, 0, 0); - assertPeriod(Period.of(0, MINUTES), 0, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.of(-1, MINUTES), 0, 0, 0, 0, -1, 0, 0); - int val = Integer.MAX_VALUE / (60 * 8); - assertPeriod(Period.of(val, MINUTES), 0, 0, 0, - (int) (val / 60L), - (int) (val % 60), - 0, 0); - val = Integer.MIN_VALUE / (60 * 8); - assertPeriod(Period.of(val, MINUTES), 0, 0, 0, - (int) (val / 60L), - (int) (val % 60), - 0, 0); - } - - public void factory_seconds() { - assertPeriod(Period.of(1, SECONDS), 0, 0, 0, 0, 0, 1, 0); - assertPeriod(Period.of(0, SECONDS), 0, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.of(-1, SECONDS), 0, 0, 0, 0, 0, -1, 0); - assertPeriod(Period.of(Integer.MAX_VALUE, SECONDS), 0, 0, 0, - (int) (Integer.MAX_VALUE / 3600L), - (int) ((Integer.MAX_VALUE / 60L) % 60), - (int) (Integer.MAX_VALUE % 60), - 0); - assertPeriod(Period.of(Integer.MIN_VALUE, SECONDS), 0, 0, 0, - (int) (Integer.MIN_VALUE / 3600L), - (int) ((Integer.MIN_VALUE / 60L) % 60), - (int) (Integer.MIN_VALUE % 60), - 0); - } - - public void factory_nanos() { - assertPeriod(Period.of(1, NANOS), 0, 0, 0, 0, 0, 0, 1); - assertPeriod(Period.of(0, NANOS), 0, 0, 0, 0, 0, 0, 0); - assertPeriod(Period.of(-1, NANOS), 0, 0, 0, 0, 0, 0, -1); - assertPeriod(Period.of(Long.MAX_VALUE, NANOS), 0, 0, 0, - (int) (Long.MAX_VALUE / 3600_000_000_000L), - (int) ((Long.MAX_VALUE / 60_000_000_000L) % 60), - (int) ((Long.MAX_VALUE / 1_000_000_000L) % 60), - Long.MAX_VALUE % 1_000_000_000L); - assertPeriod(Period.of(Long.MIN_VALUE, NANOS), 0, 0, 0, - (int) (Long.MIN_VALUE / 3600_000_000_000L), - (int) ((Long.MIN_VALUE / 60_000_000_000L) % 60), - (int) ((Long.MIN_VALUE / 1_000_000_000L) % 60), - Long.MIN_VALUE % 1_000_000_000L); - } - - //----------------------------------------------------------------------- - // of(Duration) - //----------------------------------------------------------------------- - public void factory_duration() { - assertPeriod(Period.of(Duration.ofSeconds(2, 3)), 0, 0, 0, 0, 0, 2, 3); - assertPeriod(Period.of(Duration.ofSeconds(59, 3)), 0, 0, 0, 0, 0, 59, 3); - assertPeriod(Period.of(Duration.ofSeconds(60, 3)), 0, 0, 0, 0, 1, 0, 3); - assertPeriod(Period.of(Duration.ofSeconds(61, 3)), 0, 0, 0, 0, 1, 1, 3); - assertPeriod(Period.of(Duration.ofSeconds(3599, 3)), 0, 0, 0, 0, 59, 59, 3); - assertPeriod(Period.of(Duration.ofSeconds(3600, 3)), 0, 0, 0, 1, 0, 0, 3); - } - - public void factory_duration_negative() { - assertPeriod(Period.of(Duration.ofSeconds(-2, 3)), 0, 0, 0, 0, 0, -1, -999999997); - assertPeriod(Period.of(Duration.ofSeconds(-59, 3)), 0, 0, 0, 0, 0, -58, -999999997); - assertPeriod(Period.of(Duration.ofSeconds(-60, 3)), 0, 0, 0, 0, 0, -59, -999999997); - assertPeriod(Period.of(Duration.ofSeconds(-60, -3)), 0, 0, 0, 0, -1, 0, -3); - - assertPeriod(Period.of(Duration.ofSeconds(2, -3)), 0, 0, 0, 0, 0, 1, 999999997); - } - - public void factory_duration_big() { - Duration dur = Duration.ofSeconds(Integer.MAX_VALUE, 3); - long secs = Integer.MAX_VALUE; - assertPeriod(Period.of(dur), 0, 0, 0, (int) (secs / 3600), (int) ((secs % 3600) / 60), (int) (secs % 60), 3); - } - - @Test(expectedExceptions=NullPointerException.class) - public void factory_duration_null() { - Period.of((Duration) null); - } - - //----------------------------------------------------------------------- - // between - //----------------------------------------------------------------------- - @DataProvider(name="betweenDates") - Object[][] data_betweenDates() { - return new Object[][] { - {2010, 1, 1, 2010, 1, 1, 0, 0, 0}, - {2010, 1, 1, 2010, 1, 2, 0, 0, 1}, - {2010, 1, 1, 2010, 2, 1, 0, 1, 0}, - {2010, 1, 1, 2010, 2, 2, 0, 1, 1}, - {2010, 1, 1, 2011, 1, 1, 1, 0, 0}, - - {2010, 6, 12, 2010, 1, 1, 0, -5, -11}, - {2010, 6, 12, 2010, 1, 2, 0, -5, -10}, - {2010, 6, 12, 2010, 2, 1, 0, -4, -11}, - {2010, 6, 12, 2010, 9, 24, 0, 3, 12}, - - {2010, 6, 12, 2009, 1, 1, -1, -5, -11}, - {2010, 6, 12, 2009, 1, 2, -1, -5, -10}, - {2010, 6, 12, 2009, 2, 1, -1, -4, -11}, - {2010, 6, 12, 2009, 9, 24, 0, -9, 12}, - - {2010, 6, 12, 2008, 1, 1, -2, -5, -11}, - {2010, 6, 12, 2008, 1, 2, -2, -5, -10}, - {2010, 6, 12, 2008, 2, 1, -2, -4, -11}, - {2010, 6, 12, 2008, 9, 24, -1, -9, 12}, - }; - } - - @Test(dataProvider="betweenDates") - public void factory_between_LocalDate(int y1, int m1, int d1, int y2, int m2, int d2, int ye, int me, int de) { - LocalDate start = LocalDate.of(y1, m1, d1); - LocalDate end = LocalDate.of(y2, m2, d2); - Period test = Period.between(start, end); - assertPeriod(test, ye, me, de, 0, 0, 0, 0); - //assertEquals(start.plus(test), end); - } - - @DataProvider(name="betweenTimes") - Object[][] data_betweenTimes() { - return new Object[][] { - {12, 30, 40, 12, 30, 45, 0, 0, 5}, - {12, 30, 40, 12, 35, 40, 0, 5, 0}, - {12, 30, 40, 13, 30, 40, 1, 0, 0}, - - {12, 30, 40, 12, 30, 35, 0, 0, -5}, - {12, 30, 40, 12, 25, 40, 0, -5, 0}, - {12, 30, 40, 11, 30, 40, -1, 0, 0}, - }; - } - - @Test(dataProvider="betweenTimes") - public void factory_between_LocalTime(int h1, int m1, int s1, int h2, int m2, int s2, int he, int me, int se) { - LocalTime start = LocalTime.of(h1, m1, s1); - LocalTime end = LocalTime.of(h2, m2, s2); - Period test = Period.between(start, end); - assertPeriod(test, 0, 0, 0, he, me, se, 0); - //assertEquals(start.plus(test), end); - } - - public void factory_between_YearMonth() { - assertPeriod(Period.between(YearMonth.of(2012, 6), YearMonth.of(2013, 7)), 1, 1, 0, 0, 0, 0, 0); - assertPeriod(Period.between(YearMonth.of(2012, 6), YearMonth.of(2013, 3)), 0, 9, 0, 0, 0, 0, 0); - assertPeriod(Period.between(YearMonth.of(2012, 6), YearMonth.of(2011, 7)), 0, -11, 0, 0, 0, 0, 0); - } - - public void factory_between_Month() { - assertPeriod(Period.between(Month.FEBRUARY, Month.MAY), 0, 3, 0, 0, 0, 0, 0); - assertPeriod(Period.between(Month.NOVEMBER, Month.MAY), 0, -6, 0, 0, 0, 0, 0); - } - - //----------------------------------------------------------------------- - // betweenISO - //----------------------------------------------------------------------- - @DataProvider(name="betweenISO") - Object[][] data_betweenISO() { - return new Object[][] { - {2010, 1, 1, 2010, 1, 1, 0, 0, 0}, - {2010, 1, 1, 2010, 1, 2, 0, 0, 1}, - {2010, 1, 1, 2010, 1, 31, 0, 0, 30}, - {2010, 1, 1, 2010, 2, 1, 0, 1, 0}, - {2010, 1, 1, 2010, 2, 28, 0, 1, 27}, - {2010, 1, 1, 2010, 3, 1, 0, 2, 0}, - {2010, 1, 1, 2010, 12, 31, 0, 11, 30}, - {2010, 1, 1, 2011, 1, 1, 1, 0, 0}, - {2010, 1, 1, 2011, 12, 31, 1, 11, 30}, - {2010, 1, 1, 2012, 1, 1, 2, 0, 0}, - - {2010, 1, 10, 2010, 1, 1, 0, 0, -9}, - {2010, 1, 10, 2010, 1, 2, 0, 0, -8}, - {2010, 1, 10, 2010, 1, 9, 0, 0, -1}, - {2010, 1, 10, 2010, 1, 10, 0, 0, 0}, - {2010, 1, 10, 2010, 1, 11, 0, 0, 1}, - {2010, 1, 10, 2010, 1, 31, 0, 0, 21}, - {2010, 1, 10, 2010, 2, 1, 0, 0, 22}, - {2010, 1, 10, 2010, 2, 9, 0, 0, 30}, - {2010, 1, 10, 2010, 2, 10, 0, 1, 0}, - {2010, 1, 10, 2010, 2, 28, 0, 1, 18}, - {2010, 1, 10, 2010, 3, 1, 0, 1, 19}, - {2010, 1, 10, 2010, 3, 9, 0, 1, 27}, - {2010, 1, 10, 2010, 3, 10, 0, 2, 0}, - {2010, 1, 10, 2010, 12, 31, 0, 11, 21}, - {2010, 1, 10, 2011, 1, 1, 0, 11, 22}, - {2010, 1, 10, 2011, 1, 9, 0, 11, 30}, - {2010, 1, 10, 2011, 1, 10, 1, 0, 0}, - - {2010, 3, 30, 2011, 5, 1, 1, 1, 1}, - {2010, 4, 30, 2011, 5, 1, 1, 0, 1}, - - {2010, 2, 28, 2012, 2, 27, 1, 11, 30}, - {2010, 2, 28, 2012, 2, 28, 2, 0, 0}, - {2010, 2, 28, 2012, 2, 29, 2, 0, 1}, - - {2012, 2, 28, 2014, 2, 27, 1, 11, 30}, - {2012, 2, 28, 2014, 2, 28, 2, 0, 0}, - {2012, 2, 28, 2014, 3, 1, 2, 0, 1}, - - {2012, 2, 29, 2014, 2, 28, 1, 11, 30}, - {2012, 2, 29, 2014, 3, 1, 2, 0, 1}, - {2012, 2, 29, 2014, 3, 2, 2, 0, 2}, - - {2012, 2, 29, 2016, 2, 28, 3, 11, 30}, - {2012, 2, 29, 2016, 2, 29, 4, 0, 0}, - {2012, 2, 29, 2016, 3, 1, 4, 0, 1}, - - {2010, 1, 1, 2009, 12, 31, 0, 0, -1}, - {2010, 1, 1, 2009, 12, 30, 0, 0, -2}, - {2010, 1, 1, 2009, 12, 2, 0, 0, -30}, - {2010, 1, 1, 2009, 12, 1, 0, -1, 0}, - {2010, 1, 1, 2009, 11, 30, 0, -1, -1}, - {2010, 1, 1, 2009, 11, 2, 0, -1, -29}, - {2010, 1, 1, 2009, 11, 1, 0, -2, 0}, - {2010, 1, 1, 2009, 1, 2, 0, -11, -30}, - {2010, 1, 1, 2009, 1, 1, -1, 0, 0}, - - {2010, 1, 15, 2010, 1, 15, 0, 0, 0}, - {2010, 1, 15, 2010, 1, 14, 0, 0, -1}, - {2010, 1, 15, 2010, 1, 1, 0, 0, -14}, - {2010, 1, 15, 2009, 12, 31, 0, 0, -15}, - {2010, 1, 15, 2009, 12, 16, 0, 0, -30}, - {2010, 1, 15, 2009, 12, 15, 0, -1, 0}, - {2010, 1, 15, 2009, 12, 14, 0, -1, -1}, - - {2010, 2, 28, 2009, 3, 1, 0, -11, -27}, - {2010, 2, 28, 2009, 2, 28, -1, 0, 0}, - {2010, 2, 28, 2009, 2, 27, -1, 0, -1}, - - {2010, 2, 28, 2008, 2, 29, -1, -11, -28}, - {2010, 2, 28, 2008, 2, 28, -2, 0, 0}, - {2010, 2, 28, 2008, 2, 27, -2, 0, -1}, - - {2012, 2, 29, 2009, 3, 1, -2, -11, -28}, - {2012, 2, 29, 2009, 2, 28, -3, 0, -1}, - {2012, 2, 29, 2009, 2, 27, -3, 0, -2}, - - {2012, 2, 29, 2008, 3, 1, -3, -11, -28}, - {2012, 2, 29, 2008, 2, 29, -4, 0, 0}, - {2012, 2, 29, 2008, 2, 28, -4, 0, -1}, - }; - } - - @Test(dataProvider="betweenISO") - public void factory_betweenISO_LocalDate(int y1, int m1, int d1, int y2, int m2, int d2, int ye, int me, int de) { - LocalDate start = LocalDate.of(y1, m1, d1); - LocalDate end = LocalDate.of(y2, m2, d2); - Period test = Period.betweenISO(start, end); - assertPeriod(test, ye, me, de, 0, 0, 0, 0); - //assertEquals(start.plus(test), end); - } - - @Test(expectedExceptions=NullPointerException.class) - public void factory_betweenISO_LocalDate_nullFirst() { - Period.betweenISO((LocalDate) null, LocalDate.of(2010, 1, 1)); - } - - @Test(expectedExceptions=NullPointerException.class) - public void factory_betweenISO_LocalDate_nullSecond() { - Period.betweenISO(LocalDate.of(2010, 1, 1), (LocalDate) null); - } - - //------------------------------------------------------------------------- - @Test(expectedExceptions=NullPointerException.class) - public void factory_betweenISO_LocalTime_nullFirst() { - Period.betweenISO((LocalTime) null, LocalTime.of(12, 30)); - } - - @Test(expectedExceptions=NullPointerException.class) - public void factory_betweenISO_LocalTime_nullSecond() { - Period.betweenISO(LocalTime.of(12, 30), (LocalTime) null); - } - - //----------------------------------------------------------------------- - // parse() - //----------------------------------------------------------------------- - @Test(dataProvider="toStringAndParse") - public void test_parse(Period test, String expected) { - assertEquals(test, Period.parse(expected)); - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_parse_nullText() { - Period.parse((String) null); - } - - //----------------------------------------------------------------------- - // isZero() - //----------------------------------------------------------------------- - public void test_isZero() { - assertEquals(Period.of(1, 2, 3, 4, 5, 6, 7).isZero(), false); - assertEquals(Period.of(1, 2, 3, 0, 0, 0, 0).isZero(), false); - assertEquals(Period.of(0, 0, 0, 4, 5, 6, 7).isZero(), false); - assertEquals(Period.of(1, 0, 0, 0, 0, 0, 0).isZero(), false); - assertEquals(Period.of(0, 2, 0, 0, 0, 0, 0).isZero(), false); - assertEquals(Period.of(0, 0, 3, 0, 0, 0, 0).isZero(), false); - assertEquals(Period.of(0, 0, 0, 4, 0, 0, 0).isZero(), false); - assertEquals(Period.of(0, 0, 0, 0, 5, 0, 0).isZero(), false); - assertEquals(Period.of(0, 0, 0, 0, 0, 6, 0).isZero(), false); - assertEquals(Period.of(0, 0, 0, 0, 0, 0, 7).isZero(), false); - assertEquals(Period.of(0, 0, 0, 0, 0, 0).isZero(), true); - } - - //----------------------------------------------------------------------- - // isPositive() - //----------------------------------------------------------------------- - public void test_isPositive() { - assertEquals(Period.of(1, 2, 3, 4, 5, 6, 7).isPositive(), true); - assertEquals(Period.of(1, 2, 3, 0, 0, 0, 0).isPositive(), true); - assertEquals(Period.of(0, 0, 0, 4, 5, 6, 7).isPositive(), true); - assertEquals(Period.of(1, 0, 0, 0, 0, 0, 0).isPositive(), true); - assertEquals(Period.of(0, 2, 0, 0, 0, 0, 0).isPositive(), true); - assertEquals(Period.of(0, 0, 3, 0, 0, 0, 0).isPositive(), true); - assertEquals(Period.of(0, 0, 0, 4, 0, 0, 0).isPositive(), true); - assertEquals(Period.of(0, 0, 0, 0, 5, 0, 0).isPositive(), true); - assertEquals(Period.of(0, 0, 0, 0, 0, 6, 0).isPositive(), true); - assertEquals(Period.of(0, 0, 0, 0, 0, 0, 7).isPositive(), true); - assertEquals(Period.of(-1, -2, -3, -4, -5, -6, -7).isPositive(), false); - assertEquals(Period.of(-1, -2, 3, 4, -5, -6, -7).isPositive(), false); - assertEquals(Period.of(-1, 0, 0, 0, 0, 0, 0).isPositive(), false); - assertEquals(Period.of(0, -2, 0, 0, 0, 0, 0).isPositive(), false); - assertEquals(Period.of(0, 0, -3, 0, 0, 0, 0).isPositive(), false); - assertEquals(Period.of(0, 0, 0, -4, 0, 0, 0).isPositive(), false); - assertEquals(Period.of(0, 0, 0, 0, -5, 0, 0).isPositive(), false); - assertEquals(Period.of(0, 0, 0, 0, 0, -6, 0).isPositive(), false); - assertEquals(Period.of(0, 0, 0, 0, 0, 0, -7).isPositive(), false); - assertEquals(Period.of(0, 0, 0, 0, 0, 0).isPositive(), false); - } - - //----------------------------------------------------------------------- - // withYears() - //----------------------------------------------------------------------- - public void test_withYears() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.withYears(10), 10, 2, 3, 4, 5, 6, 7); - } - - public void test_withYears_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.withYears(1), test); - } - - public void test_withYears_toZero() { - Period test = Period.of(1, YEARS); - assertSame(test.withYears(0), Period.ZERO); - } - - //----------------------------------------------------------------------- - // withMonths() - //----------------------------------------------------------------------- - public void test_withMonths() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.withMonths(10), 1, 10, 3, 4, 5, 6, 7); - } - - public void test_withMonths_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.withMonths(2), test); - } - - public void test_withMonths_toZero() { - Period test = Period.of(1, MONTHS); - assertSame(test.withMonths(0), Period.ZERO); - } - - //----------------------------------------------------------------------- - // withDays() - //----------------------------------------------------------------------- - public void test_withDays() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.withDays(10), 1, 2, 10, 4, 5, 6, 7); - } - - public void test_withDays_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.withDays(3), test); - } - - public void test_withDays_toZero() { - Period test = Period.of(1, DAYS); - assertSame(test.withDays(0), Period.ZERO); - } - - //----------------------------------------------------------------------- - // withTimeNanos() - //----------------------------------------------------------------------- - public void test_withNanos() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.withTimeNanos(10), 1, 2, 3, 0, 0, 0, 10); - } - - public void test_withNanos_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.withTimeNanos(((4 * 60 + 5) * 60 + 6) * 1_000_000_000L + 7), test); - } - - public void test_withNanos_toZero() { - Period test = Period.of(1, NANOS); - assertSame(test.withTimeNanos(0), Period.ZERO); - } - - - - //----------------------------------------------------------------------- - // plusYears() - //----------------------------------------------------------------------- - public void test_plusYears() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.plus(10, YEARS), 11, 2, 3, 4, 5, 6, 7); - assertPeriod(test.plus(Period.of(10, YEARS)), 11, 2, 3, 4, 5, 6, 7); - } - - public void test_plusYears_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.plus(0, YEARS), test); - assertPeriod(test.plus(Period.of(0, YEARS)), 1, 2, 3, 4, 5, 6, 7); - } - - public void test_plusYears_toZero() { - Period test = Period.of(-1, YEARS); - assertSame(test.plus(1, YEARS), Period.ZERO); - assertSame(test.plus(Period.of(1, YEARS)), Period.ZERO); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_plusYears_overflowTooBig() { - Period test = Period.of(Integer.MAX_VALUE, YEARS); - test.plus(1, YEARS); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_plusYears_overflowTooSmall() { - Period test = Period.of(Integer.MIN_VALUE, YEARS); - test.plus(-1, YEARS); - } - - //----------------------------------------------------------------------- - // plusMonths() - //----------------------------------------------------------------------- - public void test_plusMonths() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.plus(10, MONTHS), 1, 12, 3, 4, 5, 6, 7); - assertPeriod(test.plus(Period.of(10, MONTHS)), 1, 12, 3, 4, 5, 6, 7); - } - - public void test_plusMonths_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.plus(0, MONTHS), test); - assertEquals(test.plus(Period.of(0, MONTHS)), test); - } - - public void test_plusMonths_toZero() { - Period test = Period.of(-1, MONTHS); - assertSame(test.plus(1, MONTHS), Period.ZERO); - assertSame(test.plus(Period.of(1, MONTHS)), Period.ZERO); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_plusMonths_overflowTooBig() { - Period test = Period.of(Integer.MAX_VALUE, MONTHS); - test.plus(1, MONTHS); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_plusMonths_overflowTooSmall() { - Period test = Period.of(Integer.MIN_VALUE, MONTHS); - test.plus(-1, MONTHS); - } - - //----------------------------------------------------------------------- - // plusDays() - //----------------------------------------------------------------------- - public void test_plusDays() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.plus(10, DAYS), 1, 2, 13, 4, 5, 6, 7); - } - - public void test_plusDays_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.plus(0, DAYS), test); - } - - public void test_plusDays_toZero() { - Period test = Period.of(-1, DAYS); - assertSame(test.plus(1, DAYS), Period.ZERO); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_plusDays_overflowTooBig() { - Period test = Period.of(Integer.MAX_VALUE, DAYS); - test.plus(1, DAYS); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_plusDays_overflowTooSmall() { - Period test = Period.of(Integer.MIN_VALUE, DAYS); - test.plus(-1, DAYS); - } - - //----------------------------------------------------------------------- - // plusHours() - //----------------------------------------------------------------------- - public void test_plusHours() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.plus(10, HOURS), 1, 2, 3, 14, 5, 6, 7); - } - - public void test_plusHours_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.plus(0, HOURS), test); - } - - public void test_plusHours_toZero() { - Period test = Period.of(-1, HOURS); - assertSame(test.plus(1, HOURS), Period.ZERO); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_plusHours_overflowTooBig() { - Period test = Period.of(Integer.MAX_VALUE, HOURS); - test.plus(1, HOURS); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_plusHours_overflowTooSmall() { - Period test = Period.of(Integer.MIN_VALUE, HOURS); - test.plus(-1, HOURS); - } - - //----------------------------------------------------------------------- - // plusMinutes() - //----------------------------------------------------------------------- - public void test_plusMinutes() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.plus(10, MINUTES), 1, 2, 3, 4, 15, 6, 7); - } - - public void test_plusMinutes_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.plus(0, MINUTES), test); - } - - public void test_plusMinutes_toZero() { - Period test = Period.of(-1, MINUTES); - assertSame(test.plus(1, MINUTES), Period.ZERO); - } - - //----------------------------------------------------------------------- - // plusSeconds() - //----------------------------------------------------------------------- - public void test_plusSeconds() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.plus(10, SECONDS), 1, 2, 3, 4, 5, 16, 7); - } - - public void test_plusSeconds_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.plus(0, SECONDS), test); - } - - public void test_plusSeconds_toZero() { - Period test = Period.of(-1, SECONDS); - assertSame(test.plus(1, SECONDS), Period.ZERO); - } - - //----------------------------------------------------------------------- - // plusNanos() - //----------------------------------------------------------------------- - public void test_plusNanos() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.plus(10, NANOS), 1, 2, 3, 4, 5, 6, 17); - } - - public void test_plusNanos_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.plus(0, NANOS), test); - } - - public void test_plusNanos_toZero() { - Period test = Period.of(-1, NANOS); - assertSame(test.plus(1, NANOS), Period.ZERO); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_plusNanos_overflowTooBig() { - Period test = Period.of(Long.MAX_VALUE, NANOS); - test.plus(1, NANOS); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_plusNanos_overflowTooSmall() { - Period test = Period.of(Long.MIN_VALUE, NANOS); - test.plus(-1, NANOS); - } - - //----------------------------------------------------------------------- - // minusYears() - //----------------------------------------------------------------------- - public void test_minusYears() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.minus(10, YEARS), -9, 2, 3, 4, 5, 6, 7); - } - - public void test_minusYears_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.minus(0, YEARS), test); - } - - public void test_minusYears_toZero() { - Period test = Period.of(1, YEARS); - assertSame(test.minus(1, YEARS), Period.ZERO); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_minusYears_overflowTooBig() { - Period test = Period.of(Integer.MAX_VALUE, YEARS); - test.minus(-1, YEARS); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_minusYears_overflowTooSmall() { - Period test = Period.of(Integer.MIN_VALUE, YEARS); - test.minus(1, YEARS); - } - - //----------------------------------------------------------------------- - // minusMonths() - //----------------------------------------------------------------------- - public void test_minusMonths() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.minus(10, MONTHS), 1, -8, 3, 4, 5, 6, 7); - } - - public void test_minusMonths_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.minus(0, MONTHS), test); - } - - public void test_minusMonths_toZero() { - Period test = Period.of(1, MONTHS); - assertSame(test.minus(1, MONTHS), Period.ZERO); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_minusMonths_overflowTooBig() { - Period test = Period.of(Integer.MAX_VALUE, MONTHS); - test.minus(-1, MONTHS); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_minusMonths_overflowTooSmall() { - Period test = Period.of(Integer.MIN_VALUE, MONTHS); - test.minus(1, MONTHS); - } - - //----------------------------------------------------------------------- - // minusDays() - //----------------------------------------------------------------------- - public void test_minusDays() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.minus(10, DAYS), 1, 2, -7, 4, 5, 6, 7); - } - - public void test_minusDays_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.minus(0, DAYS), test); - } - - public void test_minusDays_toZero() { - Period test = Period.of(1, DAYS); - assertSame(test.minus(1, DAYS), Period.ZERO); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_minusDays_overflowTooBig() { - Period test = Period.of(Integer.MAX_VALUE, DAYS); - test.minus(-1, DAYS); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_minusDays_overflowTooSmall() { - Period test = Period.of(Integer.MIN_VALUE, DAYS); - test.minus(1, DAYS); - } - - //----------------------------------------------------------------------- - // minusHours() - //----------------------------------------------------------------------- - public void test_minusHours() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.minus(10, HOURS), 1, 2, 3, -5, -54, -53, -999999993); - assertEquals(test.minus(10, HOURS).plus(10, HOURS), test); - } - - public void test_minusHours_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.minus(0, HOURS), test); - } - - public void test_minusHours_toZero() { - Period test = Period.of(1, HOURS); - assertSame(test.minus(1, HOURS), Period.ZERO); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_minusHours_overflowTooBig() { - Period test = Period.of(Integer.MAX_VALUE, HOURS); - test.minus(-1, HOURS); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_minusHours_overflowTooSmall() { - Period test = Period.of(Integer.MIN_VALUE, HOURS); - test.minus(1, HOURS); - } - - //----------------------------------------------------------------------- - // minusMinutes() - //----------------------------------------------------------------------- - public void test_minusMinutes() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.minus(10, MINUTES), 1, 2, 3, 3, 55, 6, 7); - assertEquals(test.minus(10, MINUTES).plus(10, MINUTES), test); - } - - public void test_minusMinutes_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.minus(0, MINUTES), test); - } - - public void test_minusMinutes_toZero() { - Period test = Period.of(1, MINUTES); - assertSame(test.minus(1, MINUTES), Period.ZERO); - } - - //----------------------------------------------------------------------- - // minusSeconds() - //----------------------------------------------------------------------- - public void test_minusSeconds() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.minus(10, SECONDS), 1, 2, 3, 4, 4, 56, 7); - assertEquals(test.minus(10, SECONDS).plus(10, SECONDS), test); - } - - public void test_minusSeconds_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.minus(0, SECONDS), test); - } - - public void test_minusSeconds_toZero() { - Period test = Period.of(1, SECONDS); - assertSame(test.minus(1, SECONDS), Period.ZERO); - } - - //----------------------------------------------------------------------- - // minusNanos() - //----------------------------------------------------------------------- - public void test_minusNanos() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.minus(10, NANOS), 1, 2, 3, 4, 5, 5, 999999997); - } - - public void test_minusNanos_noChange() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.minus(0, NANOS), test); - } - - public void test_minusNanos_toZero() { - Period test = Period.of(1, NANOS); - assertSame(test.minus(1, NANOS), Period.ZERO); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_minusNanos_overflowTooBig() { - Period test = Period.of(Long.MAX_VALUE, NANOS); - test.minus(-1, NANOS); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_minusNanos_overflowTooSmall() { - Period test = Period.of(Long.MIN_VALUE, NANOS); - test.minus(1, NANOS); - } - - //----------------------------------------------------------------------- - // multipliedBy() - //----------------------------------------------------------------------- - public void test_multipliedBy() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.multipliedBy(2), 2, 4, 6, 8, 10, 12, 14); - assertPeriod(test.multipliedBy(-3), -3, -6, -9, -12, -15, -18, -21); - } - - public void test_multipliedBy_zeroBase() { - assertSame(Period.ZERO.multipliedBy(2), Period.ZERO); - } - - public void test_multipliedBy_zero() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.multipliedBy(0), Period.ZERO); - } - - public void test_multipliedBy_one() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertSame(test.multipliedBy(1), test); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_multipliedBy_overflowTooBig() { - Period test = Period.of(Integer.MAX_VALUE / 2 + 1, YEARS); - test.multipliedBy(2); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_multipliedBy_overflowTooSmall() { - Period test = Period.of(Integer.MIN_VALUE / 2 - 1, YEARS); - test.multipliedBy(2); - } - - //----------------------------------------------------------------------- - // negated() - //----------------------------------------------------------------------- - public void test_negated() { - Period test = Period.of(1, 2, 3, 4, 5, 6, 7); - assertPeriod(test.negated(), -1, -2, -3, -4, -5, -6, -7); - } - - public void test_negated_zero() { - assertSame(Period.ZERO.negated(), Period.ZERO); - } - - public void test_negated_max() { - assertPeriod(Period.of(Integer.MAX_VALUE, YEARS).negated(), -Integer.MAX_VALUE, 0, 0, 0, 0, 0, 0); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_negated_overflow() { - Period.of(Integer.MIN_VALUE, YEARS).negated(); - } - - //----------------------------------------------------------------------- - // normalizedHoursToDays() - //----------------------------------------------------------------------- - @DataProvider(name="normalizedHoursToDays") - Object[][] data_normalizedHoursToDays() { - return new Object[][] { - {0, 0, 0, 0}, - {1, 0, 1, 0}, - {-1, 0, -1, 0}, - - {1, 1, 1, 1}, - {1, 23, 1, 23}, - {1, 24, 2, 0}, - {1, 25, 2, 1}, - - {1, -1, 0, 23}, - {1, -23, 0, 1}, - {1, -24, 0, 0}, - {1, -25, 0, -1}, - {1, -47, 0, -23}, - {1, -48, -1, 0}, - {1, -49, -1, -1}, - - {-1, 1, 0, -23}, - {-1, 23, 0, -1}, - {-1, 24, 0, 0}, - {-1, 25, 0, 1}, - {-1, 47, 0, 23}, - {-1, 48, 1, 0}, - {-1, 49, 1, 1}, - - {-1, -1, -1, -1}, - {-1, -23, -1, -23}, - {-1, -24, -2, 0}, - {-1, -25, -2, -1}, - }; - } - - @Test(dataProvider="normalizedHoursToDays") - public void test_normalizedHoursToDays(int inputDays, int inputHours, int expectedDays, int expectedHours) { - assertPeriod(Period.of(0, 0, inputDays, inputHours, 0, 0, 0).normalizedHoursToDays(), 0, 0, expectedDays, expectedHours, 0, 0, 0); - } - - @Test(dataProvider="normalizedHoursToDays") - public void test_normalizedHoursToDays_yearsMonthsUnaffected(int inputDays, int inputHours, int expectedDays, int expectedHours) { - assertPeriod(Period.of(12, 6, inputDays, inputHours, 0, 0, 0).normalizedHoursToDays(), 12, 6, expectedDays, expectedHours, 0, 0, 0); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_normalizedHoursToDays_min() { - Period base = Period.of(0, 0, Integer.MIN_VALUE, -24, 0, 0, 0); - base.normalizedHoursToDays(); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_normalizedHoursToDays_max() { - Period base = Period.of(0, 0, Integer.MAX_VALUE, 24, 0, 0, 0); - base.normalizedHoursToDays(); - } - - //----------------------------------------------------------------------- - // normalizedDaysToHours() - //----------------------------------------------------------------------- - @DataProvider(name="normalizedDaysToHours") - Object[][] data_normalizedDaysToHours() { - return new Object[][] { - {0, 0, 0, 0, 0}, - - {1, 0, 0, 24, 0}, - {1, 1, 0, 25, 0}, - {1, 23, 0, 47, 0}, - {1, 24, 0, 48, 0}, - {1, 25, 0, 49, 0}, - {2, 23, 0, 71, 0}, - {2, 24, 0, 72, 0}, - {2, 25, 0, 73, 0}, - - {1, 0, 0, 24, 0}, - {1, -1, 0, 23, 0}, - {1, -23, 0, 1, 0}, - {1, -24, 0, 0, 0}, - {1, -25, 0, -1, 0}, - {2, -23, 0, 25, 0}, - {2, -24, 0, 24, 0}, - {2, -25, 0, 23, 0}, - - {-1, 0, 0, -24, 0}, - {-1, 1, 0, -23, 0}, - {-1, 23, 0, -1, 0}, - {-1, 24, 0, 0, 0}, - {-1, 25, 0, 1, 0}, - {-2, 23, 0, -25, 0}, - {-2, 24, 0, -24, 0}, - {-2, 25, 0, -23, 0}, - - {-1, 0, 0, -24, 0}, - {-1, -1, 0, -25, 0}, - {-1, -23, 0, -47, 0}, - {-1, -24, 0, -48, 0}, - {-1, -25, 0, -49, 0}, - - // minutes - {1, -1, -1, 22, 59}, - {1, -23, -1, 0, 59}, - {1, -24, -1, 0, -1}, - {1, -25, -1, -1, -1}, - {-1, 1, 1, -22, -59}, - {-1, 23, 1, 0, -59}, - {-1, 24, 1, 0, 1}, - {-1, 25, 1, 1, 1}, - }; - } - - @Test(dataProvider="normalizedDaysToHours") - public void test_normalizedDaysToHours(int inputDays, int inputHours, int inputMinutes, int expectedHours, int expectedMinutes) { - assertPeriod(Period.of(0, 0, inputDays, inputHours, inputMinutes, 0).normalizedDaysToHours(), 0, 0, 0, expectedHours, expectedMinutes, 0, 0); - } - - @Test(dataProvider="normalizedDaysToHours") - public void test_normalizedDaysToHours_yearsMonthsUnaffected(int inputDays, int inputHours, int inputMinutes, int expectedHours, int expectedMinutes) { - assertPeriod(Period.of(12, 6, inputDays, inputHours, inputMinutes, 0).normalizedDaysToHours(), 12, 6, 0, expectedHours, expectedMinutes, 0, 0); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_normalizedDaysToHours_min() { - Period base = Period.of(0, 0, -1_000, -10_000_000, 0, 0, 0); - base.normalizedDaysToHours(); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_normalizedDaysToHours_max() { - Period base = Period.of(0, 0, 1_000, 10_000_000, 0, 0, 0); - base.normalizedDaysToHours(); - } - - //----------------------------------------------------------------------- - // normalizedMonthsISO() - //----------------------------------------------------------------------- - @DataProvider(name="normalizedMonthsISO") - Object[][] data_normalizedMonthsISO() { - return new Object[][] { - {0, 0, 0, 0}, - {1, 0, 1, 0}, - {-1, 0, -1, 0}, - - {1, 1, 1, 1}, - {1, 2, 1, 2}, - {1, 11, 1, 11}, - {1, 12, 2, 0}, - {1, 13, 2, 1}, - {1, 23, 2, 11}, - {1, 24, 3, 0}, - {1, 25, 3, 1}, - - {1, -1, 0, 11}, - {1, -2, 0, 10}, - {1, -11, 0, 1}, - {1, -12, 0, 0}, - {1, -13, 0, -1}, - {1, -23, 0, -11}, - {1, -24, -1, 0}, - {1, -25, -1, -1}, - {1, -35, -1, -11}, - {1, -36, -2, 0}, - {1, -37, -2, -1}, - - {-1, 1, 0, -11}, - {-1, 11, 0, -1}, - {-1, 12, 0, 0}, - {-1, 13, 0, 1}, - {-1, 23, 0, 11}, - {-1, 24, 1, 0}, - {-1, 25, 1, 1}, - - {-1, -1, -1, -1}, - {-1, -11, -1, -11}, - {-1, -12, -2, 0}, - {-1, -13, -2, -1}, - }; - } - - @Test(dataProvider="normalizedMonthsISO") - public void test_normalizedMonthsISO(int inputYears, int inputMonths, int expectedYears, int expectedMonths) { - assertPeriod(Period.ofDate(inputYears, inputMonths, 0).normalizedMonthsISO(), expectedYears, expectedMonths, 0, 0, 0, 0, 0); - } - - @Test(dataProvider="normalizedMonthsISO") - public void test_normalizedMonthsISO_daysTimeUnaffected(int inputYears, int inputMonths, int expectedYears, int expectedMonths) { - assertPeriod(Period.of(inputYears, inputMonths, 5, 12, 30, 0, 0).normalizedMonthsISO(), expectedYears, expectedMonths, 5, 12, 30, 0, 0); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_normalizedMonthsISO_min() { - Period base = Period.ofDate(Integer.MIN_VALUE, -12, 0); - base.normalizedMonthsISO(); - } - - @Test(expectedExceptions=ArithmeticException.class) - public void test_normalizedMonthsISO_max() { - Period base = Period.ofDate(Integer.MAX_VALUE, 12, 0); - base.normalizedMonthsISO(); - } - - //----------------------------------------------------------------------- - // addTo() - //----------------------------------------------------------------------- - @DataProvider(name="addTo") - Object[][] data_addTo() { - return new Object[][] { - {pymd(0, 0, 0), date(2012, 6, 30), date(2012, 6, 30)}, - - {pymd(1, 0, 0), date(2012, 6, 10), date(2013, 6, 10)}, - {pymd(0, 1, 0), date(2012, 6, 10), date(2012, 7, 10)}, - {pymd(0, 0, 1), date(2012, 6, 10), date(2012, 6, 11)}, - - {pymd(-1, 0, 0), date(2012, 6, 10), date(2011, 6, 10)}, - {pymd(0, -1, 0), date(2012, 6, 10), date(2012, 5, 10)}, - {pymd(0, 0, -1), date(2012, 6, 10), date(2012, 6, 9)}, - - {pymd(1, 2, 3), date(2012, 6, 27), date(2013, 8, 30)}, - {pymd(1, 2, 3), date(2012, 6, 28), date(2013, 8, 31)}, - {pymd(1, 2, 3), date(2012, 6, 29), date(2013, 9, 1)}, - {pymd(1, 2, 3), date(2012, 6, 30), date(2013, 9, 2)}, - {pymd(1, 2, 3), date(2012, 7, 1), date(2013, 9, 4)}, - - {pymd(1, 0, 0), date(2011, 2, 28), date(2012, 2, 28)}, - {pymd(4, 0, 0), date(2011, 2, 28), date(2015, 2, 28)}, - {pymd(1, 0, 0), date(2012, 2, 29), date(2013, 2, 28)}, - {pymd(4, 0, 0), date(2012, 2, 29), date(2016, 2, 29)}, - - {pymd(1, 1, 0), date(2011, 1, 29), date(2012, 2, 29)}, - {pymd(1, 2, 0), date(2012, 2, 29), date(2013, 4, 29)}, - }; - } - - @Test(dataProvider="addTo") - public void test_addTo(Period period, LocalDate baseDate, LocalDate expected) { - assertEquals(period.addTo(baseDate), expected); - } - - @Test(dataProvider="addTo") - public void test_addTo_usingLocalDatePlus(Period period, LocalDate baseDate, LocalDate expected) { - assertEquals(baseDate.plus(period), expected); - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_addTo_nullZero() { - Period.ZERO.addTo(null); - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_addTo_nullNonZero() { - Period.of(2, DAYS).addTo(null); - } - - //----------------------------------------------------------------------- - // subtractFrom() - //----------------------------------------------------------------------- - @DataProvider(name="subtractFrom") - Object[][] data_subtractFrom() { - return new Object[][] { - {pymd(0, 0, 0), date(2012, 6, 30), date(2012, 6, 30)}, - - {pymd(1, 0, 0), date(2012, 6, 10), date(2011, 6, 10)}, - {pymd(0, 1, 0), date(2012, 6, 10), date(2012, 5, 10)}, - {pymd(0, 0, 1), date(2012, 6, 10), date(2012, 6, 9)}, - - {pymd(-1, 0, 0), date(2012, 6, 10), date(2013, 6, 10)}, - {pymd(0, -1, 0), date(2012, 6, 10), date(2012, 7, 10)}, - {pymd(0, 0, -1), date(2012, 6, 10), date(2012, 6, 11)}, - - {pymd(1, 2, 3), date(2012, 8, 30), date(2011, 6, 27)}, - {pymd(1, 2, 3), date(2012, 8, 31), date(2011, 6, 27)}, - {pymd(1, 2, 3), date(2012, 9, 1), date(2011, 6, 28)}, - {pymd(1, 2, 3), date(2012, 9, 2), date(2011, 6, 29)}, - {pymd(1, 2, 3), date(2012, 9, 3), date(2011, 6, 30)}, - {pymd(1, 2, 3), date(2012, 9, 4), date(2011, 7, 1)}, - - {pymd(1, 0, 0), date(2011, 2, 28), date(2010, 2, 28)}, - {pymd(4, 0, 0), date(2011, 2, 28), date(2007, 2, 28)}, - {pymd(1, 0, 0), date(2012, 2, 29), date(2011, 2, 28)}, - {pymd(4, 0, 0), date(2012, 2, 29), date(2008, 2, 29)}, - - {pymd(1, 1, 0), date(2013, 3, 29), date(2012, 2, 29)}, - {pymd(1, 2, 0), date(2012, 2, 29), date(2010, 12, 29)}, - }; - } - - @Test(dataProvider="subtractFrom") - public void test_subtractFrom(Period period, LocalDate baseDate, LocalDate expected) { - assertEquals(period.subtractFrom(baseDate), expected); - } - - @Test(dataProvider="subtractFrom") - public void test_subtractFrom_usingLocalDateMinus(Period period, LocalDate baseDate, LocalDate expected) { - assertEquals(baseDate.minus(period), expected); - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_subtractFrom_nullZero() { - Period.ZERO.subtractFrom(null); - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_subtractFrom_nullNonZero() { - Period.of(2, DAYS).subtractFrom(null); - } - - //----------------------------------------------------------------------- - // toDuration() - //----------------------------------------------------------------------- - public void test_toDuration() { - assertEquals(Period.ZERO.toDuration(), Duration.of(0, SECONDS)); - assertEquals(Period.of(0, 0, 0, 4, 5, 6, 7).toDuration(), Duration.ofSeconds((4 * 60 + 5) * 60L + 6, 7)); - } - - public void test_toDuration_calculation() { - assertEquals(Period.of(0, 0, 0, 2, 0, 0, 0).toDuration(), Duration.ofSeconds(2 * 3600)); - assertEquals(Period.of(0, 0, 0, 0, 2, 0, 0).toDuration(), Duration.of(120, SECONDS)); - assertEquals(Period.of(0, 0, 0, 0, 0, 2, 0).toDuration(), Duration.of(2, SECONDS)); - - assertEquals(Period.of(0, 0, 0, 0, 0, 3, 1000000000L - 1).toDuration(), Duration.ofSeconds(3, 999999999)); - assertEquals(Period.of(0, 0, 0, 0, 0, 3, 1000000000L).toDuration(), Duration.ofSeconds(4, 0)); - } - - public void test_toDuration_negatives() { - assertEquals(Period.of(0, 0, 0, 0, 0, 2, 1).toDuration(), Duration.ofSeconds(2, 1)); - assertEquals(Period.of(0, 0, 0, 0, 0, 2, -1).toDuration(), Duration.ofSeconds(1, 999999999)); - assertEquals(Period.of(0, 0, 0, 0, 0, -2, 1).toDuration(), Duration.ofSeconds(-2, 1)); - assertEquals(Period.of(0, 0, 0, 0, 0, -2, -1).toDuration(), Duration.ofSeconds(-3, 999999999)); - } - - @Test(expectedExceptions=DateTimeException.class) - public void test_toDuration_years() { - Period.of(1, 0, 0, 4, 5, 6, 7).toDuration(); - } - - @Test(expectedExceptions=DateTimeException.class) - public void test_toDuration_months() { - Period.of(0, 1, 0, 4, 5, 6, 7).toDuration(); - } - - @Test(expectedExceptions=DateTimeException.class) - public void test_toDuration_days() { - Duration test = Period.of(0, 0, 1, 4, 5, 6, 7).toDuration(); - assertEquals(test, Duration.ofSeconds(101106, 7L)); - } - - //----------------------------------------------------------------------- - // equals() / hashCode() - //----------------------------------------------------------------------- - public void test_equals() { - assertEquals(Period.of(1, 0, 0, 0, 0, 0).equals(Period.of(1, YEARS)), true); - assertEquals(Period.of(0, 1, 0, 0, 0, 0).equals(Period.of(1, MONTHS)), true); - assertEquals(Period.of(0, 0, 1, 0, 0, 0).equals(Period.of(1, DAYS)), true); - assertEquals(Period.of(0, 0, 0, 1, 0, 0).equals(Period.of(1, HOURS)), true); - assertEquals(Period.of(0, 0, 0, 0, 1, 0).equals(Period.of(1, MINUTES)), true); - assertEquals(Period.of(0, 0, 0, 0, 0, 1).equals(Period.of(1, SECONDS)), true); - assertEquals(Period.of(1, 2, 3, 0, 0, 0).equals(Period.ofDate(1, 2, 3)), true); - assertEquals(Period.of(0, 0, 0, 1, 2, 3).equals(Period.ofTime(1, 2, 3)), true); - assertEquals(Period.of(1, 2, 3, 4, 5, 6).equals(Period.of(1, 2, 3, 4, 5, 6)), true); - - assertEquals(Period.of(1, YEARS).equals(Period.of(1, YEARS)), true); - assertEquals(Period.of(1, YEARS).equals(Period.of(2, YEARS)), false); - - assertEquals(Period.of(1, MONTHS).equals(Period.of(1, MONTHS)), true); - assertEquals(Period.of(1, MONTHS).equals(Period.of(2, MONTHS)), false); - - assertEquals(Period.of(1, DAYS).equals(Period.of(1, DAYS)), true); - assertEquals(Period.of(1, DAYS).equals(Period.of(2, DAYS)), false); - - assertEquals(Period.of(1, HOURS).equals(Period.of(1, HOURS)), true); - assertEquals(Period.of(1, HOURS).equals(Period.of(2, HOURS)), false); - - assertEquals(Period.of(1, MINUTES).equals(Period.of(1, MINUTES)), true); - assertEquals(Period.of(1, MINUTES).equals(Period.of(2, MINUTES)), false); - - assertEquals(Period.of(1, SECONDS).equals(Period.of(1, SECONDS)), true); - assertEquals(Period.of(1, SECONDS).equals(Period.of(2, SECONDS)), false); - - assertEquals(Period.ofDate(1, 2, 3).equals(Period.ofDate(1, 2, 3)), true); - assertEquals(Period.ofDate(1, 2, 3).equals(Period.ofDate(0, 2, 3)), false); - assertEquals(Period.ofDate(1, 2, 3).equals(Period.ofDate(1, 0, 3)), false); - assertEquals(Period.ofDate(1, 2, 3).equals(Period.ofDate(1, 2, 0)), false); - - assertEquals(Period.ofTime(1, 2, 3).equals(Period.ofTime(1, 2, 3)), true); - assertEquals(Period.ofTime(1, 2, 3).equals(Period.ofTime(0, 2, 3)), false); - assertEquals(Period.ofTime(1, 2, 3).equals(Period.ofTime(1, 0, 3)), false); - assertEquals(Period.ofTime(1, 2, 3).equals(Period.ofTime(1, 2, 0)), false); - } - - public void test_equals_self() { - Period test = Period.of(1, 2, 3, 4, 5, 6); - assertEquals(test.equals(test), true); - } - - public void test_equals_null() { - Period test = Period.of(1, 2, 3, 4, 5, 6); - assertEquals(test.equals(null), false); - } - - public void test_equals_otherClass() { - Period test = Period.of(1, 2, 3, 4, 5, 6); - assertEquals(test.equals(""), false); - } - + // hashCode() //----------------------------------------------------------------------- public void test_hashCode() { - Period test5 = Period.of(5, DAYS); - Period test6 = Period.of(6, DAYS); - Period test5M = Period.of(5, MONTHS); - Period test5Y = Period.of(5, YEARS); + Period test5 = Period.ofDays(5); + Period test6 = Period.ofDays(6); + Period test5M = Period.ofMonths(5); + Period test5Y = Period.ofYears(5); assertEquals(test5.hashCode() == test5.hashCode(), true); assertEquals(test5.hashCode() == test6.hashCode(), false); assertEquals(test5.hashCode() == test5M.hashCode(), false); assertEquals(test5.hashCode() == test5Y.hashCode(), false); } - //----------------------------------------------------------------------- - // toString() - //----------------------------------------------------------------------- - @DataProvider(name="toStringAndParse") - Object[][] data_toString() { - return new Object[][] { - {Period.ZERO, "PT0S"}, - {Period.of(0, DAYS), "PT0S"}, - {Period.of(1, YEARS), "P1Y"}, - {Period.of(1, MONTHS), "P1M"}, - {Period.of(1, DAYS), "P1D"}, - {Period.of(1, HOURS), "PT1H"}, - {Period.of(1, MINUTES), "PT1M"}, - {Period.of(1, SECONDS), "PT1S"}, - {Period.of(12, SECONDS), "PT12S"}, - {Period.of(123, SECONDS), "PT2M3S"}, - {Period.of(1234, SECONDS), "PT20M34S"}, - {Period.of(-1, SECONDS), "PT-1S"}, - {Period.of(-12, SECONDS), "PT-12S"}, - {Period.of(-123, SECONDS), "PT-2M-3S"}, - {Period.of(-1234, SECONDS), "PT-20M-34S"}, - {Period.of(1, 2, 3, 4, 5, 6), "P1Y2M3DT4H5M6S"}, - {Period.of(1, 2, 3, 4, 5, 6, 700000000), "P1Y2M3DT4H5M6.7S"}, - {Period.of(0, 0, 0, 0, 0, 0, 100000000), "PT0.1S"}, - {Period.of(0, 0, 0, 0, 0, 0, -100000000), "PT-0.1S"}, - {Period.of(0, 0, 0, 0, 0, 1, -900000000), "PT0.1S"}, - {Period.of(0, 0, 0, 0, 0, -1, 900000000), "PT-0.1S"}, - {Period.of(0, 0, 0, 0, 0, 1, 100000000), "PT1.1S"}, - {Period.of(0, 0, 0, 0, 0, 1, -100000000), "PT0.9S"}, - {Period.of(0, 0, 0, 0, 0, -1, 100000000), "PT-0.9S"}, - {Period.of(0, 0, 0, 0, 0, -1, -100000000), "PT-1.1S"}, - {Period.of(0, 0, 0, 0, 0, 0, 10000000), "PT0.01S"}, - {Period.of(0, 0, 0, 0, 0, 0, -10000000), "PT-0.01S"}, - {Period.of(0, 0, 0, 0, 0, 0, 1000000), "PT0.001S"}, - {Period.of(0, 0, 0, 0, 0, 0, -1000000), "PT-0.001S"}, - {Period.of(0, 0, 0, 0, 0, 0, 1000), "PT0.000001S"}, - {Period.of(0, 0, 0, 0, 0, 0, -1000), "PT-0.000001S"}, - {Period.of(0, 0, 0, 0, 0, 0, 1), "PT0.000000001S"}, - {Period.of(0, 0, 0, 0, 0, 0, -1), "PT-0.000000001S"}, - }; - } - - @Test(groups="tck", dataProvider="toStringAndParse") - public void test_toString(Period input, String expected) { - assertEquals(input.toString(), expected); - } - - //----------------------------------------------------------------------- - private void assertPeriod(Period test, int y, int mo, int d, int h, int mn, int s, long n) { - assertEquals(test.getYears(), y, "years"); - assertEquals(test.getMonths(), mo, "months"); - assertEquals(test.getDays(), d, "days"); - assertEquals(test.getHours(), h, "hours"); - assertEquals(test.getMinutes(), mn, "mins"); - assertEquals(test.getSeconds(), s, "secs"); - assertEquals(test.getNanos(), n, "nanos"); - assertEquals(test.getTimeNanos(), (((h * 60L + mn) * 60 + s) * 1_000_000_000L + n), "total nanos"); - } - - private static Period pymd(int y, int m, int d) { - return Period.ofDate(y, m, d); - } - - private static LocalDate date(int y, int m, int d) { - return LocalDate.of(y, m, d); - } - } diff --git a/jdk/test/java/time/test/java/time/TestPeriodParser.java b/jdk/test/java/time/test/java/time/TestPeriodParser.java deleted file mode 100644 index 1d3a8abe373..00000000000 --- a/jdk/test/java/time/test/java/time/TestPeriodParser.java +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file: - * - * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of JSR-310 nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package test.java.time; - -import java.time.*; - -import static java.time.temporal.ChronoUnit.DAYS; -import static java.time.temporal.ChronoUnit.HOURS; -import static java.time.temporal.ChronoUnit.MINUTES; -import static java.time.temporal.ChronoUnit.MONTHS; -import static java.time.temporal.ChronoUnit.NANOS; -import static java.time.temporal.ChronoUnit.SECONDS; -import static java.time.temporal.ChronoUnit.YEARS; -import static org.testng.Assert.assertEquals; - -import java.time.format.DateTimeParseException; - -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -/** - * Test PeriodParser. - */ -@Test -public class TestPeriodParser { - - //----------------------------------------------------------------------- - // parse(String) - //----------------------------------------------------------------------- - @DataProvider(name="Parse") - Object[][] provider_factory_parse() { - return new Object[][] { - {"Pt0S", Period.ZERO}, - {"pT0S", Period.ZERO}, - {"PT0S", Period.ZERO}, - {"Pt0s", Period.ZERO}, - {"pt0s", Period.ZERO}, - {"P0Y0M0DT0H0M0.0S", Period.ZERO}, - - {"P1Y", Period.of(1, YEARS)}, - {"P100Y", Period.of(100, YEARS)}, - {"P-25Y", Period.of(-25, YEARS)}, - {"P" + Integer.MAX_VALUE + "Y", Period.of(Integer.MAX_VALUE, YEARS)}, - {"P" + Integer.MIN_VALUE + "Y", Period.of(Integer.MIN_VALUE, YEARS)}, - - {"P1M", Period.of(1, MONTHS)}, - {"P0M", Period.of(0, MONTHS)}, - {"P-1M", Period.of(-1, MONTHS)}, - {"P" + Integer.MAX_VALUE + "M", Period.of(Integer.MAX_VALUE, MONTHS)}, - {"P" + Integer.MIN_VALUE + "M", Period.of(Integer.MIN_VALUE, MONTHS)}, - - {"P1D", Period.of(1, DAYS)}, - {"P0D", Period.of(0, DAYS)}, - {"P-1D", Period.of(-1, DAYS)}, - {"P" + Integer.MAX_VALUE + "D", Period.of(Integer.MAX_VALUE, DAYS)}, - {"P" + Integer.MIN_VALUE + "D", Period.of(Integer.MIN_VALUE, DAYS)}, - - {"P2Y3M25D", Period.ofDate(2, 3, 25)}, - - {"PT1H", Period.of(1, HOURS)}, - {"PT-1H", Period.of(-1, HOURS)}, - {"PT24H", Period.of(24, HOURS)}, - {"PT-24H", Period.of(-24, HOURS)}, - {"PT" + Integer.MAX_VALUE / (3600 * 8) + "H", Period.of(Integer.MAX_VALUE / (3600 * 8), HOURS)}, - {"PT" + Integer.MIN_VALUE / (3600 * 8) + "H", Period.of(Integer.MIN_VALUE / (3600 * 8), HOURS)}, - - {"PT1M", Period.of(1, MINUTES)}, - {"PT-1M", Period.of(-1, MINUTES)}, - {"PT60M", Period.of(60, MINUTES)}, - {"PT-60M", Period.of(-60, MINUTES)}, - {"PT" + Integer.MAX_VALUE / (60 * 8) + "M", Period.of(Integer.MAX_VALUE / (60 * 8), MINUTES)}, - {"PT" + Integer.MIN_VALUE / (60 * 8) + "M", Period.of(Integer.MIN_VALUE / (60 * 8), MINUTES)}, - - {"PT1S", Period.of(1, SECONDS)}, - {"PT-1S", Period.of(-1, SECONDS)}, - {"PT60S", Period.of(60, SECONDS)}, - {"PT-60S", Period.of(-60, SECONDS)}, - {"PT" + Integer.MAX_VALUE + "S", Period.of(Integer.MAX_VALUE, SECONDS)}, - {"PT" + Integer.MIN_VALUE + "S", Period.of(Integer.MIN_VALUE, SECONDS)}, - - {"PT0.1S", Period.of( 0, 0, 0, 0, 0, 0, 100000000 ) }, - {"PT-0.1S", Period.of( 0, 0, 0, 0, 0, 0, -100000000 ) }, - {"PT1.1S", Period.of( 0, 0, 0, 0, 0, 1, 100000000 ) }, - {"PT-1.1S", Period.of( 0, 0, 0, 0, 0, -1, -100000000 ) }, - {"PT1.0001S", Period.of(1, SECONDS).plus( 100000, NANOS ) }, - {"PT1.0000001S", Period.of(1, SECONDS).plus( 100, NANOS ) }, - {"PT1.123456789S", Period.of( 0, 0, 0, 0, 0, 1, 123456789 ) }, - {"PT1.999999999S", Period.of( 0, 0, 0, 0, 0, 1, 999999999 ) }, - - }; - } - - @Test(dataProvider="Parse") - public void factory_parse(String text, Period expected) { - Period p = Period.parse(text); - assertEquals(p, expected); - } - - @Test(dataProvider="Parse") - public void factory_parse_comma(String text, Period expected) { - if (text.contains(".")) { - text = text.replace('.', ','); - Period p = Period.parse(text); - assertEquals(p, expected); - } - } - - @DataProvider(name="ParseFailures") - Object[][] provider_factory_parseFailures() { - return new Object[][] { - {"", 0}, - {"PTS", 2}, - {"AT0S", 0}, - {"PA0S", 1}, - {"PT0A", 3}, - - {"PT+S", 2}, - {"PT-S", 2}, - {"PT.S", 2}, - {"PTAS", 2}, - - {"PT+0S", 2}, - {"PT-0S", 2}, - {"PT+1S", 2}, - {"PT-.S", 2}, - - {"PT1ABC2S", 3}, - {"PT1.1ABC2S", 5}, - - {"PT123456789123456789123456789S", 2}, - {"PT0.1234567891S", 4}, - {"PT1.S", 2}, - {"PT.1S", 2}, - - {"PT2.-3S", 2}, - {"PT-2.-3S", 2}, - - {"P1Y1MT1DT1M1S", 7}, - {"P1Y1MT1HT1M1S", 8}, - {"P1YMD", 3}, - {"PT1ST1D", 4}, - {"P1Y2Y", 4}, - {"PT1M+3S", 4}, - - {"PT1S1", 4}, - {"PT1S.", 4}, - {"PT1SA", 4}, - {"PT1M1", 4}, - {"PT1M.", 4}, - {"PT1MA", 4}, - }; - } - - @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class) - public void factory_parseFailures(String text, int errPos) { - try { - Period.parse(text); - } catch (DateTimeParseException ex) { - assertEquals(ex.getParsedString(), text); - assertEquals(ex.getErrorIndex(), errPos); - throw ex; - } - } - - @Test(dataProvider="ParseFailures", expectedExceptions=DateTimeParseException.class) - public void factory_parseFailures_comma(String text, int errPos) { - text = text.replace('.', ','); - try { - Period.parse(text); - } catch (DateTimeParseException ex) { - assertEquals(ex.getParsedString(), text); - assertEquals(ex.getErrorIndex(), errPos); - throw ex; - } - } - - @Test(expectedExceptions=DateTimeParseException.class) - public void factory_parse_tooBig() { - String text = "PT" + Long.MAX_VALUE + "1S"; - Period.parse(text); - } - - @Test(expectedExceptions=DateTimeParseException.class) - public void factory_parse_tooBig_decimal() { - String text = "PT" + Long.MAX_VALUE + "1.1S"; - Period.parse(text); - } - - @Test(expectedExceptions=DateTimeParseException.class) - public void factory_parse_tooSmall() { - String text = "PT" + Long.MIN_VALUE + "1S"; - Period.parse(text); - } - - @Test(expectedExceptions=DateTimeParseException.class) - public void factory_parse_tooSmall_decimal() { - String text = "PT" + Long.MIN_VALUE + ".1S"; - Period.parse(text); - } - - @Test(expectedExceptions=NullPointerException.class) - public void factory_parse_null() { - Period.parse(null); - } - - @DataProvider(name="ParseSequenceFailures") - Object[][] provider_factory_parseSequenceFailures() { - return new Object[][] { - {"P0M0Y0DT0H0M0.0S"}, - {"P0M0D0YT0H0M0.0S"}, - {"P0S0D0YT0S0M0.0H"}, - {"PT0M0H0.0S"}, - {"PT0M0H"}, - {"PT0S0M"}, - {"PT0.0M2S"}, - }; - } - - @Test(dataProvider="ParseSequenceFailures", expectedExceptions=DateTimeParseException.class) - public void factory_parse_badSequence(String text) { - Period.parse(text); - } - -} diff --git a/jdk/test/java/time/test/java/time/temporal/TestYear.java b/jdk/test/java/time/test/java/time/TestYear.java similarity index 96% rename from jdk/test/java/time/test/java/time/temporal/TestYear.java rename to jdk/test/java/time/test/java/time/TestYear.java index 5880ac46820..71791ab5fa7 100644 --- a/jdk/test/java/time/test/java/time/temporal/TestYear.java +++ b/jdk/test/java/time/test/java/time/TestYear.java @@ -57,12 +57,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package test.java.time.temporal; +package test.java.time; -import java.time.temporal.Year; +import java.time.Year; import org.testng.annotations.Test; -import test.java.time.AbstractTest; /** * Test Year. diff --git a/jdk/test/java/time/test/java/time/temporal/TestYearMonth.java b/jdk/test/java/time/test/java/time/TestYearMonth.java similarity index 96% rename from jdk/test/java/time/test/java/time/temporal/TestYearMonth.java rename to jdk/test/java/time/test/java/time/TestYearMonth.java index ab0d7f4c8cb..f02ed96a5d7 100644 --- a/jdk/test/java/time/test/java/time/temporal/TestYearMonth.java +++ b/jdk/test/java/time/test/java/time/TestYearMonth.java @@ -57,12 +57,11 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package test.java.time.temporal; +package test.java.time; -import java.time.temporal.YearMonth; +import java.time.YearMonth; import org.testng.annotations.Test; -import test.java.time.AbstractTest; /** * Test YearMonth. diff --git a/jdk/test/java/time/test/java/time/TestZoneId.java b/jdk/test/java/time/test/java/time/TestZoneId.java index 5e9380391df..6aa373288a7 100644 --- a/jdk/test/java/time/test/java/time/TestZoneId.java +++ b/jdk/test/java/time/test/java/time/TestZoneId.java @@ -59,32 +59,28 @@ */ package test.java.time; -import java.time.*; - import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; -import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.SimpleTimeZone; -import java.util.TimeZone; - -import java.time.temporal.Queries; -import java.time.temporal.TemporalQuery; -import java.time.temporal.TemporalAccessor; -import java.time.temporal.TemporalField; +import java.time.DateTimeException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.time.format.TextStyle; import java.time.zone.ZoneOffsetTransition; import java.time.zone.ZoneRules; import java.time.zone.ZoneRulesException; +import java.util.List; +import java.util.Locale; +import java.util.SimpleTimeZone; +import java.util.TimeZone; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -95,8 +91,6 @@ import org.testng.annotations.Test; @Test public class TestZoneId extends AbstractTest { - private static final ZoneId ZONE_PARIS = ZoneId.of("Europe/Paris"); - public static final String LATEST_TZDB = "2010i"; private static final int OVERLAP = 2; private static final int GAP = 0; @@ -104,6 +98,7 @@ public class TestZoneId extends AbstractTest { // Basics //----------------------------------------------------------------------- public void test_immutable() { + // cannot use standard test as ZoneId is abstract Class cls = ZoneId.class; assertTrue(Modifier.isPublic(cls.getModifiers())); Field[] fields = cls.getDeclaredFields(); @@ -116,127 +111,27 @@ public class TestZoneId extends AbstractTest { } } - public void test_serialization_UTC() throws Exception { - ZoneId test = ZoneOffset.UTC; - assertSerializableAndSame(test); - } - - public void test_serialization_fixed() throws Exception { - ZoneId test = ZoneId.of("UTC+01:30"); - assertSerializable(test); - } - - public void test_serialization_Europe() throws Exception { - ZoneId test = ZoneId.of("Europe/London"); - assertSerializable(test); - } - - public void test_serialization_America() throws Exception { - ZoneId test = ZoneId.of("America/Chicago"); - assertSerializable(test); - } - //----------------------------------------------------------------------- // UTC //----------------------------------------------------------------------- public void test_constant_UTC() { ZoneId test = ZoneOffset.UTC; assertEquals(test.getId(), "Z"); - assertEquals(test.getText(TextStyle.FULL, Locale.UK), "Z"); + assertEquals(test.getDisplayName(TextStyle.FULL, Locale.UK), "Z"); assertEquals(test.getRules().isFixedOffset(), true); assertEquals(test.getRules().getOffset(Instant.ofEpochSecond(0L)), ZoneOffset.UTC); checkOffset(test.getRules(), createLDT(2008, 6, 30), ZoneOffset.UTC, 1); assertSame(test, ZoneId.of("UTC+00")); } - //----------------------------------------------------------------------- - // OLD_IDS_PRE_2005 - //----------------------------------------------------------------------- - public void test_constant_OLD_IDS_PRE_2005() { - Map ids = ZoneId.OLD_IDS_PRE_2005; - assertEquals(ids.get("EST"), "America/Indianapolis"); - assertEquals(ids.get("MST"), "America/Phoenix"); - assertEquals(ids.get("HST"), "Pacific/Honolulu"); - assertEquals(ids.get("ACT"), "Australia/Darwin"); - assertEquals(ids.get("AET"), "Australia/Sydney"); - assertEquals(ids.get("AGT"), "America/Argentina/Buenos_Aires"); - assertEquals(ids.get("ART"), "Africa/Cairo"); - assertEquals(ids.get("AST"), "America/Anchorage"); - assertEquals(ids.get("BET"), "America/Sao_Paulo"); - assertEquals(ids.get("BST"), "Asia/Dhaka"); - assertEquals(ids.get("CAT"), "Africa/Harare"); - assertEquals(ids.get("CNT"), "America/St_Johns"); - assertEquals(ids.get("CST"), "America/Chicago"); - assertEquals(ids.get("CTT"), "Asia/Shanghai"); - assertEquals(ids.get("EAT"), "Africa/Addis_Ababa"); - assertEquals(ids.get("ECT"), "Europe/Paris"); - assertEquals(ids.get("IET"), "America/Indiana/Indianapolis"); - assertEquals(ids.get("IST"), "Asia/Kolkata"); - assertEquals(ids.get("JST"), "Asia/Tokyo"); - assertEquals(ids.get("MIT"), "Pacific/Apia"); - assertEquals(ids.get("NET"), "Asia/Yerevan"); - assertEquals(ids.get("NST"), "Pacific/Auckland"); - assertEquals(ids.get("PLT"), "Asia/Karachi"); - assertEquals(ids.get("PNT"), "America/Phoenix"); - assertEquals(ids.get("PRT"), "America/Puerto_Rico"); - assertEquals(ids.get("PST"), "America/Los_Angeles"); - assertEquals(ids.get("SST"), "Pacific/Guadalcanal"); - assertEquals(ids.get("VST"), "Asia/Ho_Chi_Minh"); - } - - @Test(expectedExceptions=UnsupportedOperationException.class) - public void test_constant_OLD_IDS_PRE_2005_immutable() { - Map ids = ZoneId.OLD_IDS_PRE_2005; - ids.clear(); - } - - //----------------------------------------------------------------------- - // OLD_IDS_POST_2005 - //----------------------------------------------------------------------- - public void test_constant_OLD_IDS_POST_2005() { - Map ids = ZoneId.OLD_IDS_POST_2005; - assertEquals(ids.get("EST"), "-05:00"); - assertEquals(ids.get("MST"), "-07:00"); - assertEquals(ids.get("HST"), "-10:00"); - assertEquals(ids.get("ACT"), "Australia/Darwin"); - assertEquals(ids.get("AET"), "Australia/Sydney"); - assertEquals(ids.get("AGT"), "America/Argentina/Buenos_Aires"); - assertEquals(ids.get("ART"), "Africa/Cairo"); - assertEquals(ids.get("AST"), "America/Anchorage"); - assertEquals(ids.get("BET"), "America/Sao_Paulo"); - assertEquals(ids.get("BST"), "Asia/Dhaka"); - assertEquals(ids.get("CAT"), "Africa/Harare"); - assertEquals(ids.get("CNT"), "America/St_Johns"); - assertEquals(ids.get("CST"), "America/Chicago"); - assertEquals(ids.get("CTT"), "Asia/Shanghai"); - assertEquals(ids.get("EAT"), "Africa/Addis_Ababa"); - assertEquals(ids.get("ECT"), "Europe/Paris"); - assertEquals(ids.get("IET"), "America/Indiana/Indianapolis"); - assertEquals(ids.get("IST"), "Asia/Kolkata"); - assertEquals(ids.get("JST"), "Asia/Tokyo"); - assertEquals(ids.get("MIT"), "Pacific/Apia"); - assertEquals(ids.get("NET"), "Asia/Yerevan"); - assertEquals(ids.get("NST"), "Pacific/Auckland"); - assertEquals(ids.get("PLT"), "Asia/Karachi"); - assertEquals(ids.get("PNT"), "America/Phoenix"); - assertEquals(ids.get("PRT"), "America/Puerto_Rico"); - assertEquals(ids.get("PST"), "America/Los_Angeles"); - assertEquals(ids.get("SST"), "Pacific/Guadalcanal"); - assertEquals(ids.get("VST"), "Asia/Ho_Chi_Minh"); - } - - @Test(expectedExceptions=UnsupportedOperationException.class) - public void test_constant_OLD_IDS_POST_2005_immutable() { - Map ids = ZoneId.OLD_IDS_POST_2005; - ids.clear(); - } - //----------------------------------------------------------------------- // system default //----------------------------------------------------------------------- public void test_systemDefault() { ZoneId test = ZoneId.systemDefault(); - assertEquals(test.getId(), TimeZone.getDefault().getID()); + assertEquals(test.getId(), TimeZone.getDefault() + .getID() + .replaceAll("GMT|UTC|UT", "Z")); } @Test(expectedExceptions = DateTimeException.class) @@ -261,72 +156,10 @@ public class TestZoneId extends AbstractTest { } } - //----------------------------------------------------------------------- - // mapped factory - //----------------------------------------------------------------------- - public void test_of_string_Map() { - Map map = new HashMap(); - map.put("LONDON", "Europe/London"); - map.put("PARIS", "Europe/Paris"); - ZoneId test = ZoneId.of("LONDON", map); - assertEquals(test.getId(), "Europe/London"); - } - - public void test_of_string_Map_lookThrough() { - Map map = new HashMap(); - map.put("LONDON", "Europe/London"); - map.put("PARIS", "Europe/Paris"); - ZoneId test = ZoneId.of("Europe/Madrid", map); - assertEquals(test.getId(), "Europe/Madrid"); - } - - public void test_of_string_Map_emptyMap() { - Map map = new HashMap(); - ZoneId test = ZoneId.of("Europe/Madrid", map); - assertEquals(test.getId(), "Europe/Madrid"); - } - - @Test(expectedExceptions=DateTimeException.class) - public void test_of_string_Map_badFormat() { - Map map = new HashMap(); - ZoneId.of("Not kknown", map); - } - - @Test(expectedExceptions=ZoneRulesException.class) - public void test_of_string_Map_unknown() { - Map map = new HashMap(); - ZoneId.of("Unknown", map); - } - - //----------------------------------------------------------------------- - // regular factory - //----------------------------------------------------------------------- - @DataProvider(name="String_UTC") - Object[][] data_of_string_UTC() { - return new Object[][] { - {""}, {"Z"}, - {"+00"},{"+0000"},{"+00:00"},{"+000000"},{"+00:00:00"}, - {"-00"},{"-0000"},{"-00:00"},{"-000000"},{"-00:00:00"}, - }; - } - - @Test(dataProvider="String_UTC") - public void test_of_string_UTC(String id) { - ZoneId test = ZoneId.of("UTC" + id); - assertSame(test, ZoneOffset.UTC); - } - - @Test(dataProvider="String_UTC") - public void test_of_string_GMT(String id) { - ZoneId test = ZoneId.of("GMT" + id); - assertSame(test, ZoneOffset.UTC); - } - //----------------------------------------------------------------------- @DataProvider(name="String_Fixed") Object[][] data_of_string_Fixed() { return new Object[][] { - {"Z", "Z"}, {"+0", "Z"}, {"+5", "+05:00"}, {"+01", "+01:00"}, @@ -346,7 +179,7 @@ public class TestZoneId extends AbstractTest { public void test_of_string_offset(String input, String id) { ZoneId test = ZoneId.of(input); assertEquals(test.getId(), id); - assertEquals(test.getText(TextStyle.FULL, Locale.UK), id); + assertEquals(test.getDisplayName(TextStyle.FULL, Locale.UK), id); assertEquals(test.getRules().isFixedOffset(), true); ZoneOffset offset = ZoneOffset.of(id); assertEquals(test.getRules().getOffset(Instant.ofEpochSecond(0L)), offset); @@ -357,7 +190,7 @@ public class TestZoneId extends AbstractTest { public void test_of_string_FixedUTC(String input, String id) { ZoneId test = ZoneId.of("UTC" + input); assertEquals(test.getId(), id); - assertEquals(test.getText(TextStyle.FULL, Locale.UK), id); + assertEquals(test.getDisplayName(TextStyle.FULL, Locale.UK), id); assertEquals(test.getRules().isFixedOffset(), true); ZoneOffset offset = ZoneOffset.of(id); assertEquals(test.getRules().getOffset(Instant.ofEpochSecond(0L)), offset); @@ -368,143 +201,13 @@ public class TestZoneId extends AbstractTest { public void test_of_string_FixedGMT(String input, String id) { ZoneId test = ZoneId.of("GMT" + input); assertEquals(test.getId(), id); - assertEquals(test.getText(TextStyle.FULL, Locale.UK), id); + assertEquals(test.getDisplayName(TextStyle.FULL, Locale.UK), id); assertEquals(test.getRules().isFixedOffset(), true); ZoneOffset offset = ZoneOffset.of(id); assertEquals(test.getRules().getOffset(Instant.ofEpochSecond(0L)), offset); checkOffset(test.getRules(), createLDT(2008, 6, 30), offset, 1); } - //----------------------------------------------------------------------- - @DataProvider(name="String_UTC_Invalid") - Object[][] data_of_string_UTC_invalid() { - return new Object[][] { - {"A"}, {"B"}, {"C"}, {"D"}, {"E"}, {"F"}, {"G"}, {"H"}, {"I"}, {"J"}, {"K"}, {"L"}, {"M"}, - {"N"}, {"O"}, {"P"}, {"Q"}, {"R"}, {"S"}, {"T"}, {"U"}, {"V"}, {"W"}, {"X"}, {"Y"}, - {"+0:00"}, {"+00:0"}, {"+0:0"}, - {"+000"}, {"+00000"}, - {"+0:00:00"}, {"+00:0:00"}, {"+00:00:0"}, {"+0:0:0"}, {"+0:0:00"}, {"+00:0:0"}, {"+0:00:0"}, - {"+01_00"}, {"+01;00"}, {"+01@00"}, {"+01:AA"}, - {"+19"}, {"+19:00"}, {"+18:01"}, {"+18:00:01"}, {"+1801"}, {"+180001"}, - {"-0:00"}, {"-00:0"}, {"-0:0"}, - {"-000"}, {"-00000"}, - {"-0:00:00"}, {"-00:0:00"}, {"-00:00:0"}, {"-0:0:0"}, {"-0:0:00"}, {"-00:0:0"}, {"-0:00:0"}, - {"-19"}, {"-19:00"}, {"-18:01"}, {"-18:00:01"}, {"-1801"}, {"-180001"}, - {"-01_00"}, {"-01;00"}, {"-01@00"}, {"-01:AA"}, - {"@01:00"}, - }; - } - - @Test(dataProvider="String_UTC_Invalid", expectedExceptions=DateTimeException.class) - public void test_of_string_UTC_invalid(String id) { - ZoneId.of("UTC" + id); - } - - @Test(dataProvider="String_UTC_Invalid", expectedExceptions=DateTimeException.class) - public void test_of_string_GMT_invalid(String id) { - ZoneId.of("GMT" + id); - } - - //----------------------------------------------------------------------- - @DataProvider(name="String_Invalid") - Object[][] data_of_string_invalid() { - // \u00ef is a random unicode character - return new Object[][] { - {""}, {":"}, {"#"}, - {"\u00ef"}, {"`"}, {"!"}, {"\""}, {"\u00ef"}, {"$"}, {"^"}, {"&"}, {"*"}, {"("}, {")"}, {"="}, - {"\\"}, {"|"}, {","}, {"<"}, {">"}, {"?"}, {";"}, {"'"}, {"["}, {"]"}, {"{"}, {"}"}, - {"\u00ef:A"}, {"`:A"}, {"!:A"}, {"\":A"}, {"\u00ef:A"}, {"$:A"}, {"^:A"}, {"&:A"}, {"*:A"}, {"(:A"}, {"):A"}, {"=:A"}, {"+:A"}, - {"\\:A"}, {"|:A"}, {",:A"}, {"<:A"}, {">:A"}, {"?:A"}, {";:A"}, {"::A"}, {"':A"}, {"@:A"}, {"~:A"}, {"[:A"}, {"]:A"}, {"{:A"}, {"}:A"}, - {"A:B#\u00ef"}, {"A:B#`"}, {"A:B#!"}, {"A:B#\""}, {"A:B#\u00ef"}, {"A:B#$"}, {"A:B#^"}, {"A:B#&"}, {"A:B#*"}, - {"A:B#("}, {"A:B#)"}, {"A:B#="}, {"A:B#+"}, - {"A:B#\\"}, {"A:B#|"}, {"A:B#,"}, {"A:B#<"}, {"A:B#>"}, {"A:B#?"}, {"A:B#;"}, {"A:B#:"}, - {"A:B#'"}, {"A:B#@"}, {"A:B#~"}, {"A:B#["}, {"A:B#]"}, {"A:B#{"}, {"A:B#}"}, - }; - } - - @Test(dataProvider="String_Invalid", expectedExceptions=DateTimeException.class) - public void test_of_string_invalid(String id) { - ZoneId.of(id); - } - - //----------------------------------------------------------------------- - public void test_of_string_GMT0() { - ZoneId test = ZoneId.of("GMT0"); - assertEquals(test.getId(), "Z"); - assertEquals(test.getRules().isFixedOffset(), true); - } - - //----------------------------------------------------------------------- - public void test_of_string_London() { - ZoneId test = ZoneId.of("Europe/London"); - assertEquals(test.getId(), "Europe/London"); - assertEquals(test.getRules().isFixedOffset(), false); - } - - //----------------------------------------------------------------------- - @Test(expectedExceptions=NullPointerException.class) - public void test_of_string_null() { - ZoneId.of((String) null); - } - - @Test(expectedExceptions=ZoneRulesException.class) - public void test_of_string_unknown_simple() { - ZoneId.of("Unknown"); - } - - //------------------------------------------------------------------------- - // TODO: test by deserialization -// public void test_ofUnchecked_string_invalidNotChecked() { -// ZoneRegion test = ZoneRegion.ofLenient("Unknown"); -// assertEquals(test.getId(), "Unknown"); -// } -// -// public void test_ofUnchecked_string_invalidNotChecked_unusualCharacters() { -// ZoneRegion test = ZoneRegion.ofLenient("QWERTYUIOPASDFGHJKLZXCVBNM~/._+-"); -// assertEquals(test.getId(), "QWERTYUIOPASDFGHJKLZXCVBNM~/._+-"); -// } - - //----------------------------------------------------------------------- - // from(TemporalAccessor) - //----------------------------------------------------------------------- - public void test_factory_from_DateTimeAccessor_zoneId() { - TemporalAccessor mock = new TemporalAccessor() { - @Override - public boolean isSupported(TemporalField field) { - return false; - } - - @Override - public long getLong(TemporalField field) { - throw new DateTimeException("Mock"); - } - - @Override - public R query(TemporalQuery query) { - if (query == Queries.zoneId()) { - return (R) ZONE_PARIS; - } - return TemporalAccessor.super.query(query); - } - }; - assertEquals(ZoneId.from(mock), ZONE_PARIS); - } - - public void test_factory_from_DateTimeAccessor_offset() { - ZoneOffset offset = ZoneOffset.ofHours(1); - assertEquals(ZoneId.from(offset), offset); - } - - @Test(expectedExceptions=DateTimeException.class) - public void test_factory_from_DateTimeAccessor_invalid_noDerive() { - ZoneId.from(LocalTime.of(12, 30)); - } - - @Test(expectedExceptions=NullPointerException.class) - public void test_factory_from_DateTimeAccessor_null() { - ZoneId.from((TemporalAccessor) null); - } - //----------------------------------------------------------------------- // Europe/London //----------------------------------------------------------------------- @@ -998,53 +701,6 @@ public class TestZoneId extends AbstractTest { assertEquals(test.getRules().isFixedOffset(), true); } - //----------------------------------------------------------------------- - // equals() / hashCode() - //----------------------------------------------------------------------- - public void test_equals() { - ZoneId test1 = ZoneId.of("Europe/London"); - ZoneId test2 = ZoneId.of("Europe/Paris"); - ZoneId test2b = ZoneId.of("Europe/Paris"); - assertEquals(test1.equals(test2), false); - assertEquals(test2.equals(test1), false); - - assertEquals(test1.equals(test1), true); - assertEquals(test2.equals(test2), true); - assertEquals(test2.equals(test2b), true); - - assertEquals(test1.hashCode() == test1.hashCode(), true); - assertEquals(test2.hashCode() == test2.hashCode(), true); - assertEquals(test2.hashCode() == test2b.hashCode(), true); - } - - public void test_equals_null() { - assertEquals(ZoneId.of("Europe/London").equals(null), false); - } - - public void test_equals_notTimeZone() { - assertEquals(ZoneId.of("Europe/London").equals("Europe/London"), false); - } - - //----------------------------------------------------------------------- - // toString() - //----------------------------------------------------------------------- - @DataProvider(name="ToString") - Object[][] data_toString() { - return new Object[][] { - {"Europe/London", "Europe/London"}, - {"Europe/Paris", "Europe/Paris"}, - {"Europe/Berlin", "Europe/Berlin"}, - {"UTC", "Z"}, - {"UTC+01:00", "+01:00"}, - }; - } - - @Test(dataProvider="ToString") - public void test_toString(String id, String expected) { - ZoneId test = ZoneId.of(id); - assertEquals(test.toString(), expected); - } - //----------------------------------------------------------------------- //----------------------------------------------------------------------- //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/test/java/time/chrono/TestExampleCode.java b/jdk/test/java/time/test/java/time/chrono/TestExampleCode.java new file mode 100644 index 00000000000..bfdec45c198 --- /dev/null +++ b/jdk/test/java/time/test/java/time/chrono/TestExampleCode.java @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2012, 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +/* + * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package test.java.time.chrono; + +import java.time.LocalTime; +import java.time.chrono.HijrahDate; +import java.time.chrono.ThaiBuddhistDate; +import java.time.chrono.ChronoLocalDateTime; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.Chronology; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; +import java.util.Set; + +import org.testng.annotations.Test; + +/** + * Test case verify that the example code in the package-info.java compiles + * and runs. + */ +public class TestExampleCode { + + @Test + public void test_chronoPackageExample() { + // Print the Thai Buddhist date + ChronoLocalDate now1 = Chronology.of("ThaiBuddhist").dateNow(); + int day = now1.get(ChronoField.DAY_OF_MONTH); + int dow = now1.get(ChronoField.DAY_OF_WEEK); + int month = now1.get(ChronoField.MONTH_OF_YEAR); + int year = now1.get(ChronoField.YEAR); + System.out.printf(" Today is %s %s %d-%s-%d%n", now1.getChronology().getId(), + dow, day, month, year); + + // Enumerate the list of available calendars and print today for each + Set chronos = Chronology.getAvailableChronologies(); + for (Chronology chrono : chronos) { + ChronoLocalDate date = chrono.dateNow(); + System.out.printf(" %20s: %s%n", chrono.getId(), date.toString()); + } + + // Print today's date and the last day of the year for the Thai Buddhist Calendar. + ChronoLocalDate first = now1 + .with(ChronoField.DAY_OF_MONTH, 1) + .with(ChronoField.MONTH_OF_YEAR, 1); + ChronoLocalDate last = first + .plus(1, ChronoUnit.YEARS) + .minus(1, ChronoUnit.DAYS); + System.out.printf(" %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(), + first, last); + } + + @Test + public void test_calendarPackageExample() { + + // Enumerate the list of available calendars and print today for each + Set chronos = Chronology.getAvailableChronologies(); + for (Chronology chrono : chronos) { + ChronoLocalDate date = chrono.dateNow(); + System.out.printf(" %20s: %s%n", chrono.getId(), date.toString()); + } + + // Print the Thai Buddhist date + ThaiBuddhistDate now1 = ThaiBuddhistDate.now(); + int day = now1.get(ChronoField.DAY_OF_MONTH); + int dow = now1.get(ChronoField.DAY_OF_WEEK); + int month = now1.get(ChronoField.MONTH_OF_YEAR); + int year = now1.get(ChronoField.YEAR); + System.out.printf(" Today is %s %s %d-%s-%d%n", now1.getChronology().getId(), + dow, day, month, year); + + // Print today's date and the last day of the year for the Thai Buddhist Calendar. + ThaiBuddhistDate first = now1 + .with(ChronoField.DAY_OF_MONTH, 1) + .with(ChronoField.MONTH_OF_YEAR, 1); + ThaiBuddhistDate last = first + .plus(1, ChronoUnit.YEARS) + .minus(1, ChronoUnit.DAYS); + System.out.printf(" %s: 1st of year: %s; end of year: %s%n", last.getChronology().getId(), + first, last); + } + + @Test + public void test_library() { + HijrahDate date = HijrahDate.now(); + HijrahDate next = next(date); + ChronoLocalDateTime noonTomorrow = tomorrowNoon(date); + System.out.printf(" now: %s, noon tomorrow: %s%n", date, noonTomorrow); + } + + /** + * Simple function based on a date, returning a ChronoDate of the same type. + * @param a parameterized ChronoLocalDate + * @param date a specific date extending ChronoLocalDate + * @return a new date in the same chronology. + */ + private > D next(D date) { + return date.plus(1, ChronoUnit.DAYS); + } + + /** + * Simple function based on a date, returning a ChronoLocalDateTime of the + * same chronology. + * @param a parameterized ChronoLocalDate + * @param date a specific date extending ChronoLocalDate + * @return a [@code ChronoLocalDateTime} using the change chronology. + */ + private > ChronoLocalDateTime tomorrowNoon(D date) { + return date.plus(1, ChronoUnit.DAYS).atTime(LocalTime.of(12, 0)); + } +} diff --git a/jdk/test/java/time/test/java/time/temporal/TestISOChronoImpl.java b/jdk/test/java/time/test/java/time/chrono/TestIsoChronoImpl.java similarity index 94% rename from jdk/test/java/time/test/java/time/temporal/TestISOChronoImpl.java rename to jdk/test/java/time/test/java/time/chrono/TestIsoChronoImpl.java index 9fc01553202..1e66574a4a8 100644 --- a/jdk/test/java/time/test/java/time/temporal/TestISOChronoImpl.java +++ b/jdk/test/java/time/test/java/time/chrono/TestIsoChronoImpl.java @@ -54,7 +54,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package test.java.time.temporal; +package test.java.time.chrono; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; @@ -69,10 +69,10 @@ import java.util.TimeZone; import java.time.DayOfWeek; import java.time.LocalDate; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.IsoChronology; import java.time.temporal.ChronoUnit; -import java.time.temporal.ISOChrono; import java.time.temporal.WeekFields; -import java.time.temporal.ChronoLocalDate; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -81,7 +81,7 @@ import org.testng.annotations.Test; * Test. */ @Test -public class TestISOChronoImpl { +public class TestIsoChronoImpl { @DataProvider(name = "RangeVersusCalendar") Object[][] provider_rangeVersusCalendar() { @@ -95,10 +95,10 @@ public class TestISOChronoImpl { // Verify ISO Calendar matches java.util.Calendar for range //----------------------------------------------------------------------- @Test(groups = {"implementation"}, dataProvider = "RangeVersusCalendar") - public void test_ISOChrono_vsCalendar(LocalDate isoStartDate, LocalDate isoEndDate) { + public void test_IsoChrono_vsCalendar(LocalDate isoStartDate, LocalDate isoEndDate) { GregorianCalendar cal = new GregorianCalendar(); assertEquals(cal.getCalendarType(), "gregory", "Unexpected calendar type"); - ChronoLocalDate isoDate = ISOChrono.INSTANCE.date(isoStartDate); + LocalDate isoDate = IsoChronology.INSTANCE.date(isoStartDate); cal.setTimeZone(TimeZone.getTimeZone("GMT+00")); cal.set(Calendar.YEAR, isoDate.get(YEAR)); @@ -120,10 +120,10 @@ public class TestISOChronoImpl { // DayOfWeek, WeekOfMonth, WeekOfYear for range //----------------------------------------------------------------------- @Test(groups = {"implementation"}, dataProvider = "RangeVersusCalendar") - public void test_DayOfWeek_ISOChrono_vsCalendar(LocalDate isoStartDate, LocalDate isoEndDate) { + public void test_DayOfWeek_IsoChronology_vsCalendar(LocalDate isoStartDate, LocalDate isoEndDate) { GregorianCalendar cal = new GregorianCalendar(); assertEquals(cal.getCalendarType(), "gregory", "Unexpected calendar type"); - ChronoLocalDate isoDate = ISOChrono.INSTANCE.date(isoStartDate); + LocalDate isoDate = IsoChronology.INSTANCE.date(isoStartDate); for (DayOfWeek firstDayOfWeek : DayOfWeek.values()) { for (int minDays = 1; minDays <= 7; minDays++) { diff --git a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatters.java b/jdk/test/java/time/test/java/time/chrono/TestServiceLoader.java similarity index 74% rename from jdk/test/java/time/test/java/time/format/TestDateTimeFormatters.java rename to jdk/test/java/time/test/java/time/chrono/TestServiceLoader.java index 5e7ab3ef7cb..99304a74cd5 100644 --- a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatters.java +++ b/jdk/test/java/time/test/java/time/chrono/TestServiceLoader.java @@ -1,5 +1,4 @@ /* - * Copyright (c) 2012, 2013, 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 @@ -27,7 +26,7 @@ * However, the following notice accompanied the original version of this * file: * - * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos + * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos * * All rights reserved. * @@ -57,37 +56,31 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package test.java.time.format; +package test.java.time.chrono; -import java.time.format.*; +import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Modifier; -import java.util.Collections; - -import org.testng.annotations.BeforeMethod; +import java.util.HashMap; +import java.util.Map; +import java.util.ServiceLoader; +import java.time.chrono.Chronology; import org.testng.annotations.Test; /** - * Test DateTimeFormatters. + * Tests that a custom Chronology is available via the ServiceLoader. + * The CopticChronology is configured via META-INF/services/java.time.chrono.Chronology. */ @Test -public class TestDateTimeFormatters { +public class TestServiceLoader { - @BeforeMethod - public void setUp() { - } - - @Test(groups={"implementation"}) - @SuppressWarnings("rawtypes") - public void test_constructor() throws Exception { - for (Constructor constructor : DateTimeFormatters.class.getDeclaredConstructors()) { - assertTrue(Modifier.isPrivate(constructor.getModifiers())); - //constructor.setAccessible(true); - //constructor.newInstance(Collections.nCopies(constructor.getParameterTypes().length, null).toArray()); + @Test(groups="implementation") + public void test_copticServiceLoader() { + Map chronos = new HashMap<>(); + ServiceLoader loader = ServiceLoader.load(Chronology.class, null); + for (Chronology chrono : loader) { + chronos.put(chrono.getId(), chrono); } + assertNotNull(chronos.get("Coptic"), "CopticChronology not found"); } } diff --git a/jdk/test/java/time/test/java/time/format/TestCharLiteralParser.java b/jdk/test/java/time/test/java/time/format/TestCharLiteralParser.java index c2fe6290a5d..ff73696c3e5 100644 --- a/jdk/test/java/time/test/java/time/format/TestCharLiteralParser.java +++ b/jdk/test/java/time/test/java/time/format/TestCharLiteralParser.java @@ -59,11 +59,15 @@ */ package test.java.time.format; +import static java.time.temporal.ChronoField.YEAR; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; -import java.time.format.DateTimeBuilder; import java.text.ParsePosition; +import java.time.temporal.Queries; +import java.time.temporal.TemporalAccessor; + import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -101,13 +105,14 @@ public class TestCharLiteralParser extends AbstractTestPrinterParser { String text, int pos, int expectedPos) { setCaseSensitive(caseSensitive); ParsePosition ppos = new ParsePosition(pos); - DateTimeBuilder result = - getFormatter(c).parseToBuilder(text, ppos); + TemporalAccessor parsed = getFormatter(c).parseUnresolved(text, ppos); if (ppos.getErrorIndex() != -1) { assertEquals(ppos.getIndex(), expectedPos); } else { assertEquals(ppos.getIndex(), expectedPos); - assertEquals(result.getCalendricalList().size(), 0); + assertEquals(parsed.isSupported(YEAR), false); + assertEquals(parsed.query(Queries.chronology()), null); + assertEquals(parsed.query(Queries.zoneId()), null); } } @@ -123,9 +128,9 @@ public class TestCharLiteralParser extends AbstractTestPrinterParser { @Test(dataProvider="error") public void test_parse_error(char c, String text, int pos, Class expected) { try { - DateTimeBuilder result = - getFormatter(c).parseToBuilder(text, new ParsePosition(pos)); - assertTrue(false); + ParsePosition ppos = new ParsePosition(pos); + getFormatter(c).parseUnresolved(text, ppos); + fail(); } catch (RuntimeException ex) { assertTrue(expected.isInstance(ex)); } diff --git a/jdk/test/java/time/test/java/time/format/TestCharLiteralPrinter.java b/jdk/test/java/time/test/java/time/format/TestCharLiteralPrinter.java index f2c1f7d65b1..780c04db8cb 100644 --- a/jdk/test/java/time/test/java/time/format/TestCharLiteralPrinter.java +++ b/jdk/test/java/time/test/java/time/format/TestCharLiteralPrinter.java @@ -74,18 +74,18 @@ public class TestCharLiteralPrinter extends AbstractTestPrinterParser { //----------------------------------------------------------------------- public void test_print_emptyCalendrical() throws Exception { buf.append("EXISTING"); - getFormatter('a').printTo(EMPTY_DTA, buf); + getFormatter('a').formatTo(EMPTY_DTA, buf); assertEquals(buf.toString(), "EXISTINGa"); } public void test_print_dateTime() throws Exception { buf.append("EXISTING"); - getFormatter('a').printTo(dta, buf); + getFormatter('a').formatTo(dta, buf); assertEquals(buf.toString(), "EXISTINGa"); } public void test_print_emptyAppendable() throws Exception { - getFormatter('a').printTo(dta, buf); + getFormatter('a').formatTo(dta, buf); assertEquals(buf.toString(), "a"); } diff --git a/jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java new file mode 100644 index 00000000000..ec0d16e8fd4 --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeFormatterBuilder.java @@ -0,0 +1,864 @@ +/* + * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of JSR-310 nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package test.java.time.format; + +import static java.time.temporal.ChronoField.DAY_OF_MONTH; +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; +import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.YEAR; +import static org.testng.Assert.assertEquals; + +import java.text.ParsePosition; +import java.time.LocalDate; +import java.time.YearMonth; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.SignStyle; +import java.time.format.TextStyle; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test DateTimeFormatterBuilder. + */ +@Test +public class TestDateTimeFormatterBuilder { + + private DateTimeFormatterBuilder builder; + + @BeforeMethod + public void setUp() { + builder = new DateTimeFormatterBuilder(); + } + + //----------------------------------------------------------------------- + @Test + public void test_toFormatter_empty() throws Exception { + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), ""); + } + + //----------------------------------------------------------------------- + @Test + public void test_parseCaseSensitive() throws Exception { + builder.parseCaseSensitive(); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "ParseCaseSensitive(true)"); + } + + @Test + public void test_parseCaseInsensitive() throws Exception { + builder.parseCaseInsensitive(); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "ParseCaseSensitive(false)"); + } + + //----------------------------------------------------------------------- + @Test + public void test_parseStrict() throws Exception { + builder.parseStrict(); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "ParseStrict(true)"); + } + + @Test + public void test_parseLenient() throws Exception { + builder.parseLenient(); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "ParseStrict(false)"); + } + + //----------------------------------------------------------------------- + @Test + public void test_appendValue_1arg() throws Exception { + builder.appendValue(DAY_OF_MONTH); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(DayOfMonth)"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendValue_1arg_null() throws Exception { + builder.appendValue(null); + } + + //----------------------------------------------------------------------- + @Test + public void test_appendValue_2arg() throws Exception { + builder.appendValue(DAY_OF_MONTH, 3); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(DayOfMonth,3)"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendValue_2arg_null() throws Exception { + builder.appendValue(null, 3); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendValue_2arg_widthTooSmall() throws Exception { + builder.appendValue(DAY_OF_MONTH, 0); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendValue_2arg_widthTooBig() throws Exception { + builder.appendValue(DAY_OF_MONTH, 20); + } + + //----------------------------------------------------------------------- + @Test + public void test_appendValue_3arg() throws Exception { + builder.appendValue(DAY_OF_MONTH, 2, 3, SignStyle.NORMAL); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(DayOfMonth,2,3,NORMAL)"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendValue_3arg_nullField() throws Exception { + builder.appendValue(null, 2, 3, SignStyle.NORMAL); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendValue_3arg_minWidthTooSmall() throws Exception { + builder.appendValue(DAY_OF_MONTH, 0, 2, SignStyle.NORMAL); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendValue_3arg_minWidthTooBig() throws Exception { + builder.appendValue(DAY_OF_MONTH, 20, 2, SignStyle.NORMAL); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendValue_3arg_maxWidthTooSmall() throws Exception { + builder.appendValue(DAY_OF_MONTH, 2, 0, SignStyle.NORMAL); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendValue_3arg_maxWidthTooBig() throws Exception { + builder.appendValue(DAY_OF_MONTH, 2, 20, SignStyle.NORMAL); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendValue_3arg_maxWidthMinWidth() throws Exception { + builder.appendValue(DAY_OF_MONTH, 4, 2, SignStyle.NORMAL); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendValue_3arg_nullSignStyle() throws Exception { + builder.appendValue(DAY_OF_MONTH, 2, 3, null); + } + + //----------------------------------------------------------------------- + @Test + public void test_appendValue_subsequent2_parse3() throws Exception { + builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)"); + TemporalAccessor parsed = f.parseUnresolved("123", new ParsePosition(0)); + assertEquals(parsed.getLong(MONTH_OF_YEAR), 1L); + assertEquals(parsed.getLong(DAY_OF_MONTH), 23L); + } + + @Test + public void test_appendValue_subsequent2_parse4() throws Exception { + builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)"); + TemporalAccessor parsed = f.parseUnresolved("0123", new ParsePosition(0)); + assertEquals(parsed.getLong(MONTH_OF_YEAR), 1L); + assertEquals(parsed.getLong(DAY_OF_MONTH), 23L); + } + + @Test + public void test_appendValue_subsequent2_parse5() throws Exception { + builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValue(DAY_OF_MONTH, 2).appendLiteral('4'); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)Value(DayOfMonth,2)'4'"); + TemporalAccessor parsed = f.parseUnresolved("01234", new ParsePosition(0)); + assertEquals(parsed.getLong(MONTH_OF_YEAR), 1L); + assertEquals(parsed.getLong(DAY_OF_MONTH), 23L); + } + + @Test + public void test_appendValue_subsequent3_parse6() throws Exception { + builder + .appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD) + .appendValue(MONTH_OF_YEAR, 2) + .appendValue(DAY_OF_MONTH, 2); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(Year,4,10,EXCEEDS_PAD)Value(MonthOfYear,2)Value(DayOfMonth,2)"); + TemporalAccessor parsed = f.parseUnresolved("20090630", new ParsePosition(0)); + assertEquals(parsed.getLong(YEAR), 2009L); + assertEquals(parsed.getLong(MONTH_OF_YEAR), 6L); + assertEquals(parsed.getLong(DAY_OF_MONTH), 30L); + } + + //----------------------------------------------------------------------- + @Test(expectedExceptions=NullPointerException.class) + public void test_appendValueReduced_null() throws Exception { + builder.appendValueReduced(null, 2, 2000); + } + + @Test + public void test_appendValueReduced() throws Exception { + builder.appendValueReduced(YEAR, 2, 2000); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "ReducedValue(Year,2,2000)"); + TemporalAccessor parsed = f.parseUnresolved("12", new ParsePosition(0)); + assertEquals(parsed.getLong(YEAR), 2012L); + } + + @Test + public void test_appendValueReduced_subsequent_parse() throws Exception { + builder.appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL).appendValueReduced(YEAR, 2, 2000); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(MonthOfYear,1,2,NORMAL)ReducedValue(Year,2,2000)"); + TemporalAccessor parsed = f.parseUnresolved("123", new ParsePosition(0)); + assertEquals(parsed.getLong(MONTH_OF_YEAR), 1L); + assertEquals(parsed.getLong(YEAR), 2023L); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @Test + public void test_appendFraction_4arg() throws Exception { + builder.appendFraction(MINUTE_OF_HOUR, 1, 9, false); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Fraction(MinuteOfHour,1,9)"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendFraction_4arg_nullRule() throws Exception { + builder.appendFraction(null, 1, 9, false); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendFraction_4arg_invalidRuleNotFixedSet() throws Exception { + builder.appendFraction(DAY_OF_MONTH, 1, 9, false); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendFraction_4arg_minTooSmall() throws Exception { + builder.appendFraction(MINUTE_OF_HOUR, -1, 9, false); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendFraction_4arg_minTooBig() throws Exception { + builder.appendFraction(MINUTE_OF_HOUR, 10, 9, false); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendFraction_4arg_maxTooSmall() throws Exception { + builder.appendFraction(MINUTE_OF_HOUR, 0, -1, false); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendFraction_4arg_maxTooBig() throws Exception { + builder.appendFraction(MINUTE_OF_HOUR, 1, 10, false); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_appendFraction_4arg_maxWidthMinWidth() throws Exception { + builder.appendFraction(MINUTE_OF_HOUR, 9, 3, false); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @Test + public void test_appendText_1arg() throws Exception { + builder.appendText(MONTH_OF_YEAR); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Text(MonthOfYear)"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendText_1arg_null() throws Exception { + builder.appendText(null); + } + + //----------------------------------------------------------------------- + @Test + public void test_appendText_2arg() throws Exception { + builder.appendText(MONTH_OF_YEAR, TextStyle.SHORT); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Text(MonthOfYear,SHORT)"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendText_2arg_nullRule() throws Exception { + builder.appendText(null, TextStyle.SHORT); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendText_2arg_nullStyle() throws Exception { + builder.appendText(MONTH_OF_YEAR, (TextStyle) null); + } + + //----------------------------------------------------------------------- + @Test + public void test_appendTextMap() throws Exception { + Map map = new HashMap<>(); + map.put(1L, "JNY"); + map.put(2L, "FBY"); + map.put(3L, "MCH"); + map.put(4L, "APL"); + map.put(5L, "MAY"); + map.put(6L, "JUN"); + map.put(7L, "JLY"); + map.put(8L, "AGT"); + map.put(9L, "SPT"); + map.put(10L, "OBR"); + map.put(11L, "NVR"); + map.put(12L, "DBR"); + builder.appendText(MONTH_OF_YEAR, map); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Text(MonthOfYear)"); // TODO: toString should be different? + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendTextMap_nullRule() throws Exception { + builder.appendText(null, new HashMap()); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendTextMap_nullStyle() throws Exception { + builder.appendText(MONTH_OF_YEAR, (Map) null); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @Test + public void test_appendOffsetId() throws Exception { + builder.appendOffsetId(); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Offset(+HH:MM:ss,'Z')"); + } + + @DataProvider(name="offsetPatterns") + Object[][] data_offsetPatterns() { + return new Object[][] { + {"+HH", 2, 0, 0, "+02"}, + {"+HH", -2, 0, 0, "-02"}, + {"+HH", 2, 30, 0, "+02"}, + {"+HH", 2, 0, 45, "+02"}, + {"+HH", 2, 30, 45, "+02"}, + + {"+HHMM", 2, 0, 0, "+0200"}, + {"+HHMM", -2, 0, 0, "-0200"}, + {"+HHMM", 2, 30, 0, "+0230"}, + {"+HHMM", 2, 0, 45, "+0200"}, + {"+HHMM", 2, 30, 45, "+0230"}, + + {"+HH:MM", 2, 0, 0, "+02:00"}, + {"+HH:MM", -2, 0, 0, "-02:00"}, + {"+HH:MM", 2, 30, 0, "+02:30"}, + {"+HH:MM", 2, 0, 45, "+02:00"}, + {"+HH:MM", 2, 30, 45, "+02:30"}, + + {"+HHMMss", 2, 0, 0, "+0200"}, + {"+HHMMss", -2, 0, 0, "-0200"}, + {"+HHMMss", 2, 30, 0, "+0230"}, + {"+HHMMss", 2, 0, 45, "+020045"}, + {"+HHMMss", 2, 30, 45, "+023045"}, + + {"+HH:MM:ss", 2, 0, 0, "+02:00"}, + {"+HH:MM:ss", -2, 0, 0, "-02:00"}, + {"+HH:MM:ss", 2, 30, 0, "+02:30"}, + {"+HH:MM:ss", 2, 0, 45, "+02:00:45"}, + {"+HH:MM:ss", 2, 30, 45, "+02:30:45"}, + + {"+HHMMSS", 2, 0, 0, "+020000"}, + {"+HHMMSS", -2, 0, 0, "-020000"}, + {"+HHMMSS", 2, 30, 0, "+023000"}, + {"+HHMMSS", 2, 0, 45, "+020045"}, + {"+HHMMSS", 2, 30, 45, "+023045"}, + + {"+HH:MM:SS", 2, 0, 0, "+02:00:00"}, + {"+HH:MM:SS", -2, 0, 0, "-02:00:00"}, + {"+HH:MM:SS", 2, 30, 0, "+02:30:00"}, + {"+HH:MM:SS", 2, 0, 45, "+02:00:45"}, + {"+HH:MM:SS", 2, 30, 45, "+02:30:45"}, + }; + } + + @Test(dataProvider="offsetPatterns") + public void test_appendOffset_format(String pattern, int h, int m, int s, String expected) throws Exception { + builder.appendOffset(pattern, "Z"); + DateTimeFormatter f = builder.toFormatter(); + ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(h, m, s); + assertEquals(f.format(offset), expected); + } + + @Test(dataProvider="offsetPatterns") + public void test_appendOffset_parse(String pattern, int h, int m, int s, String expected) throws Exception { + builder.appendOffset(pattern, "Z"); + DateTimeFormatter f = builder.toFormatter(); + ZoneOffset offset = ZoneOffset.ofHoursMinutesSeconds(h, m, s); + ZoneOffset parsed = f.parse(expected, ZoneOffset::from); + assertEquals(f.format(parsed), expected); + } + + @DataProvider(name="badOffsetPatterns") + Object[][] data_badOffsetPatterns() { + return new Object[][] { + {"HH"}, + {"HHMM"}, + {"HH:MM"}, + {"HHMMss"}, + {"HH:MM:ss"}, + {"HHMMSS"}, + {"HH:MM:SS"}, + {"+H"}, + {"+HMM"}, + {"+HHM"}, + {"+A"}, + }; + } + + @Test(dataProvider="badOffsetPatterns", expectedExceptions=IllegalArgumentException.class) + public void test_appendOffset_badPattern(String pattern) throws Exception { + builder.appendOffset(pattern, "Z"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendOffset_3arg_nullText() throws Exception { + builder.appendOffset("+HH:MM", null); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendOffset_3arg_nullPattern() throws Exception { + builder.appendOffset(null, "Z"); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @Test + public void test_appendZoneId() throws Exception { + builder.appendZoneId(); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "ZoneId()"); + } + + @Test + public void test_appendZoneText_1arg() throws Exception { + builder.appendZoneText(TextStyle.FULL); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "ZoneText(FULL)"); + } + + @Test(expectedExceptions=NullPointerException.class) + public void test_appendZoneText_1arg_nullText() throws Exception { + builder.appendZoneText(null); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @Test + public void test_padNext_1arg() { + builder.appendValue(MONTH_OF_YEAR).appendLiteral(':').padNext(2).appendValue(DAY_OF_MONTH); + assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2: 1"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_padNext_1arg_invalidWidth() throws Exception { + builder.padNext(0); + } + + //----------------------------------------------------------------------- + @Test + public void test_padNext_2arg_dash() throws Exception { + builder.appendValue(MONTH_OF_YEAR).appendLiteral(':').padNext(2, '-').appendValue(DAY_OF_MONTH); + assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2:-1"); + } + + @Test(expectedExceptions=IllegalArgumentException.class) + public void test_padNext_2arg_invalidWidth() throws Exception { + builder.padNext(0, '-'); + } + + //----------------------------------------------------------------------- + @Test + public void test_padOptional() throws Exception { + builder.appendValue(MONTH_OF_YEAR).appendLiteral(':') + .padNext(5).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd() + .appendLiteral(':').appendValue(YEAR); + assertEquals(builder.toFormatter().format(LocalDate.of(2013, 2, 1)), "2: 1:2013"); + assertEquals(builder.toFormatter().format(YearMonth.of(2013, 2)), "2: :2013"); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @Test + public void test_optionalStart_noEnd() throws Exception { + builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).appendValue(DAY_OF_WEEK); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)Value(DayOfWeek)]"); + } + + @Test + public void test_optionalStart2_noEnd() throws Exception { + builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).optionalStart().appendValue(DAY_OF_WEEK); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)[Value(DayOfWeek)]]"); + } + + @Test + public void test_optionalStart_doubleStart() throws Exception { + builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]"); + } + + //----------------------------------------------------------------------- + @Test + public void test_optionalEnd() throws Exception { + builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH).optionalEnd().appendValue(DAY_OF_WEEK); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)]Value(DayOfWeek)"); + } + + @Test + public void test_optionalEnd2() throws Exception { + builder.appendValue(MONTH_OF_YEAR).optionalStart().appendValue(DAY_OF_MONTH) + .optionalStart().appendValue(DAY_OF_WEEK).optionalEnd().appendValue(DAY_OF_MONTH).optionalEnd(); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(MonthOfYear)[Value(DayOfMonth)[Value(DayOfWeek)]Value(DayOfMonth)]"); + } + + @Test + public void test_optionalEnd_doubleStartSingleEnd() throws Exception { + builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH).optionalEnd(); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]"); + } + + @Test + public void test_optionalEnd_doubleStartDoubleEnd() throws Exception { + builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalStart().appendValue(DAY_OF_MONTH).optionalEnd().optionalEnd(); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(MonthOfYear)[[Value(DayOfMonth)]]"); + } + + @Test + public void test_optionalStartEnd_immediateStartEnd() throws Exception { + builder.appendValue(MONTH_OF_YEAR).optionalStart().optionalEnd().appendValue(DAY_OF_MONTH); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), "Value(MonthOfYear)Value(DayOfMonth)"); + } + + @Test(expectedExceptions=IllegalStateException.class) + public void test_optionalEnd_noStart() throws Exception { + builder.optionalEnd(); + } + + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + //----------------------------------------------------------------------- + @DataProvider(name="validPatterns") + Object[][] dataValid() { + return new Object[][] { + {"'a'", "'a'"}, + {"''", "''"}, + {"'!'", "'!'"}, + {"!", "'!'"}, + + {"'hello_people,][)('", "'hello_people,][)('"}, + {"'hi'", "'hi'"}, + {"'yyyy'", "'yyyy'"}, + {"''''", "''"}, + {"'o''clock'", "'o''clock'"}, + + {"G", "Text(Era,SHORT)"}, + {"GG", "Text(Era,SHORT)"}, + {"GGG", "Text(Era,SHORT)"}, + {"GGGG", "Text(Era)"}, + {"GGGGG", "Text(Era,NARROW)"}, + + {"y", "Value(Year)"}, + {"yy", "ReducedValue(Year,2,2000)"}, + {"yyy", "Value(Year,3,19,NORMAL)"}, + {"yyyy", "Value(Year,4,19,EXCEEDS_PAD)"}, + {"yyyyy", "Value(Year,5,19,EXCEEDS_PAD)"}, + +// {"Y", "Value(WeekBasedYear)"}, +// {"YY", "ReducedValue(WeekBasedYear,2,2000)"}, +// {"YYY", "Value(WeekBasedYear,3,19,NORMAL)"}, +// {"YYYY", "Value(WeekBasedYear,4,19,EXCEEDS_PAD)"}, +// {"YYYYY", "Value(WeekBasedYear,5,19,EXCEEDS_PAD)"}, + + {"M", "Value(MonthOfYear)"}, + {"MM", "Value(MonthOfYear,2)"}, + {"MMM", "Text(MonthOfYear,SHORT)"}, + {"MMMM", "Text(MonthOfYear)"}, + {"MMMMM", "Text(MonthOfYear,NARROW)"}, + + {"D", "Value(DayOfYear)"}, + {"DD", "Value(DayOfYear,2)"}, + {"DDD", "Value(DayOfYear,3)"}, + + {"d", "Value(DayOfMonth)"}, + {"dd", "Value(DayOfMonth,2)"}, + {"ddd", "Value(DayOfMonth,3)"}, + + {"F", "Value(AlignedWeekOfMonth)"}, + {"FF", "Value(AlignedWeekOfMonth,2)"}, + {"FFF", "Value(AlignedWeekOfMonth,3)"}, + + {"Q", "Value(QuarterOfYear)"}, + {"QQ", "Value(QuarterOfYear,2)"}, + {"QQQ", "Text(QuarterOfYear,SHORT)"}, + {"QQQQ", "Text(QuarterOfYear)"}, + {"QQQQQ", "Text(QuarterOfYear,NARROW)"}, + + {"E", "Value(DayOfWeek)"}, + {"EE", "Value(DayOfWeek,2)"}, + {"EEE", "Text(DayOfWeek,SHORT)"}, + {"EEEE", "Text(DayOfWeek)"}, + {"EEEEE", "Text(DayOfWeek,NARROW)"}, + + {"a", "Text(AmPmOfDay,SHORT)"}, + {"aa", "Text(AmPmOfDay,SHORT)"}, + {"aaa", "Text(AmPmOfDay,SHORT)"}, + {"aaaa", "Text(AmPmOfDay)"}, + {"aaaaa", "Text(AmPmOfDay,NARROW)"}, + + {"H", "Value(HourOfDay)"}, + {"HH", "Value(HourOfDay,2)"}, + {"HHH", "Value(HourOfDay,3)"}, + + {"K", "Value(HourOfAmPm)"}, + {"KK", "Value(HourOfAmPm,2)"}, + {"KKK", "Value(HourOfAmPm,3)"}, + + {"k", "Value(ClockHourOfDay)"}, + {"kk", "Value(ClockHourOfDay,2)"}, + {"kkk", "Value(ClockHourOfDay,3)"}, + + {"h", "Value(ClockHourOfAmPm)"}, + {"hh", "Value(ClockHourOfAmPm,2)"}, + {"hhh", "Value(ClockHourOfAmPm,3)"}, + + {"m", "Value(MinuteOfHour)"}, + {"mm", "Value(MinuteOfHour,2)"}, + {"mmm", "Value(MinuteOfHour,3)"}, + + {"s", "Value(SecondOfMinute)"}, + {"ss", "Value(SecondOfMinute,2)"}, + {"sss", "Value(SecondOfMinute,3)"}, + + {"S", "Fraction(NanoOfSecond,1,1)"}, + {"SS", "Fraction(NanoOfSecond,2,2)"}, + {"SSS", "Fraction(NanoOfSecond,3,3)"}, + {"SSSSSSSSS", "Fraction(NanoOfSecond,9,9)"}, + + {"A", "Value(MilliOfDay)"}, + {"AA", "Value(MilliOfDay,2)"}, + {"AAA", "Value(MilliOfDay,3)"}, + + {"n", "Value(NanoOfSecond)"}, + {"nn", "Value(NanoOfSecond,2)"}, + {"nnn", "Value(NanoOfSecond,3)"}, + + {"N", "Value(NanoOfDay)"}, + {"NN", "Value(NanoOfDay,2)"}, + {"NNN", "Value(NanoOfDay,3)"}, + + {"z", "ZoneText(SHORT)"}, + {"zz", "ZoneText(SHORT)"}, + {"zzz", "ZoneText(SHORT)"}, + {"zzzz", "ZoneText(FULL)"}, + + {"VV", "ZoneId()"}, + + {"Z", "Offset(+HHMM,'+0000')"}, // SimpleDateFormat + {"ZZ", "Offset(+HHMM,'+0000')"}, // SimpleDateFormat + {"ZZZ", "Offset(+HHMM,'+0000')"}, // SimpleDateFormat + + {"X", "Offset(+HHmm,'Z')"}, // LDML/almost SimpleDateFormat + {"XX", "Offset(+HHMM,'Z')"}, // LDML/SimpleDateFormat + {"XXX", "Offset(+HH:MM,'Z')"}, // LDML/SimpleDateFormat + {"XXXX", "Offset(+HHMMss,'Z')"}, // LDML + {"XXXXX", "Offset(+HH:MM:ss,'Z')"}, // LDML + + {"x", "Offset(+HHmm,'+00')"}, // LDML + {"xx", "Offset(+HHMM,'+0000')"}, // LDML + {"xxx", "Offset(+HH:MM,'+00:00')"}, // LDML + {"xxxx", "Offset(+HHMMss,'+0000')"}, // LDML + {"xxxxx", "Offset(+HH:MM:ss,'+00:00')"}, // LDML + + {"ppH", "Pad(Value(HourOfDay),2)"}, + {"pppDD", "Pad(Value(DayOfYear,2),3)"}, + + {"yyyy[-MM[-dd", "Value(Year,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"}, + {"yyyy[-MM[-dd]]", "Value(Year,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)['-'Value(DayOfMonth,2)]]"}, + {"yyyy[-MM[]-dd]", "Value(Year,4,19,EXCEEDS_PAD)['-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)]"}, + + {"yyyy-MM-dd'T'HH:mm:ss.SSS", "Value(Year,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)" + + "'T'Value(HourOfDay,2)':'Value(MinuteOfHour,2)':'Value(SecondOfMinute,2)'.'Fraction(NanoOfSecond,3,3)"}, + + {"e", "WeekBased(e1)"}, + {"w", "WeekBased(w1)"}, + {"W", "WeekBased(W1)"}, + {"WW", "WeekBased(W2)"}, + + }; + } + + @Test(dataProvider="validPatterns", groups={"implementation"}) + public void test_appendPattern_valid(String input, String expected) throws Exception { + builder.appendPattern(input); + DateTimeFormatter f = builder.toFormatter(); + assertEquals(f.toString(), expected); + } + + //----------------------------------------------------------------------- + @DataProvider(name="invalidPatterns") + Object[][] dataInvalid() { + return new Object[][] { + {"'"}, + {"'hello"}, + {"'hel''lo"}, + {"'hello''"}, + {"{"}, + {"}"}, + {"{}"}, + {"]"}, + {"yyyy]"}, + {"yyyy]MM"}, + {"yyyy[MM]]"}, + + {"MMMMMM"}, + {"QQQQQQ"}, + {"EEEEEE"}, + {"aaaaaa"}, + {"ZZZZ"}, + {"XXXXXX"}, + {"zzzzz"}, + {"V"}, + {"VVV"}, + {"VVVV"}, + {"VVVVV"}, + + {"RO"}, + + {"p"}, + {"pp"}, + {"p:"}, + + {"f"}, + {"ff"}, + {"f:"}, + {"fy"}, + {"fa"}, + {"fM"}, + + {"ww"}, + {"ee"}, + {"WWW"}, + }; + } + + @Test(dataProvider="invalidPatterns", expectedExceptions=IllegalArgumentException.class) + public void test_appendPattern_invalid(String input) throws Exception { + try { + builder.appendPattern(input); + } catch (IllegalArgumentException ex) { + throw ex; + } + } + + //----------------------------------------------------------------------- + @DataProvider(name="patternPrint") + Object[][] data_patternPrint() { + return new Object[][] { + {"Q", date(2012, 2, 10), "1"}, + {"QQ", date(2012, 2, 10), "01"}, +// {"QQQ", date(2012, 2, 10), "Q1"}, // TODO: data for quarters? +// {"QQQQ", date(2012, 2, 10), "Q1"}, +// {"QQQQQ", date(2012, 2, 10), "Q1"}, + }; + } + + @Test(dataProvider="patternPrint") + public void test_appendPattern_patternPrint(String input, Temporal temporal, String expected) throws Exception { + DateTimeFormatter f = builder.appendPattern(input).toFormatter(Locale.UK); + String test = f.format(temporal); + assertEquals(test, expected); + } + + private static Temporal date(int y, int m, int d) { + return LocalDate.of(y, m, d); + } + +} diff --git a/jdk/test/java/time/test/java/time/format/TestDateTimePrintException.java b/jdk/test/java/time/test/java/time/format/TestDateTimePrintException.java deleted file mode 100644 index 3a737f33ed2..00000000000 --- a/jdk/test/java/time/test/java/time/format/TestDateTimePrintException.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file: - * - * Copyright (c) 2008-2012, Stephen Colebourne & Michael Nascimento Santos - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of JSR-310 nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package test.java.time.format; - -import java.time.format.*; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; - -import java.io.IOException; - -import org.testng.annotations.Test; - -/** - * Test DateTimePrintException. - */ -@Test -public class TestDateTimePrintException { - - @Test(groups={"implementation"}) - public void test_constructor_StringThrowable_notIOException_same() throws Exception { - IllegalArgumentException iaex = new IllegalArgumentException("INNER"); - DateTimePrintException ex = new DateTimePrintException("TEST", iaex); - assertEquals(ex.getMessage(), "TEST"); - assertSame(ex.getCause(), iaex); - ex.rethrowIOException(); // no effect - } - - @Test(expectedExceptions=IOException.class, groups={"implementation"}) - public void test_constructor_StringThrowable_IOException_same() throws Exception { - IOException ioex = new IOException("INNER"); - DateTimePrintException ex = new DateTimePrintException("TEST", ioex); - assertEquals(ex.getMessage(), "TEST"); - assertSame(ex.getCause(), ioex); - ex.rethrowIOException(); // rethrows - } - -} diff --git a/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java b/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java index ab8cec39822..1d34a2d05f1 100644 --- a/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java +++ b/jdk/test/java/time/test/java/time/format/TestDateTimeTextProvider.java @@ -180,7 +180,7 @@ public class TestDateTimeTextProvider extends AbstractTestPrinterParser { @Test(dataProvider = "Text") public void test_getText(TemporalField field, Number value, TextStyle style, Locale locale, String expected) { DateTimeFormatter fmt = getFormatter(field, style).withLocale(locale); - assertEquals(fmt.print(ZonedDateTime.now().with(field, value.longValue())), expected); + assertEquals(fmt.format(ZonedDateTime.now().with(field, value.longValue())), expected); } } diff --git a/jdk/test/java/time/test/java/time/format/TestFractionPrinterParser.java b/jdk/test/java/time/test/java/time/format/TestFractionPrinterParser.java index 4be3b6cce46..2925c9f7988 100644 --- a/jdk/test/java/time/test/java/time/format/TestFractionPrinterParser.java +++ b/jdk/test/java/time/test/java/time/format/TestFractionPrinterParser.java @@ -59,8 +59,6 @@ */ package test.java.time.format; -import java.time.format.*; - import static java.time.temporal.ChronoField.NANO_OF_SECOND; import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; import static org.testng.Assert.assertEquals; @@ -69,13 +67,13 @@ import static org.testng.Assert.fail; import java.text.ParsePosition; import java.time.DateTimeException; import java.time.LocalTime; -import java.time.format.DateTimeBuilder; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; -import test.java.time.temporal.MockFieldValue; - import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import test.java.time.temporal.MockFieldValue; /** * Test FractionPrinterParser. @@ -92,12 +90,12 @@ public class TestFractionPrinterParser extends AbstractTestPrinterParser { //----------------------------------------------------------------------- @Test(expectedExceptions=DateTimeException.class) public void test_print_emptyCalendrical() throws Exception { - getFormatter(NANO_OF_SECOND, 0, 9, true).printTo(EMPTY_DTA, buf); + getFormatter(NANO_OF_SECOND, 0, 9, true).formatTo(EMPTY_DTA, buf); } public void test_print_append() throws Exception { buf.append("EXISTING"); - getFormatter(NANO_OF_SECOND, 0, 9, true).printTo(LocalTime.of(12, 30, 40, 3), buf); + getFormatter(NANO_OF_SECOND, 0, 9, true).formatTo(LocalTime.of(12, 30, 40, 3), buf); assertEquals(buf.toString(), "EXISTING.000000003"); } @@ -180,7 +178,7 @@ public class TestFractionPrinterParser extends AbstractTestPrinterParser { @Test(dataProvider="Nanos") public void test_print_nanos(int minWidth, int maxWidth, int value, String result) throws Exception { - getFormatter(NANO_OF_SECOND, minWidth, maxWidth, true).printTo(new MockFieldValue(NANO_OF_SECOND, value), buf); + getFormatter(NANO_OF_SECOND, minWidth, maxWidth, true).formatTo(new MockFieldValue(NANO_OF_SECOND, value), buf); if (result == null) { fail("Expected exception"); } @@ -189,7 +187,7 @@ public class TestFractionPrinterParser extends AbstractTestPrinterParser { @Test(dataProvider="Nanos") public void test_print_nanos_noDecimalPoint(int minWidth, int maxWidth, int value, String result) throws Exception { - getFormatter(NANO_OF_SECOND, minWidth, maxWidth, false).printTo(new MockFieldValue(NANO_OF_SECOND, value), buf); + getFormatter(NANO_OF_SECOND, minWidth, maxWidth, false).formatTo(new MockFieldValue(NANO_OF_SECOND, value), buf); if (result == null) { fail("Expected exception"); } @@ -222,7 +220,7 @@ public class TestFractionPrinterParser extends AbstractTestPrinterParser { @Test(dataProvider="Seconds") public void test_print_seconds(int minWidth, int maxWidth, int value, String result) throws Exception { - getFormatter(SECOND_OF_MINUTE, minWidth, maxWidth, true).printTo(new MockFieldValue(SECOND_OF_MINUTE, value), buf); + getFormatter(SECOND_OF_MINUTE, minWidth, maxWidth, true).formatTo(new MockFieldValue(SECOND_OF_MINUTE, value), buf); if (result == null) { fail("Expected exception"); } @@ -231,7 +229,7 @@ public class TestFractionPrinterParser extends AbstractTestPrinterParser { @Test(dataProvider="Seconds") public void test_print_seconds_noDecimalPoint(int minWidth, int maxWidth, int value, String result) throws Exception { - getFormatter(SECOND_OF_MINUTE, minWidth, maxWidth, false).printTo(new MockFieldValue(SECOND_OF_MINUTE, value), buf); + getFormatter(SECOND_OF_MINUTE, minWidth, maxWidth, false).formatTo(new MockFieldValue(SECOND_OF_MINUTE, value), buf); if (result == null) { fail("Expected exception"); } @@ -245,27 +243,27 @@ public class TestFractionPrinterParser extends AbstractTestPrinterParser { public void test_reverseParse(int minWidth, int maxWidth, int value, String result) throws Exception { ParsePosition pos = new ParsePosition(0); int expectedValue = fixParsedValue(maxWidth, value); - DateTimeBuilder dtb = getFormatter(NANO_OF_SECOND, minWidth, maxWidth, true).parseToBuilder(result, pos); + TemporalAccessor parsed = getFormatter(NANO_OF_SECOND, minWidth, maxWidth, true).parseUnresolved(result, pos); assertEquals(pos.getIndex(), result.length()); - assertParsed(dtb, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue); + assertParsed(parsed, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue); } @Test(dataProvider="Nanos") public void test_reverseParse_noDecimalPoint(int minWidth, int maxWidth, int value, String result) throws Exception { ParsePosition pos = new ParsePosition((result.startsWith(".") ? 1 : 0)); - DateTimeBuilder dtb = getFormatter(NANO_OF_SECOND, minWidth, maxWidth, false).parseToBuilder(result, pos); + TemporalAccessor parsed = getFormatter(NANO_OF_SECOND, minWidth, maxWidth, false).parseUnresolved(result, pos); assertEquals(pos.getIndex(), result.length()); int expectedValue = fixParsedValue(maxWidth, value); - assertParsed(dtb, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue); + assertParsed(parsed, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue); } @Test(dataProvider="Nanos") public void test_reverseParse_followedByNonDigit(int minWidth, int maxWidth, int value, String result) throws Exception { ParsePosition pos = new ParsePosition(0); int expectedValue = fixParsedValue(maxWidth, value); - DateTimeBuilder dtb = getFormatter(NANO_OF_SECOND, minWidth, maxWidth, true).parseToBuilder(result + " ", pos); + TemporalAccessor parsed = getFormatter(NANO_OF_SECOND, minWidth, maxWidth, true).parseUnresolved(result + " ", pos); assertEquals(pos.getIndex(), result.length()); - assertParsed(dtb, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue); + assertParsed(parsed, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue); } // @Test(dataProvider="Nanos") @@ -281,9 +279,9 @@ public class TestFractionPrinterParser extends AbstractTestPrinterParser { public void test_reverseParse_preceededByNonDigit(int minWidth, int maxWidth, int value, String result) throws Exception { ParsePosition pos = new ParsePosition(1); int expectedValue = fixParsedValue(maxWidth, value); - DateTimeBuilder dtb = getFormatter(NANO_OF_SECOND, minWidth, maxWidth, true).parseToBuilder(" " + result, pos); + TemporalAccessor parsed = getFormatter(NANO_OF_SECOND, minWidth, maxWidth, true).parseUnresolved(" " + result, pos); assertEquals(pos.getIndex(), result.length() + 1); - assertParsed(dtb, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue); + assertParsed(parsed, NANO_OF_SECOND, value == 0 && minWidth == 0 ? null : (long) expectedValue); } private int fixParsedValue(int maxWidth, int value) { @@ -297,16 +295,17 @@ public class TestFractionPrinterParser extends AbstractTestPrinterParser { @Test(dataProvider="Seconds") public void test_reverseParse_seconds(int minWidth, int maxWidth, int value, String result) throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter(SECOND_OF_MINUTE, minWidth, maxWidth, true).parseToBuilder(result, pos); + TemporalAccessor parsed = getFormatter(SECOND_OF_MINUTE, minWidth, maxWidth, true).parseUnresolved(result, pos); assertEquals(pos.getIndex(), result.length()); - assertParsed(dtb, SECOND_OF_MINUTE, value == 0 && minWidth == 0 ? null : (long) value); + assertParsed(parsed, SECOND_OF_MINUTE, value == 0 && minWidth == 0 ? null : (long) value); } - private void assertParsed(DateTimeBuilder dtb, TemporalField field, Long value) { + private void assertParsed(TemporalAccessor parsed, TemporalField field, Long value) { if (value == null) { - assertEquals(dtb.containsFieldValue(field), false); + assertEquals(parsed.isSupported(field), false); } else { - assertEquals(dtb.getLong(field), (long)value); + assertEquals(parsed.isSupported(field), true); + assertEquals(parsed.getLong(field), (long) value); } } @@ -327,8 +326,9 @@ public class TestFractionPrinterParser extends AbstractTestPrinterParser { @Test(dataProvider = "ParseNothing") public void test_parse_nothing(TemporalField field, int min, int max, boolean decimalPoint, String text, int pos, int expected) { ParsePosition ppos = new ParsePosition(pos); - DateTimeBuilder dtb = getFormatter(field, min, max, decimalPoint).parseToBuilder(text, ppos); + TemporalAccessor parsed = getFormatter(field, min, max, decimalPoint).parseUnresolved(text, ppos); assertEquals(ppos.getErrorIndex(), expected); + assertEquals(parsed, null); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java b/jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java new file mode 100644 index 00000000000..43a603cceae --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/TestNonIsoFormatter.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2013, 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. + */ +package test.java.time.format; + +import java.time.*; +import java.time.chrono.*; +import java.time.format.*; +import java.time.temporal.*; +import java.util.Locale; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; + +/** + * Test DateTimeFormatter with non-ISO chronology. + * + * Strings in test data are all dependent on CLDR data which may change + * in future CLDR releases. + */ +@Test(groups={"implementation"}) +public class TestNonIsoFormatter { + private static final Chronology JAPANESE = JapaneseChronology.INSTANCE; + private static final Chronology HIJRAH = HijrahChronology.INSTANCE; + private static final Chronology MINGUO = MinguoChronology.INSTANCE; + private static final Chronology BUDDHIST = ThaiBuddhistChronology.INSTANCE; + + private static final LocalDate IsoDate = LocalDate.of(2013, 2, 11); + + private static final Locale ARABIC = new Locale("ar"); + private static final Locale thTH = new Locale("th", "TH"); + private static final Locale thTHTH = new Locale("th", "TH", "TH"); + + @BeforeMethod + public void setUp() { + } + + @DataProvider(name="format_data") + Object[][] formatData() { + return new Object[][] { + // Chronology, Locale, ChronoLocalDate, expected string + { JAPANESE, Locale.JAPANESE, JAPANESE.date(IsoDate), + "\u5e73\u621025\u5e742\u670811\u65e5\u6708\u66dc\u65e5" }, // Japanese Heisei 25-02-11 (Mon) + { HIJRAH, ARABIC, HIJRAH.date(IsoDate), + "\u0627\u0644\u0627\u062b\u0646\u064a\u0646\u060c 30 \u0631\u0628\u064a\u0639 " + + "\u0627\u0644\u0623\u0648\u0644 1434" }, // Hijrah AH 1434-03-30 (Mon) + { MINGUO, Locale.TAIWAN, MINGUO.date(IsoDate), + "\u6c11\u570b102\u5e742\u670811\u65e5\u661f\u671f\u4e00" }, // Minguo ROC 102-02-11 (Mon) + { BUDDHIST, thTH, BUDDHIST.date(IsoDate), + "\u0e27\u0e31\u0e19\u0e08\u0e31\u0e19\u0e17\u0e23\u0e4c\u0e17\u0e35\u0e48" + + " 11 \u0e01\u0e38\u0e21\u0e20\u0e32\u0e1e\u0e31\u0e19\u0e18\u0e4c" + + " \u0e1e.\u0e28. 2556" }, // ThaiBuddhist BE 2556-02-11 + // { BUDDHIST, thTHTH, BUDDHIST.date(IsoDate), "" }, // doesn't work + }; + } + + @DataProvider(name="invalid_text") + Object[][] invalidText() { + return new Object[][] { + // TODO: currently fixed Chronology and Locale. + { "\u662d\u548c64\u5e741\u67089\u65e5\u6708\u66dc\u65e5" }, // S64.01.09 (Mon) + { "\u662d\u548c65\u5e741\u67081\u65e5\u6708\u66dc\u65e5" }, // S65.01.01 (Mon) + }; + } + + @Test(dataProvider="format_data") + public void test_formatLocalizedDate(Chronology chrono, Locale locale, ChronoLocalDate date, String expected) { + DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL) + .withChronology(chrono).withLocale(locale); + String text = dtf.format(date); + assertEquals(text, expected); + } + + @Test(dataProvider="format_data") + public void test_parseLocalizedText(Chronology chrono, Locale locale, ChronoLocalDate expected, String text) { + DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL) + .withChronology(chrono).withLocale(locale); + TemporalAccessor temporal = dtf.parse(text); + ChronoLocalDate date = chrono.date(temporal); + assertEquals(date, expected); + } + + @Test(dataProvider="invalid_text", expectedExceptions=DateTimeParseException.class) + public void test_parseInvalidText(String text) { + DateTimeFormatter dtf = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL) + .withChronology(JAPANESE).withLocale(Locale.JAPANESE); + TemporalAccessor temporal = dtf.parse(text); + } +} diff --git a/jdk/test/java/time/test/java/time/format/TestNumberParser.java b/jdk/test/java/time/test/java/time/format/TestNumberParser.java index af4b3b6e940..5dca693e80f 100644 --- a/jdk/test/java/time/test/java/time/format/TestNumberParser.java +++ b/jdk/test/java/time/test/java/time/format/TestNumberParser.java @@ -59,19 +59,20 @@ */ package test.java.time.format; -import java.time.format.*; - import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.DAY_OF_WEEK; import static java.time.temporal.ChronoField.DAY_OF_YEAR; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; import java.text.ParsePosition; -import java.time.format.DateTimeBuilder; -import java.time.temporal.TemporalField; import java.time.format.DateTimeFormatter; +import java.time.format.SignStyle; +import java.time.temporal.Queries; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -94,8 +95,8 @@ public class TestNumberParser extends AbstractTestPrinterParser { @Test(dataProvider="error") public void test_parse_error(TemporalField field, int min, int max, SignStyle style, String text, int pos, Class expected) { try { - getFormatter(field, min, max, style).parseToBuilder(text, new ParsePosition(pos)); - assertTrue(false); + getFormatter(field, min, max, style).parseUnresolved(text, new ParsePosition(pos)); + fail(); } catch (RuntimeException ex) { assertTrue(expected.isInstance(ex)); } @@ -170,13 +171,15 @@ public class TestNumberParser extends AbstractTestPrinterParser { // hacky, to reserve space dtf = builder.appendValue(DAY_OF_YEAR, subsequentWidth).toFormatter(locale).withSymbols(symbols); } - DateTimeBuilder dtb = dtf.parseToBuilder(text, ppos); + TemporalAccessor parsed = dtf.parseUnresolved(text, ppos); if (ppos.getErrorIndex() != -1) { assertEquals(ppos.getErrorIndex(), expectedPos); } else { assertTrue(subsequentWidth >= 0); assertEquals(ppos.getIndex(), expectedPos + subsequentWidth); - assertEquals(dtb.getLong(DAY_OF_MONTH), expectedValue); + assertEquals(parsed.getLong(DAY_OF_MONTH), expectedValue); + assertEquals(parsed.query(Queries.chronology()), null); + assertEquals(parsed.query(Queries.zoneId()), null); } } @@ -188,13 +191,15 @@ public class TestNumberParser extends AbstractTestPrinterParser { // hacky, to reserve space dtf = builder.appendValue(DAY_OF_YEAR, subsequentWidth).toFormatter(locale).withSymbols(symbols); } - DateTimeBuilder dtb = dtf.parseToBuilder(text, ppos); + TemporalAccessor parsed = dtf.parseUnresolved(text, ppos); if (ppos.getErrorIndex() != -1) { assertEquals(ppos.getErrorIndex(), expectedPos); } else { assertTrue(subsequentWidth >= 0); assertEquals(ppos.getIndex(), expectedPos + subsequentWidth); - assertEquals(dtb.getLong(DAY_OF_WEEK), expectedValue); + assertEquals(parsed.getLong(DAY_OF_WEEK), expectedValue); + assertEquals(parsed.query(Queries.chronology()), null); + assertEquals(parsed.query(Queries.zoneId()), null); } } @@ -302,12 +307,14 @@ public class TestNumberParser extends AbstractTestPrinterParser { @Test(dataProvider="parseSignsStrict") public void test_parseSignsStrict(String input, int min, int max, SignStyle style, int parseLen, Integer parseVal) throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter(DAY_OF_MONTH, min, max, style).parseToBuilder(input, pos); + TemporalAccessor parsed = getFormatter(DAY_OF_MONTH, min, max, style).parseUnresolved(input, pos); if (pos.getErrorIndex() != -1) { assertEquals(pos.getErrorIndex(), parseLen); } else { assertEquals(pos.getIndex(), parseLen); - assertEquals(dtb.getLong(DAY_OF_MONTH), (long)parseVal); + assertEquals(parsed.getLong(DAY_OF_MONTH), (long)parseVal); + assertEquals(parsed.query(Queries.chronology()), null); + assertEquals(parsed.query(Queries.zoneId()), null); } } @@ -410,12 +417,14 @@ public class TestNumberParser extends AbstractTestPrinterParser { public void test_parseSignsLenient(String input, int min, int max, SignStyle style, int parseLen, Integer parseVal) throws Exception { setStrict(false); ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter(DAY_OF_MONTH, min, max, style).parseToBuilder(input, pos); + TemporalAccessor parsed = getFormatter(DAY_OF_MONTH, min, max, style).parseUnresolved(input, pos); if (pos.getErrorIndex() != -1) { assertEquals(pos.getErrorIndex(), parseLen); } else { assertEquals(pos.getIndex(), parseLen); - assertEquals(dtb.getLong(DAY_OF_MONTH), (long)parseVal); + assertEquals(parsed.getLong(DAY_OF_MONTH), (long)parseVal); + assertEquals(parsed.query(Queries.chronology()), null); + assertEquals(parsed.query(Queries.zoneId()), null); } } @@ -499,12 +508,14 @@ public class TestNumberParser extends AbstractTestPrinterParser { public void test_parseDigitsLenient(String input, int min, int max, SignStyle style, int parseLen, Integer parseVal) throws Exception { setStrict(false); ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter(DAY_OF_MONTH, min, max, style).parseToBuilder(input, pos); + TemporalAccessor parsed = getFormatter(DAY_OF_MONTH, min, max, style).parseUnresolved(input, pos); if (pos.getErrorIndex() != -1) { assertEquals(pos.getErrorIndex(), parseLen); } else { assertEquals(pos.getIndex(), parseLen); - assertEquals(dtb.getLong(DAY_OF_MONTH), (long)parseVal); + assertEquals(parsed.getLong(DAY_OF_MONTH), (long)parseVal); + assertEquals(parsed.query(Queries.chronology()), null); + assertEquals(parsed.query(Queries.zoneId()), null); } } @@ -534,13 +545,15 @@ public class TestNumberParser extends AbstractTestPrinterParser { DateTimeFormatter f = builder .appendValue(MONTH_OF_YEAR, 1, 2, SignStyle.NORMAL) .appendValue(DAY_OF_MONTH, 2).toFormatter(locale).withSymbols(symbols); - DateTimeBuilder dtb = f.parseToBuilder(input, pos); + TemporalAccessor parsed = f.parseUnresolved(input, pos); if (pos.getErrorIndex() != -1) { assertEquals(pos.getErrorIndex(), parseLen); } else { assertEquals(pos.getIndex(), parseLen); - assertEquals(dtb.getLong(MONTH_OF_YEAR), (long) parseMonth); - assertEquals(dtb.getLong(DAY_OF_MONTH), (long) parsedDay); + assertEquals(parsed.getLong(MONTH_OF_YEAR), (long) parseMonth); + assertEquals(parsed.getLong(DAY_OF_MONTH), (long) parsedDay); + assertEquals(parsed.query(Queries.chronology()), null); + assertEquals(parsed.query(Queries.zoneId()), null); } } diff --git a/jdk/test/java/time/test/java/time/format/TestNumberPrinter.java b/jdk/test/java/time/test/java/time/format/TestNumberPrinter.java index 80c05b8eb9f..9d686472ab6 100644 --- a/jdk/test/java/time/test/java/time/format/TestNumberPrinter.java +++ b/jdk/test/java/time/test/java/time/format/TestNumberPrinter.java @@ -59,8 +59,6 @@ */ package test.java.time.format; -import java.time.format.*; - import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.HOUR_OF_DAY; import static org.testng.Assert.assertEquals; @@ -68,10 +66,11 @@ import static org.testng.Assert.fail; import java.time.DateTimeException; import java.time.LocalDate; -import test.java.time.temporal.MockFieldValue; +import java.time.format.SignStyle; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import test.java.time.temporal.MockFieldValue; /** * Test SimpleNumberPrinterParser. @@ -82,12 +81,12 @@ public class TestNumberPrinter extends AbstractTestPrinterParser { //----------------------------------------------------------------------- @Test(expectedExceptions=DateTimeException.class) public void test_print_emptyCalendrical() throws Exception { - getFormatter(DAY_OF_MONTH, 1, 2, SignStyle.NEVER).printTo(EMPTY_DTA, buf); + getFormatter(DAY_OF_MONTH, 1, 2, SignStyle.NEVER).formatTo(EMPTY_DTA, buf); } public void test_print_append() throws Exception { buf.append("EXISTING"); - getFormatter(DAY_OF_MONTH, 1, 2, SignStyle.NEVER).printTo(LocalDate.of(2012, 1, 3), buf); + getFormatter(DAY_OF_MONTH, 1, 2, SignStyle.NEVER).formatTo(LocalDate.of(2012, 1, 3), buf); assertEquals(buf.toString(), "EXISTING3"); } @@ -185,12 +184,12 @@ public class TestNumberPrinter extends AbstractTestPrinterParser { @Test(dataProvider="Pad") public void test_pad_NOT_NEGATIVE(int minPad, int maxPad, long value, String result) throws Exception { try { - getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.NOT_NEGATIVE).printTo(new MockFieldValue(DAY_OF_MONTH, value), buf); + getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.NOT_NEGATIVE).formatTo(new MockFieldValue(DAY_OF_MONTH, value), buf); if (result == null || value < 0) { fail("Expected exception"); } assertEquals(buf.toString(), result); - } catch (DateTimePrintException ex) { + } catch (DateTimeException ex) { if (result == null || value < 0) { assertEquals(ex.getMessage().contains(DAY_OF_MONTH.getName()), true); } else { @@ -202,12 +201,12 @@ public class TestNumberPrinter extends AbstractTestPrinterParser { @Test(dataProvider="Pad") public void test_pad_NEVER(int minPad, int maxPad, long value, String result) throws Exception { try { - getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.NEVER).printTo(new MockFieldValue(DAY_OF_MONTH, value), buf); + getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.NEVER).formatTo(new MockFieldValue(DAY_OF_MONTH, value), buf); if (result == null) { fail("Expected exception"); } assertEquals(buf.toString(), result); - } catch (DateTimePrintException ex) { + } catch (DateTimeException ex) { if (result != null) { throw ex; } @@ -218,12 +217,12 @@ public class TestNumberPrinter extends AbstractTestPrinterParser { @Test(dataProvider="Pad") public void test_pad_NORMAL(int minPad, int maxPad, long value, String result) throws Exception { try { - getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.NORMAL).printTo(new MockFieldValue(DAY_OF_MONTH, value), buf); + getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.NORMAL).formatTo(new MockFieldValue(DAY_OF_MONTH, value), buf); if (result == null) { fail("Expected exception"); } assertEquals(buf.toString(), (value < 0 ? "-" + result : result)); - } catch (DateTimePrintException ex) { + } catch (DateTimeException ex) { if (result != null) { throw ex; } @@ -234,12 +233,12 @@ public class TestNumberPrinter extends AbstractTestPrinterParser { @Test(dataProvider="Pad") public void test_pad_ALWAYS(int minPad, int maxPad, long value, String result) throws Exception { try { - getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.ALWAYS).printTo(new MockFieldValue(DAY_OF_MONTH, value), buf); + getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.ALWAYS).formatTo(new MockFieldValue(DAY_OF_MONTH, value), buf); if (result == null) { fail("Expected exception"); } assertEquals(buf.toString(), (value < 0 ? "-" + result : "+" + result)); - } catch (DateTimePrintException ex) { + } catch (DateTimeException ex) { if (result != null) { throw ex; } @@ -250,7 +249,7 @@ public class TestNumberPrinter extends AbstractTestPrinterParser { @Test(dataProvider="Pad") public void test_pad_EXCEEDS_PAD(int minPad, int maxPad, long value, String result) throws Exception { try { - getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.EXCEEDS_PAD).printTo(new MockFieldValue(DAY_OF_MONTH, value), buf); + getFormatter(DAY_OF_MONTH, minPad, maxPad, SignStyle.EXCEEDS_PAD).formatTo(new MockFieldValue(DAY_OF_MONTH, value), buf); if (result == null) { fail("Expected exception"); return; // unreachable @@ -259,7 +258,7 @@ public class TestNumberPrinter extends AbstractTestPrinterParser { result = (value < 0 ? "-" + result : "+" + result); } assertEquals(buf.toString(), result); - } catch (DateTimePrintException ex) { + } catch (DateTimeException ex) { if (result != null) { throw ex; } diff --git a/jdk/test/java/time/test/java/time/format/TestPadPrinterDecorator.java b/jdk/test/java/time/test/java/time/format/TestPadPrinterDecorator.java index d6302aee4d7..c8dcbf39c53 100644 --- a/jdk/test/java/time/test/java/time/format/TestPadPrinterDecorator.java +++ b/jdk/test/java/time/test/java/time/format/TestPadPrinterDecorator.java @@ -59,10 +59,9 @@ */ package test.java.time.format; -import java.time.format.*; - import static org.testng.Assert.assertEquals; +import java.time.DateTimeException; import java.time.LocalDate; import org.testng.annotations.Test; @@ -76,52 +75,52 @@ public class TestPadPrinterDecorator extends AbstractTestPrinterParser { //----------------------------------------------------------------------- public void test_print_emptyCalendrical() throws Exception { builder.padNext(3, '-').appendLiteral('Z'); - getFormatter().printTo(EMPTY_DTA, buf); + getFormatter().formatTo(EMPTY_DTA, buf); assertEquals(buf.toString(), "--Z"); } public void test_print_fullDateTime() throws Exception { builder.padNext(3, '-').appendLiteral('Z'); - getFormatter().printTo(LocalDate.of(2008, 12, 3), buf); + getFormatter().formatTo(LocalDate.of(2008, 12, 3), buf); assertEquals(buf.toString(), "--Z"); } public void test_print_append() throws Exception { buf.append("EXISTING"); builder.padNext(3, '-').appendLiteral('Z'); - getFormatter().printTo(EMPTY_DTA, buf); + getFormatter().formatTo(EMPTY_DTA, buf); assertEquals(buf.toString(), "EXISTING--Z"); } //----------------------------------------------------------------------- public void test_print_noPadRequiredSingle() throws Exception { builder.padNext(1, '-').appendLiteral('Z'); - getFormatter().printTo(EMPTY_DTA, buf); + getFormatter().formatTo(EMPTY_DTA, buf); assertEquals(buf.toString(), "Z"); } public void test_print_padRequiredSingle() throws Exception { builder.padNext(5, '-').appendLiteral('Z'); - getFormatter().printTo(EMPTY_DTA, buf); + getFormatter().formatTo(EMPTY_DTA, buf); assertEquals(buf.toString(), "----Z"); } public void test_print_noPadRequiredMultiple() throws Exception { builder.padNext(4, '-').appendLiteral("WXYZ"); - getFormatter().printTo(EMPTY_DTA, buf); + getFormatter().formatTo(EMPTY_DTA, buf); assertEquals(buf.toString(), "WXYZ"); } public void test_print_padRequiredMultiple() throws Exception { builder.padNext(5, '-').appendLiteral("WXYZ"); - getFormatter().printTo(EMPTY_DTA, buf); + getFormatter().formatTo(EMPTY_DTA, buf); assertEquals(buf.toString(), "-WXYZ"); } - @Test(expectedExceptions=DateTimePrintException.class) + @Test(expectedExceptions=DateTimeException.class) public void test_print_overPad() throws Exception { builder.padNext(3, '-').appendLiteral("WXYZ"); - getFormatter().printTo(EMPTY_DTA, buf); + getFormatter().formatTo(EMPTY_DTA, buf); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/test/java/time/format/TestReducedParser.java b/jdk/test/java/time/test/java/time/format/TestReducedParser.java index bcd383039ff..c1a41bbef95 100644 --- a/jdk/test/java/time/test/java/time/format/TestReducedParser.java +++ b/jdk/test/java/time/test/java/time/format/TestReducedParser.java @@ -59,15 +59,14 @@ */ package test.java.time.format; -import java.time.format.*; - import static java.time.temporal.ChronoField.DAY_OF_YEAR; import static java.time.temporal.ChronoField.YEAR; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.text.ParsePosition; -import java.time.format.DateTimeBuilder; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; import org.testng.annotations.DataProvider; @@ -95,7 +94,7 @@ public class TestReducedParser extends AbstractTestPrinterParser { @Test(dataProvider="error") public void test_parse_error(TemporalField field, int width, int baseValue, String text, int pos, Class expected) { try { - getFormatter0(field, width, baseValue).parseToBuilder(text, new ParsePosition(pos)); + getFormatter0(field, width, baseValue).parseUnresolved(text, new ParsePosition(pos)); } catch (RuntimeException ex) { assertTrue(expected.isInstance(ex)); } @@ -104,9 +103,9 @@ public class TestReducedParser extends AbstractTestPrinterParser { //----------------------------------------------------------------------- public void test_parse_fieldRangeIgnored() throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter0(DAY_OF_YEAR, 3, 10).parseToBuilder("456", pos); + TemporalAccessor parsed = getFormatter0(DAY_OF_YEAR, 3, 10).parseUnresolved("456", pos); assertEquals(pos.getIndex(), 3); - assertParsed(dtb, DAY_OF_YEAR, 456L); // parsed dayOfYear=456 + assertParsed(parsed, DAY_OF_YEAR, 456L); // parsed dayOfYear=456 } //----------------------------------------------------------------------- @@ -165,12 +164,12 @@ public class TestReducedParser extends AbstractTestPrinterParser { @Test(dataProvider="Parse") public void test_parse(TemporalField field, int width, int baseValue, String input, int pos, int parseLen, Integer parseVal) { ParsePosition ppos = new ParsePosition(pos); - DateTimeBuilder dtb = getFormatter0(field, width, baseValue).parseToBuilder(input, ppos); + TemporalAccessor parsed = getFormatter0(field, width, baseValue).parseUnresolved(input, ppos); if (ppos.getErrorIndex() != -1) { assertEquals(ppos.getErrorIndex(), parseLen); } else { assertEquals(ppos.getIndex(), parseLen); - assertParsed(dtb, YEAR, parseVal != null ? (long) parseVal : null); + assertParsed(parsed, YEAR, parseVal != null ? (long) parseVal : null); } } @@ -178,20 +177,21 @@ public class TestReducedParser extends AbstractTestPrinterParser { public void test_parseLenient(TemporalField field, int width, int baseValue, String input, int pos, int parseLen, Integer parseVal) { setStrict(false); ParsePosition ppos = new ParsePosition(pos); - DateTimeBuilder dtb = getFormatter0(field, width, baseValue).parseToBuilder(input, ppos); + TemporalAccessor parsed = getFormatter0(field, width, baseValue).parseUnresolved(input, ppos); if (ppos.getErrorIndex() != -1) { assertEquals(ppos.getErrorIndex(), parseLen); } else { assertEquals(ppos.getIndex(), parseLen); - assertParsed(dtb, YEAR, parseVal != null ? (long) parseVal : null); + assertParsed(parsed, YEAR, parseVal != null ? (long) parseVal : null); } } - private void assertParsed(DateTimeBuilder dtb, TemporalField field, Long value) { + private void assertParsed(TemporalAccessor parsed, TemporalField field, Long value) { if (value == null) { - assertEquals(dtb, null); + assertEquals(parsed, null); } else { - assertEquals(dtb.getLong(field), (long)value); + assertEquals(parsed.isSupported(field), true); + assertEquals(parsed.getLong(field), (long) value); } } diff --git a/jdk/test/java/time/test/java/time/format/TestReducedPrinter.java b/jdk/test/java/time/test/java/time/format/TestReducedPrinter.java index 698496dc57e..76060691910 100644 --- a/jdk/test/java/time/test/java/time/format/TestReducedPrinter.java +++ b/jdk/test/java/time/test/java/time/format/TestReducedPrinter.java @@ -86,13 +86,13 @@ public class TestReducedPrinter extends AbstractTestPrinterParser { //----------------------------------------------------------------------- @Test(expectedExceptions=DateTimeException.class) public void test_print_emptyCalendrical() throws Exception { - getFormatter0(YEAR, 2, 2010).printTo(EMPTY_DTA, buf); + getFormatter0(YEAR, 2, 2010).formatTo(EMPTY_DTA, buf); } //----------------------------------------------------------------------- public void test_print_append() throws Exception { buf.append("EXISTING"); - getFormatter0(YEAR, 2, 2010).printTo(LocalDate.of(2012, 1, 1), buf); + getFormatter0(YEAR, 2, 2010).formatTo(LocalDate.of(2012, 1, 1), buf); assertEquals(buf.toString(), "EXISTING12"); } @@ -159,12 +159,12 @@ public class TestReducedPrinter extends AbstractTestPrinterParser { @Test(dataProvider="Pivot") public void test_pivot(int width, int baseValue, int value, String result) throws Exception { try { - getFormatter0(YEAR, width, baseValue).printTo(new MockFieldValue(YEAR, value), buf); + getFormatter0(YEAR, width, baseValue).formatTo(new MockFieldValue(YEAR, value), buf); if (result == null) { fail("Expected exception"); } assertEquals(buf.toString(), result); - } catch (DateTimePrintException ex) { + } catch (DateTimeException ex) { if (result == null || value < 0) { assertEquals(ex.getMessage().contains(YEAR.getName()), true); } else { diff --git a/jdk/test/java/time/test/java/time/format/TestSettingsParser.java b/jdk/test/java/time/test/java/time/format/TestSettingsParser.java index 4b639aa56d4..ed3b0a58716 100644 --- a/jdk/test/java/time/test/java/time/format/TestSettingsParser.java +++ b/jdk/test/java/time/test/java/time/format/TestSettingsParser.java @@ -59,12 +59,9 @@ */ package test.java.time.format; -import java.time.format.*; - import static org.testng.Assert.assertEquals; import java.text.ParsePosition; -import java.time.ZoneOffset; import org.testng.annotations.Test; @@ -77,20 +74,20 @@ public class TestSettingsParser extends AbstractTestPrinterParser { //----------------------------------------------------------------------- public void test_print_sensitive() throws Exception { setCaseSensitive(true); - getFormatter().printTo(dta, buf); + getFormatter().formatTo(dta, buf); assertEquals(buf.toString(), ""); } public void test_print_strict() throws Exception { setStrict(true); - getFormatter().printTo(dta, buf); + getFormatter().formatTo(dta, buf); assertEquals(buf.toString(), ""); } /* public void test_print_nulls() throws Exception { setCaseSensitive(true); - getFormatter().printTo(null, null); + getFormatter().formatTo(null, null); } */ @@ -98,28 +95,28 @@ public class TestSettingsParser extends AbstractTestPrinterParser { public void test_parse_changeStyle_sensitive() throws Exception { setCaseSensitive(true); ParsePosition pos = new ParsePosition(0); - getFormatter().parseToBuilder("a", pos); + getFormatter().parseUnresolved("a", pos); assertEquals(pos.getIndex(), 0); } public void test_parse_changeStyle_insensitive() throws Exception { setCaseSensitive(false); ParsePosition pos = new ParsePosition(0); - getFormatter().parseToBuilder("a", pos); + getFormatter().parseUnresolved("a", pos); assertEquals(pos.getIndex(), 0); } public void test_parse_changeStyle_strict() throws Exception { setStrict(true); ParsePosition pos = new ParsePosition(0); - getFormatter().parseToBuilder("a", pos); + getFormatter().parseUnresolved("a", pos); assertEquals(pos.getIndex(), 0); } public void test_parse_changeStyle_lenient() throws Exception { setStrict(false); ParsePosition pos = new ParsePosition(0); - getFormatter().parseToBuilder("a", pos); + getFormatter().parseUnresolved("a", pos); assertEquals(pos.getIndex(), 0); } diff --git a/jdk/test/java/time/test/java/time/format/TestStringLiteralParser.java b/jdk/test/java/time/test/java/time/format/TestStringLiteralParser.java index bd67eab39f3..a2096521bff 100644 --- a/jdk/test/java/time/test/java/time/format/TestStringLiteralParser.java +++ b/jdk/test/java/time/test/java/time/format/TestStringLiteralParser.java @@ -59,11 +59,14 @@ */ package test.java.time.format; +import static java.time.temporal.ChronoField.YEAR; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; -import java.time.format.DateTimeBuilder; import java.text.ParsePosition; +import java.time.temporal.Queries; +import java.time.temporal.TemporalAccessor; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -105,13 +108,14 @@ public class TestStringLiteralParser extends AbstractTestPrinterParser { public void test_parse_success(String s, boolean caseSensitive, String text, int pos, int expectedPos) { setCaseSensitive(caseSensitive); ParsePosition ppos = new ParsePosition(pos); - DateTimeBuilder result = - getFormatter(s).parseToBuilder(text, ppos); + TemporalAccessor parsed = getFormatter(s).parseUnresolved(text, ppos); if (ppos.getErrorIndex() != -1) { assertEquals(ppos.getIndex(), expectedPos); } else { assertEquals(ppos.getIndex(), expectedPos); - assertEquals(result.getCalendricalList().size(), 0); + assertEquals(parsed.isSupported(YEAR), false); + assertEquals(parsed.query(Queries.chronology()), null); + assertEquals(parsed.query(Queries.zoneId()), null); } } @@ -127,9 +131,9 @@ public class TestStringLiteralParser extends AbstractTestPrinterParser { @Test(dataProvider="error") public void test_parse_error(String s, String text, int pos, Class expected) { try { - DateTimeBuilder result = - getFormatter(s).parseToBuilder(text, new ParsePosition(pos)); - assertTrue(false); + ParsePosition ppos = new ParsePosition(pos); + getFormatter(s).parseUnresolved(text, ppos); + fail(); } catch (RuntimeException ex) { assertTrue(expected.isInstance(ex)); } diff --git a/jdk/test/java/time/test/java/time/format/TestStringLiteralPrinter.java b/jdk/test/java/time/test/java/time/format/TestStringLiteralPrinter.java index df018701b3c..62d6a4efc0c 100644 --- a/jdk/test/java/time/test/java/time/format/TestStringLiteralPrinter.java +++ b/jdk/test/java/time/test/java/time/format/TestStringLiteralPrinter.java @@ -74,13 +74,13 @@ public class TestStringLiteralPrinter extends AbstractTestPrinterParser { //----------------------------------------------------------------------- public void test_print_emptyCalendrical() throws Exception { buf.append("EXISTING"); - getFormatter("hello").printTo(EMPTY_DTA, buf); + getFormatter("hello").formatTo(EMPTY_DTA, buf); assertEquals(buf.toString(), "EXISTINGhello"); } public void test_print_dateTime() throws Exception { buf.append("EXISTING"); - getFormatter("hello").printTo(dta, buf); + getFormatter("hello").formatTo(dta, buf); assertEquals(buf.toString(), "EXISTINGhello"); } @@ -88,7 +88,7 @@ public class TestStringLiteralPrinter extends AbstractTestPrinterParser { public void test_print_emptyAppendable() throws Exception { - getFormatter("hello").printTo(dta, buf); + getFormatter("hello").formatTo(dta, buf); assertEquals(buf.toString(), "hello"); } diff --git a/jdk/test/java/time/test/java/time/format/TestTextParser.java b/jdk/test/java/time/test/java/time/format/TestTextParser.java index 7961b27ac8b..9e9c3f73973 100644 --- a/jdk/test/java/time/test/java/time/format/TestTextParser.java +++ b/jdk/test/java/time/test/java/time/format/TestTextParser.java @@ -59,8 +59,6 @@ */ package test.java.time.format; -import java.time.format.*; - import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.DAY_OF_WEEK; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; @@ -68,9 +66,10 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import java.text.ParsePosition; -import java.util.Locale; -import java.time.format.DateTimeBuilder; +import java.time.format.TextStyle; +import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; +import java.util.Locale; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -93,7 +92,7 @@ public class TestTextParser extends AbstractTestPrinterParser { @Test(dataProvider="error") public void test_parse_error(TemporalField field, TextStyle style, String text, int pos, Class expected) { try { - getFormatter(field, style).parseToBuilder(text, new ParsePosition(pos)); + getFormatter(field, style).parseUnresolved(text, new ParsePosition(pos)); } catch (RuntimeException ex) { assertTrue(expected.isInstance(ex)); } @@ -103,7 +102,7 @@ public class TestTextParser extends AbstractTestPrinterParser { public void test_parse_midStr() throws Exception { ParsePosition pos = new ParsePosition(3); assertEquals(getFormatter(DAY_OF_WEEK, TextStyle.FULL) - .parseToBuilder("XxxMondayXxx", pos) + .parseUnresolved("XxxMondayXxx", pos) .getLong(DAY_OF_WEEK), 1L); assertEquals(pos.getIndex(), 9); } @@ -111,7 +110,7 @@ public class TestTextParser extends AbstractTestPrinterParser { public void test_parse_remainderIgnored() throws Exception { ParsePosition pos = new ParsePosition(0); assertEquals(getFormatter(DAY_OF_WEEK, TextStyle.SHORT) - .parseToBuilder("Wednesday", pos) + .parseUnresolved("Wednesday", pos) .getLong(DAY_OF_WEEK), 3L); assertEquals(pos.getIndex(), 3); } @@ -119,23 +118,26 @@ public class TestTextParser extends AbstractTestPrinterParser { //----------------------------------------------------------------------- public void test_parse_noMatch1() throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = - getFormatter(DAY_OF_WEEK, TextStyle.FULL).parseToBuilder("Munday", pos); + TemporalAccessor parsed = + getFormatter(DAY_OF_WEEK, TextStyle.FULL).parseUnresolved("Munday", pos); assertEquals(pos.getErrorIndex(), 0); + assertEquals(parsed, null); } public void test_parse_noMatch2() throws Exception { ParsePosition pos = new ParsePosition(3); - DateTimeBuilder dtb = - getFormatter(DAY_OF_WEEK, TextStyle.FULL).parseToBuilder("Monday", pos); + TemporalAccessor parsed = + getFormatter(DAY_OF_WEEK, TextStyle.FULL).parseUnresolved("Monday", pos); assertEquals(pos.getErrorIndex(), 3); + assertEquals(parsed, null); } public void test_parse_noMatch_atEnd() throws Exception { ParsePosition pos = new ParsePosition(6); - DateTimeBuilder dtb = - getFormatter(DAY_OF_WEEK, TextStyle.FULL).parseToBuilder("Monday", pos); + TemporalAccessor parsed = + getFormatter(DAY_OF_WEEK, TextStyle.FULL).parseUnresolved("Monday", pos); assertEquals(pos.getErrorIndex(), 6); + assertEquals(parsed, null); } //----------------------------------------------------------------------- @@ -184,14 +186,14 @@ public class TestTextParser extends AbstractTestPrinterParser { @Test(dataProvider="parseText") public void test_parseText(TemporalField field, TextStyle style, int value, String input) throws Exception { ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(field, style).parseToBuilder(input, pos).getLong(field), (long) value); + assertEquals(getFormatter(field, style).parseUnresolved(input, pos).getLong(field), (long) value); assertEquals(pos.getIndex(), input.length()); } @Test(dataProvider="parseNumber") public void test_parseNumber(TemporalField field, TextStyle style, int value, String input) throws Exception { ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(field, style).parseToBuilder(input, pos).getLong(field), (long) value); + assertEquals(getFormatter(field, style).parseUnresolved(input, pos).getLong(field), (long) value); assertEquals(pos.getIndex(), input.length()); } @@ -200,7 +202,7 @@ public class TestTextParser extends AbstractTestPrinterParser { public void test_parse_strict_caseSensitive_parseUpper(TemporalField field, TextStyle style, int value, String input) throws Exception { setCaseSensitive(true); ParsePosition pos = new ParsePosition(0); - getFormatter(field, style).parseToBuilder(input.toUpperCase(), pos); + getFormatter(field, style).parseUnresolved(input.toUpperCase(), pos); assertEquals(pos.getErrorIndex(), 0); } @@ -208,7 +210,7 @@ public class TestTextParser extends AbstractTestPrinterParser { public void test_parse_strict_caseInsensitive_parseUpper(TemporalField field, TextStyle style, int value, String input) throws Exception { setCaseSensitive(false); ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(field, style).parseToBuilder(input.toUpperCase(), pos).getLong(field), (long) value); + assertEquals(getFormatter(field, style).parseUnresolved(input.toUpperCase(), pos).getLong(field), (long) value); assertEquals(pos.getIndex(), input.length()); } @@ -217,7 +219,7 @@ public class TestTextParser extends AbstractTestPrinterParser { public void test_parse_strict_caseSensitive_parseLower(TemporalField field, TextStyle style, int value, String input) throws Exception { setCaseSensitive(true); ParsePosition pos = new ParsePosition(0); - getFormatter(field, style).parseToBuilder(input.toLowerCase(), pos); + getFormatter(field, style).parseUnresolved(input.toLowerCase(), pos); assertEquals(pos.getErrorIndex(), 0); } @@ -225,7 +227,7 @@ public class TestTextParser extends AbstractTestPrinterParser { public void test_parse_strict_caseInsensitive_parseLower(TemporalField field, TextStyle style, int value, String input) throws Exception { setCaseSensitive(false); ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(field, style).parseToBuilder(input.toLowerCase(), pos).getLong(field), (long) value); + assertEquals(getFormatter(field, style).parseUnresolved(input.toLowerCase(), pos).getLong(field), (long) value); assertEquals(pos.getIndex(), input.length()); } @@ -235,21 +237,21 @@ public class TestTextParser extends AbstractTestPrinterParser { public void test_parse_full_strict_full_match() throws Exception { setStrict(true); ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseToBuilder("January", pos).getLong(MONTH_OF_YEAR), 1L); + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseUnresolved("January", pos).getLong(MONTH_OF_YEAR), 1L); assertEquals(pos.getIndex(), 7); } public void test_parse_full_strict_short_noMatch() throws Exception { setStrict(true); ParsePosition pos = new ParsePosition(0); - getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseToBuilder("Janua", pos); + getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseUnresolved("Janua", pos); assertEquals(pos.getErrorIndex(), 0); } public void test_parse_full_strict_number_noMatch() throws Exception { setStrict(true); ParsePosition pos = new ParsePosition(0); - getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseToBuilder("1", pos); + getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseUnresolved("1", pos); assertEquals(pos.getErrorIndex(), 0); } @@ -257,21 +259,21 @@ public class TestTextParser extends AbstractTestPrinterParser { public void test_parse_short_strict_full_match() throws Exception { setStrict(true); ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseToBuilder("January", pos).getLong(MONTH_OF_YEAR), 1L); + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseUnresolved("January", pos).getLong(MONTH_OF_YEAR), 1L); assertEquals(pos.getIndex(), 3); } public void test_parse_short_strict_short_match() throws Exception { setStrict(true); ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseToBuilder("Janua", pos).getLong(MONTH_OF_YEAR), 1L); + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseUnresolved("Janua", pos).getLong(MONTH_OF_YEAR), 1L); assertEquals(pos.getIndex(), 3); } public void test_parse_short_strict_number_noMatch() throws Exception { setStrict(true); ParsePosition pos = new ParsePosition(0); - getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseToBuilder("1", pos); + getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseUnresolved("1", pos); assertEquals(pos.getErrorIndex(), 0); } @@ -280,7 +282,7 @@ public class TestTextParser extends AbstractTestPrinterParser { setStrict(true); ParsePosition pos = new ParsePosition(0); getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH) - .parseToBuilder("janvier", pos); + .parseUnresolved("janvier", pos); assertEquals(pos.getErrorIndex(), 0); } @@ -288,7 +290,7 @@ public class TestTextParser extends AbstractTestPrinterParser { setStrict(true); ParsePosition pos = new ParsePosition(0); assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH) - .parseToBuilder("janv.", pos) + .parseUnresolved("janv.", pos) .getLong(MONTH_OF_YEAR), 1L); assertEquals(pos.getIndex(), 5); @@ -298,21 +300,21 @@ public class TestTextParser extends AbstractTestPrinterParser { public void test_parse_full_lenient_full_match() throws Exception { setStrict(false); ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseToBuilder("January.", pos).getLong(MONTH_OF_YEAR), 1L); + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseUnresolved("January.", pos).getLong(MONTH_OF_YEAR), 1L); assertEquals(pos.getIndex(), 7); } public void test_parse_full_lenient_short_match() throws Exception { setStrict(false); ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseToBuilder("Janua", pos).getLong(MONTH_OF_YEAR), 1L); + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseUnresolved("Janua", pos).getLong(MONTH_OF_YEAR), 1L); assertEquals(pos.getIndex(), 3); } public void test_parse_full_lenient_number_match() throws Exception { setStrict(false); ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseToBuilder("1", pos).getLong(MONTH_OF_YEAR), 1L); + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.FULL).parseUnresolved("1", pos).getLong(MONTH_OF_YEAR), 1L); assertEquals(pos.getIndex(), 1); } @@ -320,21 +322,21 @@ public class TestTextParser extends AbstractTestPrinterParser { public void test_parse_short_lenient_full_match() throws Exception { setStrict(false); ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseToBuilder("January", pos).getLong(MONTH_OF_YEAR), 1L); + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseUnresolved("January", pos).getLong(MONTH_OF_YEAR), 1L); assertEquals(pos.getIndex(), 7); } public void test_parse_short_lenient_short_match() throws Exception { setStrict(false); ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseToBuilder("Janua", pos).getLong(MONTH_OF_YEAR), 1L); + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseUnresolved("Janua", pos).getLong(MONTH_OF_YEAR), 1L); assertEquals(pos.getIndex(), 3); } public void test_parse_short_lenient_number_match() throws Exception { setStrict(false); ParsePosition pos = new ParsePosition(0); - assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseToBuilder("1", pos).getLong(MONTH_OF_YEAR), 1L); + assertEquals(getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).parseUnresolved("1", pos).getLong(MONTH_OF_YEAR), 1L); assertEquals(pos.getIndex(), 1); } diff --git a/jdk/test/java/time/test/java/time/format/TestTextPrinter.java b/jdk/test/java/time/test/java/time/format/TestTextPrinter.java index cc93f461a78..43f2df31bef 100644 --- a/jdk/test/java/time/test/java/time/format/TestTextPrinter.java +++ b/jdk/test/java/time/test/java/time/format/TestTextPrinter.java @@ -64,6 +64,7 @@ import java.time.format.*; import static java.time.temporal.ChronoField.DAY_OF_MONTH; import static java.time.temporal.ChronoField.DAY_OF_WEEK; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; +import static java.time.temporal.ChronoField.ERA; import static org.testng.Assert.assertEquals; import java.util.Locale; @@ -71,6 +72,7 @@ import java.util.Locale; import java.time.DateTimeException; import java.time.LocalDate; import java.time.temporal.TemporalField; +import java.time.chrono.JapaneseChronology; import test.java.time.temporal.MockFieldValue; import org.testng.annotations.DataProvider; @@ -85,12 +87,12 @@ public class TestTextPrinter extends AbstractTestPrinterParser { //----------------------------------------------------------------------- @Test(expectedExceptions=DateTimeException.class) public void test_print_emptyCalendrical() throws Exception { - getFormatter(DAY_OF_WEEK, TextStyle.FULL).printTo(EMPTY_DTA, buf); + getFormatter(DAY_OF_WEEK, TextStyle.FULL).formatTo(EMPTY_DTA, buf); } public void test_print_append() throws Exception { buf.append("EXISTING"); - getFormatter(DAY_OF_WEEK, TextStyle.FULL).printTo(LocalDate.of(2012, 4, 18), buf); + getFormatter(DAY_OF_WEEK, TextStyle.FULL).formatTo(LocalDate.of(2012, 4, 18), buf); assertEquals(buf.toString(), "EXISTINGWednesday"); } @@ -163,23 +165,46 @@ public class TestTextPrinter extends AbstractTestPrinterParser { {MONTH_OF_YEAR, TextStyle.SHORT, 10, "Oct"}, {MONTH_OF_YEAR, TextStyle.SHORT, 11, "Nov"}, {MONTH_OF_YEAR, TextStyle.SHORT, 12, "Dec"}, + + {ERA, TextStyle.FULL, 0, "Before Christ"}, + {ERA, TextStyle.FULL, 1, "Anno Domini"}, + {ERA, TextStyle.SHORT, 0, "BC"}, + {ERA, TextStyle.SHORT, 1, "AD"}, + {ERA, TextStyle.NARROW, 0, "B"}, + {ERA, TextStyle.NARROW, 1, "A"}, }; } + @DataProvider(name="print_JapaneseChronology") + Object[][] provider_japaneseEra() { + return new Object[][] { + {ERA, TextStyle.FULL, 2, "Heisei"}, // Note: CLDR doesn't define "wide" Japanese era names. + {ERA, TextStyle.SHORT, 2, "Heisei"}, + {ERA, TextStyle.NARROW, 2, "H"}, + }; + }; + @Test(dataProvider="print") - public void test_print(TemporalField field, TextStyle style, int value, String expected) throws Exception { - getFormatter(field, style).printTo(new MockFieldValue(field, value), buf); + public void test_format(TemporalField field, TextStyle style, int value, String expected) throws Exception { + getFormatter(field, style).formatTo(new MockFieldValue(field, value), buf); + assertEquals(buf.toString(), expected); + } + + @Test(dataProvider="print_JapaneseChronology") + public void test_formatJapaneseEra(TemporalField field, TextStyle style, int value, String expected) throws Exception { + LocalDate ld = LocalDate.of(2013, 1, 31); + getFormatter(field, style).withChronology(JapaneseChronology.INSTANCE).formatTo(ld, buf); assertEquals(buf.toString(), expected); } //----------------------------------------------------------------------- public void test_print_french_long() throws Exception { - getFormatter(MONTH_OF_YEAR, TextStyle.FULL).withLocale(Locale.FRENCH).printTo(LocalDate.of(2012, 1, 1), buf); + getFormatter(MONTH_OF_YEAR, TextStyle.FULL).withLocale(Locale.FRENCH).formatTo(LocalDate.of(2012, 1, 1), buf); assertEquals(buf.toString(), "janvier"); } public void test_print_french_short() throws Exception { - getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH).printTo(LocalDate.of(2012, 1, 1), buf); + getFormatter(MONTH_OF_YEAR, TextStyle.SHORT).withLocale(Locale.FRENCH).formatTo(LocalDate.of(2012, 1, 1), buf); assertEquals(buf.toString(), "janv."); } diff --git a/jdk/test/java/time/test/java/time/format/TestZoneIdParser.java b/jdk/test/java/time/test/java/time/format/TestZoneIdParser.java deleted file mode 100644 index 99ee93bb52e..00000000000 --- a/jdk/test/java/time/test/java/time/format/TestZoneIdParser.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (c) 2012, 2013, 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 file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file: - * - * Copyright (c) 2009-2012, Stephen Colebourne & Michael Nascimento Santos - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of JSR-310 nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package test.java.time.format; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -import java.util.Set; - -import java.text.ParsePosition; -import java.time.ZoneId; -import java.time.format.DateTimeBuilder; -import java.time.format.DateTimeFormatter; -import java.time.format.TextStyle; -import java.time.format.DateTimeFormatterBuilder; -import java.time.temporal.Queries; -import java.time.zone.ZoneRulesProvider; - -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -/** - * Test ZonePrinterParser. - */ -@Test(groups={"implementation"}) -public class TestZoneIdParser extends AbstractTestPrinterParser { - - private static final String AMERICA_DENVER = "America/Denver"; - private static final ZoneId TIME_ZONE_DENVER = ZoneId.of(AMERICA_DENVER); - - private DateTimeFormatter getFormatter0(TextStyle style) { - if (style == null) - return builder.appendZoneId().toFormatter(locale).withSymbols(symbols); - return builder.appendZoneText(style).toFormatter(locale).withSymbols(symbols); - } - - //----------------------------------------------------------------------- - @DataProvider(name="error") - Object[][] data_error() { - return new Object[][] { - {null, "hello", -1, IndexOutOfBoundsException.class}, - {null, "hello", 6, IndexOutOfBoundsException.class}, - }; - } - - @Test(dataProvider="error") - public void test_parse_error(TextStyle style, String text, int pos, Class expected) { - try { - getFormatter0(style).parseToBuilder(text, new ParsePosition(pos)); - assertTrue(false); - } catch (RuntimeException ex) { - assertTrue(expected.isInstance(ex)); - } - } - - //----------------------------------------------------------------------- - public void test_parse_exactMatch_Denver() throws Exception { - ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter0(null).parseToBuilder(AMERICA_DENVER, pos); - assertEquals(pos.getIndex(), AMERICA_DENVER.length()); - assertParsed(dtb, TIME_ZONE_DENVER); - } - - public void test_parse_startStringMatch_Denver() throws Exception { - ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter0(null).parseToBuilder(AMERICA_DENVER + "OTHER", pos); - assertEquals(pos.getIndex(), AMERICA_DENVER.length()); - assertParsed(dtb, TIME_ZONE_DENVER); - } - - public void test_parse_midStringMatch_Denver() throws Exception { - ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHER" + AMERICA_DENVER + "OTHER", pos); - assertEquals(pos.getIndex(), 5 + AMERICA_DENVER.length()); - assertParsed(dtb, TIME_ZONE_DENVER); - } - - public void test_parse_endStringMatch_Denver() throws Exception { - ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHER" + AMERICA_DENVER, pos); - assertEquals(pos.getIndex(), 5 + AMERICA_DENVER.length()); - assertParsed(dtb, TIME_ZONE_DENVER); - } - - public void test_parse_partialMatch() throws Exception { - ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHERAmerica/Bogusville", pos); - assertEquals(pos.getErrorIndex(), 5); // TBD: -6 ? - assertEquals(dtb, null); - } - - //----------------------------------------------------------------------- - @DataProvider(name="zones") - Object[][] populateTestData() { - Set ids = ZoneRulesProvider.getAvailableZoneIds(); - Object[][] rtnval = new Object[ids.size()][]; - int i = 0; - for (String id : ids) { - rtnval[i++] = new Object[] { id, ZoneId.of(id) }; - } - return rtnval; - } - - @Test(dataProvider="zones") - public void test_parse_exactMatch(String parse, ZoneId expected) throws Exception { - ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter0(null).parseToBuilder(parse, pos); - assertEquals(pos.getIndex(), parse.length()); - assertParsed(dtb, expected); - } - - @Test(dataProvider="zones") - public void test_parse_startMatch(String parse, ZoneId expected) throws Exception { - String append = " OTHER"; - parse += append; - ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter0(null).parseToBuilder(parse, pos); - assertEquals(pos.getIndex(), parse.length() - append.length()); - assertParsed(dtb, expected); - } - - //----------------------------------------------------------------------- - public void test_parse_caseInsensitive() throws Exception { - DateTimeFormatter fmt = new DateTimeFormatterBuilder().appendZoneId().toFormatter(); - DateTimeFormatter fmtCI = new DateTimeFormatterBuilder().parseCaseInsensitive() - .appendZoneId() - .toFormatter(); - for (String zidStr : ZoneRulesProvider.getAvailableZoneIds()) { - ZoneId zid = ZoneId.of(zidStr); - assertEquals(fmt.parse(zidStr, Queries.zoneId()), zid); - assertEquals(fmtCI.parse(zidStr.toLowerCase(), Queries.zoneId()), zid); - assertEquals(fmtCI.parse(zidStr.toUpperCase(), Queries.zoneId()), zid); - ParsePosition pos = new ParsePosition(5); - assertEquals(fmtCI.parseToBuilder("OTHER" + zidStr.toLowerCase() + "OTHER", pos) - .query(Queries.zoneId()), zid); - assertEquals(pos.getIndex(), zidStr.length() + 5); - pos = new ParsePosition(5); - assertEquals(fmtCI.parseToBuilder("OTHER" + zidStr.toUpperCase() + "OTHER", pos) - .query(Queries.zoneId()), zid); - assertEquals(pos.getIndex(), zidStr.length() + 5); - } - } - - //----------------------------------------------------------------------- - /* - public void test_parse_endStringMatch_utc() throws Exception { - ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHERUTC", pos); - assertEquals(pos.getIndex(), 8); - assertParsed(dtb, ZoneOffset.UTC); - } - - public void test_parse_endStringMatch_utc_plus1() throws Exception { - ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHERUTC+01:00", pos); - assertEquals(pos.getIndex(), 14); - assertParsed(dtb, ZoneId.of("UTC+01:00")); - } - - //----------------------------------------------------------------------- - public void test_parse_midStringMatch_utc() throws Exception { - ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHERUTCOTHER", pos); - assertEquals(pos.getIndex(), 8); - assertParsed(dtb, ZoneOffset.UTC); - } - - public void test_parse_midStringMatch_utc_plus1() throws Exception { - ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter0(null).parseToBuilder("OTHERUTC+01:00OTHER", pos); - assertEquals(pos.getIndex(), 14); - assertParsed(dtb, ZoneId.of("UTC+01:00")); - } - */ - //----------------------------------------------------------------------- - public void test_toString_id() { - assertEquals(getFormatter0(null).toString(), "ZoneId()"); - } - - public void test_toString_text() { - assertEquals(getFormatter0(TextStyle.FULL).toString(), "ZoneText(FULL)"); - } - - private void assertParsed(DateTimeBuilder dtb, ZoneId expectedZone) { - assertEquals(dtb.query(ZoneId::from), expectedZone); - } - -} diff --git a/jdk/test/java/time/test/java/time/format/TestZoneOffsetParser.java b/jdk/test/java/time/test/java/time/format/TestZoneOffsetParser.java index 300411cb2eb..2c9065b93a4 100644 --- a/jdk/test/java/time/test/java/time/format/TestZoneOffsetParser.java +++ b/jdk/test/java/time/test/java/time/format/TestZoneOffsetParser.java @@ -65,7 +65,7 @@ import static org.testng.Assert.assertTrue; import java.text.ParsePosition; import java.time.ZoneOffset; -import java.time.format.DateTimeBuilder; +import java.time.temporal.TemporalAccessor; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -88,7 +88,7 @@ public class TestZoneOffsetParser extends AbstractTestPrinterParser { @Test(dataProvider="error") public void test_parse_error(String pattern, String noOffsetText, String text, int pos, Class expected) { try { - getFormatter(pattern, noOffsetText).parseToBuilder(text, new ParsePosition(pos)); + getFormatter(pattern, noOffsetText).parseUnresolved(text, new ParsePosition(pos)); } catch (RuntimeException ex) { assertTrue(expected.isInstance(ex)); } @@ -97,59 +97,59 @@ public class TestZoneOffsetParser extends AbstractTestPrinterParser { //----------------------------------------------------------------------- public void test_parse_exactMatch_UTC() throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("Z", pos); + TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("Z", pos); assertEquals(pos.getIndex(), 1); - assertParsed(dtb, ZoneOffset.UTC); + assertParsed(parsed, ZoneOffset.UTC); } public void test_parse_startStringMatch_UTC() throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("ZOTHER", pos); + TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("ZOTHER", pos); assertEquals(pos.getIndex(), 1); - assertParsed(dtb, ZoneOffset.UTC); + assertParsed(parsed, ZoneOffset.UTC); } public void test_parse_midStringMatch_UTC() throws Exception { ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("OTHERZOTHER", pos); + TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("OTHERZOTHER", pos); assertEquals(pos.getIndex(), 6); - assertParsed(dtb, ZoneOffset.UTC); + assertParsed(parsed, ZoneOffset.UTC); } public void test_parse_endStringMatch_UTC() throws Exception { ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("OTHERZ", pos); + TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("OTHERZ", pos); assertEquals(pos.getIndex(), 6); - assertParsed(dtb, ZoneOffset.UTC); + assertParsed(parsed, ZoneOffset.UTC); } //----------------------------------------------------------------------- public void test_parse_exactMatch_UTC_EmptyUTC() throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "").parseToBuilder("", pos); + TemporalAccessor parsed = getFormatter("+HH:MM:ss", "").parseUnresolved("", pos); assertEquals(pos.getIndex(), 0); - assertParsed(dtb, ZoneOffset.UTC); + assertParsed(parsed, ZoneOffset.UTC); } public void test_parse_startStringMatch_UTC_EmptyUTC() throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "").parseToBuilder("OTHER", pos); + TemporalAccessor parsed = getFormatter("+HH:MM:ss", "").parseUnresolved("OTHER", pos); assertEquals(pos.getIndex(), 0); - assertParsed(dtb, ZoneOffset.UTC); + assertParsed(parsed, ZoneOffset.UTC); } public void test_parse_midStringMatch_UTC_EmptyUTC() throws Exception { ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "").parseToBuilder("OTHEROTHER", pos); + TemporalAccessor parsed = getFormatter("+HH:MM:ss", "").parseUnresolved("OTHEROTHER", pos); assertEquals(pos.getIndex(), 5); - assertParsed(dtb, ZoneOffset.UTC); + assertParsed(parsed, ZoneOffset.UTC); } public void test_parse_endStringMatch_UTC_EmptyUTC() throws Exception { ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "").parseToBuilder("OTHER", pos); + TemporalAccessor parsed = getFormatter("+HH:MM:ss", "").parseUnresolved("OTHER", pos); assertEquals(pos.getIndex(), 5); - assertParsed(dtb, ZoneOffset.UTC); + assertParsed(parsed, ZoneOffset.UTC); } //----------------------------------------------------------------------- @@ -231,65 +231,65 @@ public class TestZoneOffsetParser extends AbstractTestPrinterParser { @Test(dataProvider="offsets") public void test_parse_exactMatch(String pattern, String parse, ZoneOffset expected) throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter(pattern, "Z").parseToBuilder(parse, pos); + TemporalAccessor parsed = getFormatter(pattern, "Z").parseUnresolved(parse, pos); assertEquals(pos.getIndex(), parse.length()); - assertParsed(dtb, expected); + assertParsed(parsed, expected); } @Test(dataProvider="offsets") public void test_parse_startStringMatch(String pattern, String parse, ZoneOffset expected) throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter(pattern, "Z").parseToBuilder(parse + ":OTHER", pos); + TemporalAccessor parsed = getFormatter(pattern, "Z").parseUnresolved(parse + ":OTHER", pos); assertEquals(pos.getIndex(), parse.length()); - assertParsed(dtb, expected); + assertParsed(parsed, expected); } @Test(dataProvider="offsets") public void test_parse_midStringMatch(String pattern, String parse, ZoneOffset expected) throws Exception { ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter(pattern, "Z").parseToBuilder("OTHER" + parse + ":OTHER", pos); + TemporalAccessor parsed = getFormatter(pattern, "Z").parseUnresolved("OTHER" + parse + ":OTHER", pos); assertEquals(pos.getIndex(), parse.length() + 5); - assertParsed(dtb, expected); + assertParsed(parsed, expected); } @Test(dataProvider="offsets") public void test_parse_endStringMatch(String pattern, String parse, ZoneOffset expected) throws Exception { ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter(pattern, "Z").parseToBuilder("OTHER" + parse, pos); + TemporalAccessor parsed = getFormatter(pattern, "Z").parseUnresolved("OTHER" + parse, pos); assertEquals(pos.getIndex(), parse.length() + 5); - assertParsed(dtb, expected); + assertParsed(parsed, expected); } @Test(dataProvider="offsets") public void test_parse_exactMatch_EmptyUTC(String pattern, String parse, ZoneOffset expected) throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter(pattern, "").parseToBuilder(parse, pos); + TemporalAccessor parsed = getFormatter(pattern, "").parseUnresolved(parse, pos); assertEquals(pos.getIndex(), parse.length()); - assertParsed(dtb, expected); + assertParsed(parsed, expected); } @Test(dataProvider="offsets") public void test_parse_startStringMatch_EmptyUTC(String pattern, String parse, ZoneOffset expected) throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter(pattern, "").parseToBuilder(parse + ":OTHER", pos); + TemporalAccessor parsed = getFormatter(pattern, "").parseUnresolved(parse + ":OTHER", pos); assertEquals(pos.getIndex(), parse.length()); - assertParsed(dtb, expected); + assertParsed(parsed, expected); } @Test(dataProvider="offsets") public void test_parse_midStringMatch_EmptyUTC(String pattern, String parse, ZoneOffset expected) throws Exception { ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter(pattern, "").parseToBuilder("OTHER" + parse + ":OTHER", pos); + TemporalAccessor parsed = getFormatter(pattern, "").parseUnresolved("OTHER" + parse + ":OTHER", pos); assertEquals(pos.getIndex(), parse.length() + 5); - assertParsed(dtb, expected); + assertParsed(parsed, expected); } @Test(dataProvider="offsets") public void test_parse_endStringMatch_EmptyUTC(String pattern, String parse, ZoneOffset expected) throws Exception { ParsePosition pos = new ParsePosition(5); - DateTimeBuilder dtb = getFormatter(pattern, "").parseToBuilder("OTHER" + parse, pos); + TemporalAccessor parsed = getFormatter(pattern, "").parseUnresolved("OTHER" + parse, pos); assertEquals(pos.getIndex(), parse.length() + 5); - assertParsed(dtb, expected); + assertParsed(parsed, expected); } //----------------------------------------------------------------------- @@ -322,9 +322,9 @@ public class TestZoneOffsetParser extends AbstractTestPrinterParser { @Test(dataProvider="bigOffsets") public void test_parse_bigOffsets(String pattern, String parse, long offsetSecs) throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter(pattern, "").parseToBuilder(parse, pos); + TemporalAccessor parsed = getFormatter(pattern, "").parseUnresolved(parse, pos); assertEquals(pos.getIndex(), parse.length()); - assertEquals(dtb.getLong(OFFSET_SECONDS), offsetSecs); + assertEquals(parsed.getLong(OFFSET_SECONDS), offsetSecs); } //----------------------------------------------------------------------- @@ -393,8 +393,9 @@ public class TestZoneOffsetParser extends AbstractTestPrinterParser { @Test(dataProvider="badOffsets") public void test_parse_invalid(String pattern, String parse, int expectedPosition) throws Exception { ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter(pattern, "Z").parseToBuilder(parse, pos); + TemporalAccessor parsed = getFormatter(pattern, "Z").parseUnresolved(parse, pos); assertEquals(pos.getErrorIndex(), expectedPosition); + assertEquals(parsed, null); } //----------------------------------------------------------------------- @@ -403,41 +404,41 @@ public class TestZoneOffsetParser extends AbstractTestPrinterParser { public void test_parse_caseSensitiveUTC_matchedCase() throws Exception { setCaseSensitive(true); ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("Z", pos); + TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("Z", pos); assertEquals(pos.getIndex(), 1); - assertParsed(dtb, ZoneOffset.UTC); + assertParsed(parsed, ZoneOffset.UTC); } public void test_parse_caseSensitiveUTC_unmatchedCase() throws Exception { setCaseSensitive(true); ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("z", pos); + TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("z", pos); assertEquals(pos.getErrorIndex(), 0); - assertEquals(dtb, null); + assertEquals(parsed, null); } public void test_parse_caseInsensitiveUTC_matchedCase() throws Exception { setCaseSensitive(false); ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("Z", pos); + TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("Z", pos); assertEquals(pos.getIndex(), 1); - assertParsed(dtb, ZoneOffset.UTC); + assertParsed(parsed, ZoneOffset.UTC); } public void test_parse_caseInsensitiveUTC_unmatchedCase() throws Exception { setCaseSensitive(false); ParsePosition pos = new ParsePosition(0); - DateTimeBuilder dtb = getFormatter("+HH:MM:ss", "Z").parseToBuilder("z", pos); + TemporalAccessor parsed = getFormatter("+HH:MM:ss", "Z").parseUnresolved("z", pos); assertEquals(pos.getIndex(), 1); - assertParsed(dtb, ZoneOffset.UTC); + assertParsed(parsed, ZoneOffset.UTC); } - private void assertParsed(DateTimeBuilder dtb, ZoneOffset expectedOffset) { + private void assertParsed(TemporalAccessor parsed, ZoneOffset expectedOffset) { if (expectedOffset == null) { - assertEquals(dtb, null); + assertEquals(parsed, null); } else { - assertEquals(dtb.getFieldValueMap().size(), 1); - assertEquals(dtb.getLong(OFFSET_SECONDS), (long) expectedOffset.getTotalSeconds()); + assertEquals(parsed.isSupported(OFFSET_SECONDS), true); + assertEquals(parsed.getLong(OFFSET_SECONDS), (long) expectedOffset.getTotalSeconds()); } } diff --git a/jdk/test/java/time/test/java/time/format/TestZoneOffsetPrinter.java b/jdk/test/java/time/test/java/time/format/TestZoneOffsetPrinter.java index e4250900b05..c84ad05a479 100644 --- a/jdk/test/java/time/test/java/time/format/TestZoneOffsetPrinter.java +++ b/jdk/test/java/time/test/java/time/format/TestZoneOffsetPrinter.java @@ -59,12 +59,10 @@ */ package test.java.time.format; -import static java.time.temporal.ChronoField.OFFSET_SECONDS; import static org.testng.Assert.assertEquals; import java.time.DateTimeException; import java.time.ZoneOffset; -import java.time.format.DateTimeBuilder; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -150,25 +148,25 @@ public class TestZoneOffsetPrinter extends AbstractTestPrinterParser { } @Test(dataProvider="offsets") - public void test_print(String pattern, String expected, ZoneOffset offset) throws Exception { + public void test_format(String pattern, String expected, ZoneOffset offset) throws Exception { buf.append("EXISTING"); - getFormatter(pattern, "NO-OFFSET").printTo(new DateTimeBuilder(OFFSET_SECONDS, offset.getTotalSeconds()), buf); + getFormatter(pattern, "NO-OFFSET").formatTo(offset, buf); assertEquals(buf.toString(), "EXISTING" + expected); } @Test(dataProvider="offsets") public void test_toString(String pattern, String expected, ZoneOffset offset) throws Exception { - assertEquals(getFormatter(pattern, "NO-OFFSET").toString(), "Offset('NO-OFFSET'," + pattern + ")"); + assertEquals(getFormatter(pattern, "NO-OFFSET").toString(), "Offset(" + pattern + ",'NO-OFFSET')"); } //----------------------------------------------------------------------- @Test(expectedExceptions=DateTimeException.class) public void test_print_emptyCalendrical() throws Exception { - getFormatter("+HH:MM:ss", "Z").printTo(EMPTY_DTA, buf); + getFormatter("+HH:MM:ss", "Z").formatTo(EMPTY_DTA, buf); } public void test_print_emptyAppendable() throws Exception { - getFormatter("+HH:MM:ss", "Z").printTo(new DateTimeBuilder(OFFSET_SECONDS, OFFSET_0130.getTotalSeconds()), buf); + getFormatter("+HH:MM:ss", "Z").formatTo(OFFSET_0130, buf); assertEquals(buf.toString(), "+01:30"); } diff --git a/jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java b/jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java index 0f58634b655..a7d63e8c47b 100644 --- a/jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java +++ b/jdk/test/java/time/test/java/time/format/TestZoneTextPrinterParser.java @@ -23,7 +23,10 @@ package test.java.time.format; +import java.text.DateFormatSymbols; +import java.util.Arrays; import java.util.Date; +import java.util.HashSet; import java.util.Locale; import java.util.Random; import java.util.Set; @@ -32,12 +35,14 @@ import java.util.TimeZone; import java.time.ZonedDateTime; import java.time.ZoneId; import java.time.temporal.ChronoField; +import java.time.temporal.Queries; import java.time.format.DateTimeFormatSymbols; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.TextStyle; import java.time.zone.ZoneRulesProvider; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; @@ -65,6 +70,12 @@ public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { zdt = zdt.withDayOfYear(r.nextInt(365) + 1) .with(ChronoField.SECOND_OF_DAY, r.nextInt(86400)); for (String zid : zids) { + if (zid.equals("ROC") || + zid.startsWith("UTC") || + zid.startsWith("GMT") || zid.startsWith("Etc/GMT")) { + // UTC, GMT are treated as zone offset + continue; // TBD: match jdk behavior? + } zdt = zdt.withZoneSameLocal(ZoneId.of(zid)); TimeZone tz = TimeZone.getTimeZone(zid); boolean isDST = tz.inDaylightTime(new Date(zdt.toInstant().toEpochMilli())); @@ -79,10 +90,9 @@ public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { } private void printText(Locale locale, ZonedDateTime zdt, TextStyle style, String expected) { - String result = getFormatter(locale, style).print(zdt); + String result = getFormatter(locale, style).format(zdt); if (!result.equals(expected)) { - if (result.equals("FooLocation") || // from rules provider test if same vm - result.startsWith("Etc/GMT") || result.equals("ROC")) { // TBD: match jdk behavior? + if (result.equals("FooLocation")) { // from rules provider test if same vm return; } System.out.println("----------------"); @@ -92,4 +102,117 @@ public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { } assertEquals(result, expected); } + + public void test_ParseText() { + Locale[] locales = new Locale[] { Locale.ENGLISH, Locale.JAPANESE, Locale.FRENCH }; + Set zids = ZoneRulesProvider.getAvailableZoneIds(); + for (Locale locale : locales) { + parseText(zids, locale, TextStyle.FULL, false); + parseText(zids, locale, TextStyle.FULL, true); + parseText(zids, locale, TextStyle.SHORT, false); + parseText(zids, locale, TextStyle.SHORT, true); + } + } + + private static Set preferred = new HashSet<>(Arrays.asList(new ZoneId[] { + ZoneId.of("EST"), + ZoneId.of("Asia/Taipei"), + ZoneId.of("CET"), + })); + + private static Set preferred_s = new HashSet<>(Arrays.asList(new ZoneId[] { + ZoneId.of("EST"), + ZoneId.of("CET"), + ZoneId.of("Australia/South"), + ZoneId.of("Australia/West"), + ZoneId.of("Asia/Shanghai"), + })); + + private static Set none = new HashSet<>(); + + @DataProvider(name="preferredZones") + Object[][] data_preferredZones() { + return new Object[][] { + {"America/New_York", "Eastern Standard Time", none, Locale.ENGLISH, TextStyle.FULL}, + {"EST", "Eastern Standard Time", preferred, Locale.ENGLISH, TextStyle.FULL}, + {"Europe/Paris", "Central European Time", none, Locale.ENGLISH, TextStyle.FULL}, + {"CET", "Central European Time", preferred, Locale.ENGLISH, TextStyle.FULL}, + {"Asia/Shanghai", "China Standard Time", none, Locale.ENGLISH, TextStyle.FULL}, + {"Asia/Taipei", "China Standard Time", preferred, Locale.ENGLISH, TextStyle.FULL}, + {"America/Chicago", "CST", none, Locale.ENGLISH, TextStyle.SHORT}, + {"Asia/Taipei", "CST", preferred, Locale.ENGLISH, TextStyle.SHORT}, + {"Australia/South", "CST", preferred_s, Locale.ENGLISH, TextStyle.SHORT}, + {"America/Chicago", "CDT", none, Locale.ENGLISH, TextStyle.SHORT}, + {"Asia/Shanghai", "CDT", preferred_s, Locale.ENGLISH, TextStyle.SHORT}, + }; + } + + @Test(dataProvider="preferredZones") + public void test_ParseText(String expected, String text, Set preferred, Locale locale, TextStyle style) { + DateTimeFormatter fmt = new DateTimeFormatterBuilder().appendZoneText(style, preferred) + .toFormatter(locale) + .withSymbols(DateTimeFormatSymbols.of(locale)); + + String ret = fmt.parse(text, Queries.zone()).getId(); + + System.out.printf("[%-5s %s] %24s -> %s(%s)%n", + locale.toString(), + style == TextStyle.FULL ? " full" :"short", + text, ret, expected); + + assertEquals(ret, expected); + + } + + + private void parseText(Set zids, Locale locale, TextStyle style, boolean ci) { + System.out.println("---------------------------------------"); + DateTimeFormatter fmt = getFormatter(locale, style, ci); + for (String[] names : new DateFormatSymbols(locale).getZoneStrings()) { + if (!zids.contains(names[0])) { + continue; + } + String zid = names[0]; + String expected = ZoneName.toZid(zid, locale); + + parse(fmt, zid, expected, zid, locale, style, ci); + int i = style == TextStyle.FULL ? 1 : 2; + for (; i < names.length; i += 2) { + parse(fmt, zid, expected, names[i], locale, style, ci); + } + } + } + + private void parse(DateTimeFormatter fmt, + String zid, String expected, String text, + Locale locale, TextStyle style, boolean ci) { + if (ci) { + text = text.toUpperCase(); + } + String ret = fmt.parse(text, Queries.zone()).getId(); + // TBD: need an excluding list + // assertEquals(...); + if (ret.equals(expected) || + ret.equals(zid) || + ret.equals(ZoneName.toZid(zid)) || + ret.equals(expected.replace("UTC", "UCT"))) { + return; + } + System.out.printf("[%-5s %s %s %16s] %24s -> %s(%s)%n", + locale.toString(), + ci ? "ci" : " ", + style == TextStyle.FULL ? " full" :"short", + zid, text, ret, expected); + } + + private DateTimeFormatter getFormatter(Locale locale, TextStyle style, boolean ci) { + DateTimeFormatterBuilder db = new DateTimeFormatterBuilder(); + if (ci) { + db = db.parseCaseInsensitive(); + } + return db.appendZoneText(style) + .toFormatter(locale) + .withSymbols(DateTimeFormatSymbols.of(locale)); + } + } diff --git a/jdk/test/java/time/test/java/time/format/ZoneName.java b/jdk/test/java/time/test/java/time/format/ZoneName.java new file mode 100644 index 00000000000..4ae5b43f30b --- /dev/null +++ b/jdk/test/java/time/test/java/time/format/ZoneName.java @@ -0,0 +1,780 @@ +/* + * Copyright (c) 2013, 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. + */ + +package test.java.time.format; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +class ZoneName { + + public static String toZid(String zid, Locale locale) { + String mzone = zidToMzone.get(zid); + if (mzone == null && aliases.containsKey(zid)) { + zid = aliases.get(zid); + mzone = zidToMzone.get(zid); + } + if (mzone != null) { + Map map = mzoneToZidL.get(mzone); + if (map != null && map.containsKey(locale.getCountry())) { + zid = map.get(locale.getCountry()); + } else { + zid = mzoneToZid.get(mzone); + } + } + return toZid(zid); + } + + public static String toZid(String zid) { + if (aliases.containsKey(zid)) { + return aliases.get(zid); + } + return zid; + } + + private static final String[] zidMap = new String[] { + "Asia/Bangkok", "Indochina", "Asia/Saigon", + "Pacific/Pago_Pago", "Samoa", "Pacific/Apia", + "Africa/Blantyre", "Africa_Central", "Africa/Maputo", + "America/Argentina/San_Juan", "Argentina", "America/Buenos_Aires", + "America/Cancun", "America_Central", "America/Chicago", + "Pacific/Nauru", "Nauru", "Pacific/Nauru", + "America/Atikokan", "America_Eastern", "America/New_York", + "Africa/Asmara", "Africa_Eastern", "Africa/Nairobi", + "Europe/Berlin", "Europe_Central", "Europe/Paris", + "Asia/Kolkata", "India", "Asia/Calcutta", + "Australia/Darwin", "Australia_Central", "Australia/Adelaide", + "America/Guayaquil", "Ecuador", "America/Guayaquil", + "Europe/Vienna", "Europe_Central", "Europe/Paris", + "Atlantic/St_Helena", "GMT", "Atlantic/Reykjavik", + "Europe/London", "GMT", "Atlantic/Reykjavik", + "Europe/Moscow", "Moscow", "Europe/Moscow", + "America/St_Vincent", "Atlantic", "America/Halifax", + "America/Bogota", "Colombia", "America/Bogota", + "America/Marigot", "Atlantic", "America/Halifax", + "Europe/Sarajevo", "Europe_Central", "Europe/Paris", + "America/Hermosillo", "America_Mountain", "America/Denver", + "America/Winnipeg", "America_Central", "America/Chicago", + "America/Rainy_River", "America_Central", "America/Chicago", + "Indian/Mahe", "Seychelles", "Indian/Mahe", + "Africa/Freetown", "GMT", "Atlantic/Reykjavik", + "America/Grand_Turk", "America_Eastern", "America/New_York", + "America/Argentina/Ushuaia", "Argentina", "America/Buenos_Aires", + "Atlantic/Azores", "Azores", "Atlantic/Azores", + "Asia/Harbin", "China", "Asia/Shanghai", + "America/Cuiaba", "Amazon", "America/Manaus", + "Asia/Bahrain", "Arabian", "Asia/Riyadh", + "Asia/Katmandu", "Nepal", "Asia/Katmandu", + "Pacific/Galapagos", "Galapagos", "Pacific/Galapagos", + "Asia/Brunei", "Brunei", "Asia/Brunei", + "Africa/Kigali", "Africa_Central", "Africa/Maputo", + "Asia/Makassar", "Indonesia_Central", "Asia/Makassar", + "Africa/Maputo", "Africa_Central", "Africa/Maputo", + "Asia/Kamchatka", "Magadan", "Asia/Magadan", + "Atlantic/Faroe", "Europe_Western", "Atlantic/Canary", + "America/El_Salvador", "America_Central", "America/Chicago", + "Asia/Saigon", "Indochina", "Asia/Saigon", + "Africa/Kinshasa", "Africa_Western", "Africa/Lagos", + "Europe/Oslo", "Europe_Central", "Europe/Paris", + "Asia/Hong_Kong", "Hong_Kong", "Asia/Hong_Kong", + "Pacific/Midway", "Samoa", "Pacific/Apia", + "Africa/Douala", "Africa_Western", "Africa/Lagos", + "Europe/San_Marino", "Europe_Central", "Europe/Paris", + "Pacific/Chuuk", "Truk", "Pacific/Truk", + "Africa/Gaborone", "Africa_Central", "Africa/Maputo", + "Africa/Tunis", "Europe_Central", "Europe/Paris", + "Africa/Khartoum", "Africa_Eastern", "Africa/Nairobi", + "Europe/Isle_of_Man", "GMT", "Atlantic/Reykjavik", + "Europe/Skopje", "Europe_Central", "Europe/Paris", + "America/Merida", "America_Central", "America/Chicago", + "Antarctica/DumontDUrville", "DumontDUrville", "Antarctica/DumontDUrville", + "Atlantic/Reykjavik", "GMT", "Atlantic/Reykjavik", + "Indian/Mauritius", "Mauritius", "Indian/Mauritius", + "Africa/Malabo", "Africa_Western", "Africa/Lagos", + "Africa/Juba", "Africa_Eastern", "Africa/Nairobi", + "America/Resolute", "America_Central", "America/Chicago", + "Africa/Abidjan", "GMT", "Atlantic/Reykjavik", + "Antarctica/McMurdo", "New_Zealand", "Pacific/Auckland", + "Asia/Thimphu", "Bhutan", "Asia/Thimphu", + "Europe/Zaporozhye", "Europe_Eastern", "Europe/Bucharest", + "Antarctica/Davis", "Davis", "Antarctica/Davis", + "Indian/Antananarivo", "Africa_Eastern", "Africa/Nairobi", + "Africa/Harare", "Africa_Central", "Africa/Maputo", + "Pacific/Marquesas", "Marquesas", "Pacific/Marquesas", + "Africa/Tripoli", "Europe_Eastern", "Europe/Bucharest", + "America/North_Dakota/Beulah", "America_Central", "America/Chicago", + "America/Buenos_Aires", "Argentina", "America/Buenos_Aires", + "America/Tortola", "Atlantic", "America/Halifax", + "Asia/Kuwait", "Arabian", "Asia/Riyadh", + "Europe/Rome", "Europe_Central", "Europe/Paris", + "America/Eirunepe", "Amazon", "America/Manaus", + "Australia/Hobart", "Australia_Eastern", "Australia/Sydney", + "America/Thule", "Atlantic", "America/Halifax", + "Asia/Beirut", "Europe_Eastern", "Europe/Bucharest", + "America/Bahia_Banderas", "America_Central", "America/Chicago", + "Africa/Dar_es_Salaam", "Africa_Eastern", "Africa/Nairobi", + "America/Argentina/Tucuman", "Argentina", "America/Buenos_Aires", + "America/Paramaribo", "Suriname", "America/Paramaribo", + "Africa/Kampala", "Africa_Eastern", "Africa/Nairobi", + "Pacific/Port_Moresby", "Papua_New_Guinea", "Pacific/Port_Moresby", + "America/Mendoza", "Argentina", "America/Buenos_Aires", + "Asia/Dushanbe", "Tajikistan", "Asia/Dushanbe", + "Asia/Qyzylorda", "Kazakhstan_Eastern", "Asia/Almaty", + "Antarctica/Vostok", "Vostok", "Antarctica/Vostok", + "Pacific/Majuro", "Marshall_Islands", "Pacific/Majuro", + "Asia/Tehran", "Iran", "Asia/Tehran", + "Asia/Hovd", "Hovd", "Asia/Hovd", + "Antarctica/Rothera", "Rothera", "Antarctica/Rothera", + "Africa/Brazzaville", "Africa_Western", "Africa/Lagos", + "Europe/Tirane", "Europe_Central", "Europe/Paris", + "Asia/Urumqi", "China", "Asia/Shanghai", + "Asia/Krasnoyarsk", "Krasnoyarsk", "Asia/Krasnoyarsk", + "America/Tegucigalpa", "America_Central", "America/Chicago", + "Asia/Vientiane", "Indochina", "Asia/Saigon", + "Asia/Pontianak", "Indonesia_Western", "Asia/Jakarta", + "America/Bahia", "Brasilia", "America/Sao_Paulo", + "Asia/Choibalsan", "Choibalsan", "Asia/Choibalsan", + "America/Regina", "America_Central", "America/Chicago", + "Africa/Cairo", "Europe_Eastern", "Europe/Bucharest", + "Asia/Irkutsk", "Irkutsk", "Asia/Irkutsk", + "Europe/Luxembourg", "Europe_Central", "Europe/Paris", + "America/St_Kitts", "Atlantic", "America/Halifax", + "America/Manaus", "Amazon", "America/Manaus", + "America/Noronha", "Noronha", "America/Noronha", + "Pacific/Gambier", "Gambier", "Pacific/Gambier", + "America/Edmonton", "America_Mountain", "America/Denver", + "Pacific/Palau", "Palau", "Pacific/Palau", + "America/Lower_Princes", "Atlantic", "America/Halifax", + "Africa/Ouagadougou", "GMT", "Atlantic/Reykjavik", + "Asia/Yerevan", "Armenia", "Asia/Yerevan", + "America/Montevideo", "Uruguay", "America/Montevideo", + "Europe/Minsk", "Europe_Eastern", "Europe/Bucharest", + "Europe/Amsterdam", "Europe_Central", "Europe/Paris", + "Pacific/Efate", "Vanuatu", "Pacific/Efate", + "Asia/Manila", "Philippines", "Asia/Manila", + "America/Dawson", "America_Pacific", "America/Los_Angeles", + "America/Argentina/Cordoba", "Argentina", "America/Buenos_Aires", + "Australia/Melbourne", "Australia_Eastern", "Australia/Sydney", + "Asia/Rangoon", "Myanmar", "Asia/Rangoon", + "America/Los_Angeles", "America_Pacific", "America/Los_Angeles", + "Africa/Casablanca", "Europe_Western", "Atlantic/Canary", + "Africa/Porto-Novo", "Africa_Western", "Africa/Lagos", + "Asia/Macau", "China", "Asia/Shanghai", + "America/Boa_Vista", "Amazon", "America/Manaus", + "Europe/Guernsey", "GMT", "Atlantic/Reykjavik", + "Africa/Monrovia", "GMT", "Atlantic/Reykjavik", + "America/Godthab", "Greenland_Western", "America/Godthab", + "Africa/Ceuta", "Europe_Central", "Europe/Paris", + "Asia/Oral", "Kazakhstan_Western", "Asia/Aqtobe", + "America/Yakutat", "Alaska", "America/Juneau", + "Indian/Mayotte", "Africa_Eastern", "Africa/Nairobi", + "America/Denver", "America_Mountain", "America/Denver", + "America/New_York", "America_Eastern", "America/New_York", + "Pacific/Rarotonga", "Cook", "Pacific/Rarotonga", + "America/Louisville", "America_Eastern", "America/New_York", + "Africa/El_Aaiun", "Europe_Western", "Atlantic/Canary", + "Africa/Sao_Tome", "GMT", "Atlantic/Reykjavik", + "Pacific/Fiji", "Fiji", "Pacific/Fiji", + "Asia/Damascus", "Europe_Eastern", "Europe/Bucharest", + "Asia/Ulaanbaatar", "Mongolia", "Asia/Ulaanbaatar", + "America/Cayman", "America_Eastern", "America/New_York", + "America/Tijuana", "America_Pacific", "America/Los_Angeles", + "Atlantic/Bermuda", "Atlantic", "America/Halifax", + "Australia/Sydney", "Australia_Eastern", "Australia/Sydney", + "Asia/Aden", "Arabian", "Asia/Riyadh", + "Australia/Eucla", "Australia_CentralWestern", "Australia/Eucla", + "America/Indiana/Petersburg", "America_Eastern", "America/New_York", + "America/Panama", "America_Eastern", "America/New_York", + "Europe/Istanbul", "Europe_Eastern", "Europe/Bucharest", + "America/Kralendijk", "Atlantic", "America/Halifax", + "America/Catamarca", "Argentina", "America/Buenos_Aires", + "America/Nassau", "America_Eastern", "America/New_York", + "Europe/Paris", "Europe_Central", "Europe/Paris", + "Asia/Jakarta", "Indonesia_Western", "Asia/Jakarta", + "Australia/Lindeman", "Australia_Eastern", "Australia/Sydney", + "America/Sao_Paulo", "Brasilia", "America/Sao_Paulo", + "America/Juneau", "Alaska", "America/Juneau", + "America/Grenada", "Atlantic", "America/Halifax", + "America/Cayenne", "French_Guiana", "America/Cayenne", + "Antarctica/Casey", "Australia_Western", "Australia/Perth", + "Africa/Algiers", "Europe_Central", "Europe/Paris", + "America/Miquelon", "Pierre_Miquelon", "America/Miquelon", + "Asia/Tokyo", "Japan", "Asia/Tokyo", + "Africa/Windhoek", "Africa_Western", "Africa/Lagos", + "Africa/Bujumbura", "Africa_Central", "Africa/Maputo", + "America/Guatemala", "America_Central", "America/Chicago", + "Africa/Dakar", "GMT", "Atlantic/Reykjavik", + "Asia/Bishkek", "Kyrgystan", "Asia/Bishkek", + "America/Guadeloupe", "Atlantic", "America/Halifax", + "Africa/Ndjamena", "Africa_Western", "Africa/Lagos", + "Europe/Simferopol", "Europe_Eastern", "Europe/Bucharest", + "America/Santa_Isabel", "America_Pacific", "America/Los_Angeles", + "Asia/Dubai", "Gulf", "Asia/Dubai", + "America/Maceio", "Brasilia", "America/Sao_Paulo", + "America/Anchorage", "Alaska", "America/Juneau", + "Australia/Currie", "Australia_Eastern", "Australia/Sydney", + "Africa/Djibouti", "Africa_Eastern", "Africa/Nairobi", + "Europe/Budapest", "Europe_Central", "Europe/Paris", + "America/Argentina/Salta", "Argentina", "America/Buenos_Aires", + "Asia/Calcutta", "India", "Asia/Calcutta", + "America/Indiana/Winamac", "America_Eastern", "America/New_York", + "Asia/Yekaterinburg", "Yekaterinburg", "Asia/Yekaterinburg", + "America/Santiago", "Chile", "America/Santiago", + "Asia/Aqtobe", "Kazakhstan_Western", "Asia/Aqtobe", + "Asia/Dili", "East_Timor", "Asia/Dili", + "America/Detroit", "America_Eastern", "America/New_York", + "Africa/Libreville", "Africa_Western", "Africa/Lagos", + "Pacific/Ponape", "Ponape", "Pacific/Ponape", + "Pacific/Wallis", "Wallis", "Pacific/Wallis", + "Asia/Vladivostok", "Vladivostok", "Asia/Vladivostok", + "Africa/Lubumbashi", "Africa_Central", "Africa/Maputo", + "Africa/Asmera", "Africa_Eastern", "Africa/Nairobi", + "Pacific/Guam", "Chamorro", "Pacific/Saipan", + "America/Chicago", "America_Central", "America/Chicago", + "America/Swift_Current", "America_Central", "America/Chicago", + "America/Coral_Harbour", "America_Eastern", "America/New_York", + "America/Cambridge_Bay", "America_Mountain", "America/Denver", + "America/Costa_Rica", "America_Central", "America/Chicago", + "America/Curacao", "Atlantic", "America/Halifax", + "America/Recife", "Brasilia", "America/Sao_Paulo", + "Africa/Bangui", "Africa_Western", "Africa/Lagos", + "America/Cordoba", "Argentina", "America/Buenos_Aires", + "Asia/Baghdad", "Arabian", "Asia/Riyadh", + "America/Shiprock", "America_Mountain", "America/Denver", + "America/Glace_Bay", "Atlantic", "America/Halifax", + "America/North_Dakota/Center", "America_Central", "America/Chicago", + "Europe/Stockholm", "Europe_Central", "Europe/Paris", + "America/Halifax", "Atlantic", "America/Halifax", + "Atlantic/Canary", "Europe_Western", "Atlantic/Canary", + "Europe/Volgograd", "Volgograd", "Europe/Volgograd", + "America/Moncton", "Atlantic", "America/Halifax", + "Pacific/Tongatapu", "Tonga", "Pacific/Tongatapu", + "America/Argentina/Buenos_Aires", "Argentina", "America/Buenos_Aires", + "Asia/Samarkand", "Uzbekistan", "Asia/Tashkent", + "Pacific/Apia", "Samoa", "Pacific/Apia", + "America/Sitka", "Alaska", "America/Juneau", + "Europe/Warsaw", "Europe_Central", "Europe/Paris", + "Africa/Accra", "GMT", "Atlantic/Reykjavik", + "Europe/Bratislava", "Europe_Central", "Europe/Paris", + "Europe/Zurich", "Europe_Central", "Europe/Paris", + "Indian/Reunion", "Reunion", "Indian/Reunion", + "America/Mazatlan", "America_Mountain", "America/Denver", + "Pacific/Tarawa", "Gilbert_Islands", "Pacific/Tarawa", + "America/Indiana/Knox", "America_Central", "America/Chicago", + "Asia/Tbilisi", "Georgia", "Asia/Tbilisi", + "Asia/Novosibirsk", "Novosibirsk", "Asia/Novosibirsk", + "Atlantic/Faeroe", "Europe_Western", "Atlantic/Canary", + "Africa/Bissau", "GMT", "Atlantic/Reykjavik", + "Asia/Amman", "Europe_Eastern", "Europe/Bucharest", + "Africa/Lagos", "Africa_Western", "Africa/Lagos", + "Africa/Banjul", "GMT", "Atlantic/Reykjavik", + "America/Araguaina", "Brasilia", "America/Sao_Paulo", + "America/Nipigon", "America_Eastern", "America/New_York", + "Europe/Vilnius", "Europe_Eastern", "Europe/Bucharest", + "America/Montserrat", "Atlantic", "America/Halifax", + "Asia/Baku", "Azerbaijan", "Asia/Baku", + "Africa/Lusaka", "Africa_Central", "Africa/Maputo", + "Europe/Uzhgorod", "Europe_Eastern", "Europe/Bucharest", + "America/Argentina/Rio_Gallegos", "Argentina", "America/Buenos_Aires", + "America/Blanc-Sablon", "Atlantic", "America/Halifax", + "Asia/Kabul", "Afghanistan", "Asia/Kabul", + "America/Jamaica", "America_Eastern", "America/New_York", + "Europe/Vatican", "Europe_Central", "Europe/Paris", + "Africa/Nouakchott", "GMT", "Atlantic/Reykjavik", + "Africa/Addis_Ababa", "Africa_Eastern", "Africa/Nairobi", + "Europe/Athens", "Europe_Eastern", "Europe/Bucharest", + "Atlantic/Madeira", "Europe_Western", "Atlantic/Canary", + "America/Thunder_Bay", "America_Eastern", "America/New_York", + "Europe/Brussels", "Europe_Central", "Europe/Paris", + "Africa/Luanda", "Africa_Western", "Africa/Lagos", + "Africa/Mogadishu", "Africa_Eastern", "Africa/Nairobi", + "America/Matamoros", "America_Central", "America/Chicago", + "Pacific/Norfolk", "Norfolk", "Pacific/Norfolk", + "America/Scoresbysund", "Greenland_Eastern", "America/Scoresbysund", + "America/Indianapolis", "America_Eastern", "America/New_York", + "Pacific/Pitcairn", "Pitcairn", "Pacific/Pitcairn", + "Asia/Singapore", "Singapore", "Asia/Singapore", + "America/Port-au-Prince", "America_Eastern", "America/New_York", + "Pacific/Honolulu", "Hawaii_Aleutian", "Pacific/Honolulu", + "Antarctica/Syowa", "Syowa", "Antarctica/Syowa", + "Atlantic/Cape_Verde", "Cape_Verde", "Atlantic/Cape_Verde", + "America/Asuncion", "Paraguay", "America/Asuncion", + "America/Martinique", "Atlantic", "America/Halifax", + "Europe/Gibraltar", "Europe_Central", "Europe/Paris", + "Africa/Lome", "GMT", "Atlantic/Reykjavik", + "Australia/Lord_Howe", "Lord_Howe", "Australia/Lord_Howe", + "America/Argentina/La_Rioja", "Argentina", "America/Buenos_Aires", + "Europe/Jersey", "GMT", "Atlantic/Reykjavik", + "America/Kentucky/Louisville", "America_Eastern", "America/New_York", + "America/Monterrey", "America_Central", "America/Chicago", + "Europe/Belgrade", "Europe_Central", "Europe/Paris", + "Asia/Gaza", "Europe_Eastern", "Europe/Bucharest", + "Asia/Ho_Chi_Minh", "Indochina", "Asia/Saigon", + "Europe/Prague", "Europe_Central", "Europe/Paris", + "Indian/Christmas", "Christmas", "Indian/Christmas", + "Pacific/Fakaofo", "Tokelau", "Pacific/Fakaofo", + "America/Dominica", "Atlantic", "America/Halifax", + "America/Ojinaga", "America_Mountain", "America/Denver", + "Asia/Colombo", "India", "Asia/Calcutta", + "Asia/Nicosia", "Europe_Eastern", "Europe/Bucharest", + "Europe/Copenhagen", "Europe_Central", "Europe/Paris", + "America/Creston", "America_Mountain", "America/Denver", + "Asia/Ashgabat", "Turkmenistan", "Asia/Ashgabat", + "Asia/Shanghai", "China", "Asia/Shanghai", + "Pacific/Easter", "Easter", "Pacific/Easter", + "Africa/Maseru", "Africa_Southern", "Africa/Johannesburg", + "America/La_Paz", "Bolivia", "America/La_Paz", + "Pacific/Truk", "Truk", "Pacific/Truk", + "America/Inuvik", "America_Mountain", "America/Denver", + "America/Belem", "Brasilia", "America/Sao_Paulo", + "Asia/Hebron", "Europe_Eastern", "Europe/Bucharest", + "Asia/Jerusalem", "Israel", "Asia/Jerusalem", + "America/Belize", "America_Central", "America/Chicago", + "America/Rio_Branco", "Amazon", "America/Manaus", + "America/Dawson_Creek", "America_Mountain", "America/Denver", + "America/Anguilla", "Atlantic", "America/Halifax", + "America/Port_of_Spain", "Atlantic", "America/Halifax", + "America/St_Barthelemy", "Atlantic", "America/Halifax", + "America/Indiana/Marengo", "America_Eastern", "America/New_York", + "America/St_Johns", "Newfoundland", "America/St_Johns", + "Asia/Jayapura", "Indonesia_Eastern", "Asia/Jayapura", + "Europe/Riga", "Europe_Eastern", "Europe/Bucharest", + "America/Phoenix", "America_Mountain", "America/Denver", + "America/Boise", "America_Mountain", "America/Denver", + "Pacific/Kiritimati", "Line_Islands", "Pacific/Kiritimati", + "Africa/Johannesburg", "Africa_Southern", "Africa/Johannesburg", + "America/Pangnirtung", "America_Eastern", "America/New_York", + "America/Toronto", "America_Eastern", "America/New_York", + "Australia/Brisbane", "Australia_Eastern", "Australia/Sydney", + "Asia/Aqtau", "Kazakhstan_Western", "Asia/Aqtobe", + "America/Vancouver", "America_Pacific", "America/Los_Angeles", + "Africa/Mbabane", "Africa_Southern", "Africa/Johannesburg", + "Europe/Vaduz", "Europe_Central", "Europe/Paris", + "Asia/Karachi", "Pakistan", "Asia/Karachi", + "Asia/Riyadh", "Arabian", "Asia/Riyadh", + "Indian/Maldives", "Maldives", "Indian/Maldives", + "Asia/Anadyr", "Magadan", "Asia/Magadan", + "Europe/Helsinki", "Europe_Eastern", "Europe/Bucharest", + "America/Nome", "Alaska", "America/Juneau", + "Asia/Yakutsk", "Yakutsk", "Asia/Yakutsk", + "Africa/Conakry", "GMT", "Atlantic/Reykjavik", + "Asia/Seoul", "Korea", "Asia/Seoul", + "America/Antigua", "Atlantic", "America/Halifax", + "Asia/Almaty", "Kazakhstan_Eastern", "Asia/Almaty", + "America/Fortaleza", "Brasilia", "America/Sao_Paulo", + "Pacific/Tahiti", "Tahiti", "Pacific/Tahiti", + "Asia/Kashgar", "China", "Asia/Shanghai", + "America/Whitehorse", "America_Pacific", "America/Los_Angeles", + "Europe/Kaliningrad", "Europe_Eastern", "Europe/Bucharest", + "Pacific/Enderbury", "Phoenix_Islands", "Pacific/Enderbury", + "America/St_Lucia", "Atlantic", "America/Halifax", + "Atlantic/Stanley", "Falkland", "Atlantic/Stanley", + "Asia/Omsk", "Omsk", "Asia/Omsk", + "America/Menominee", "America_Central", "America/Chicago", + "Asia/Novokuznetsk", "Novosibirsk", "Asia/Novosibirsk", + "Asia/Sakhalin", "Sakhalin", "Asia/Sakhalin", + "Asia/Muscat", "Gulf", "Asia/Dubai", + "Pacific/Noumea", "New_Caledonia", "Pacific/Noumea", + "Asia/Phnom_Penh", "Indochina", "Asia/Saigon", + "Antarctica/Mawson", "Mawson", "Antarctica/Mawson", + "Indian/Cocos", "Cocos", "Indian/Cocos", + "Europe/Tallinn", "Europe_Eastern", "Europe/Bucharest", + "Africa/Nairobi", "Africa_Eastern", "Africa/Nairobi", + "Europe/Ljubljana", "Europe_Central", "Europe/Paris", + "America/Montreal", "America_Eastern", "America/New_York", + "Asia/Kuala_Lumpur", "Malaysia", "Asia/Kuching", + "Asia/Magadan", "Magadan", "Asia/Magadan", + "Africa/Bamako", "GMT", "Atlantic/Reykjavik", + "Australia/Broken_Hill", "Australia_Central", "Australia/Adelaide", + "America/Indiana/Indianapolis", "America_Eastern", "America/New_York", + "Asia/Taipei", "Taipei", "Asia/Taipei", + "Europe/Samara", "Moscow", "Europe/Moscow", + "America/Indiana/Vevay", "America_Eastern", "America/New_York", + "Atlantic/South_Georgia", "South_Georgia", "Atlantic/South_Georgia", + "Pacific/Wake", "Wake", "Pacific/Wake", + "Asia/Tashkent", "Uzbekistan", "Asia/Tashkent", + "America/St_Thomas", "Atlantic", "America/Halifax", + "America/Argentina/San_Luis", "Argentina_Western", "America/Argentina/San_Luis", + "Arctic/Longyearbyen", "Europe_Central", "Europe/Paris", + "Asia/Chongqing", "China", "Asia/Shanghai", + "Europe/Monaco", "Europe_Central", "Europe/Paris", + "Asia/Qatar", "Arabian", "Asia/Riyadh", + "America/Chihuahua", "America_Mountain", "America/Denver", + "America/Havana", "Cuba", "America/Havana", + "Pacific/Auckland", "New_Zealand", "Pacific/Auckland", + "America/Jujuy", "Argentina", "America/Buenos_Aires", + "America/Goose_Bay", "Atlantic", "America/Halifax", + "Africa/Niamey", "Africa_Western", "Africa/Lagos", + "Asia/Kathmandu", "Nepal", "Asia/Katmandu", + "America/Caracas", "Venezuela", "America/Caracas", + "Indian/Comoro", "Africa_Eastern", "Africa/Nairobi", + "America/Argentina/Jujuy", "Argentina", "America/Buenos_Aires", + "America/Guyana", "Guyana", "America/Guyana", + "America/Indiana/Tell_City", "America_Central", "America/Chicago", + "America/Metlakatla", "America_Pacific", "America/Los_Angeles", + "Europe/Mariehamn", "Europe_Eastern", "Europe/Bucharest", + "Europe/Dublin", "GMT", "Atlantic/Reykjavik", + "Europe/Lisbon", "Europe_Western", "Atlantic/Canary", + "America/Puerto_Rico", "Atlantic", "America/Halifax", + "Asia/Pyongyang", "Korea", "Asia/Seoul", + "America/North_Dakota/New_Salem", "America_Central", "America/Chicago", + "Asia/Dhaka", "Bangladesh", "Asia/Dhaka", + "America/Rankin_Inlet", "America_Central", "America/Chicago", + "America/Adak", "Hawaii_Aleutian", "Pacific/Honolulu", + "America/Campo_Grande", "Amazon", "America/Manaus", + "Europe/Chisinau", "Europe_Eastern", "Europe/Bucharest", + "Pacific/Saipan", "Chamorro", "Pacific/Saipan", + "Pacific/Niue", "Niue", "Pacific/Niue", + "Europe/Madrid", "Europe_Central", "Europe/Paris", + "Pacific/Kwajalein", "Marshall_Islands", "Pacific/Majuro", + "America/Porto_Velho", "Amazon", "America/Manaus", + "Indian/Kerguelen", "French_Southern", "Indian/Kerguelen", + "America/Santarem", "Brasilia", "America/Sao_Paulo", + "Asia/Kuching", "Malaysia", "Asia/Kuching", + "Australia/Adelaide", "Australia_Central", "Australia/Adelaide", + "Europe/Bucharest", "Europe_Eastern", "Europe/Bucharest", + "Australia/Perth", "Australia_Western", "Australia/Perth", + "Europe/Sofia", "Europe_Eastern", "Europe/Bucharest", + "Indian/Chagos", "Indian_Ocean", "Indian/Chagos", + "America/Yellowknife", "America_Mountain", "America/Denver", + "America/Managua", "America_Central", "America/Chicago", + "America/Iqaluit", "America_Eastern", "America/New_York", + "Pacific/Kosrae", "Kosrae", "Pacific/Kosrae", + "Pacific/Guadalcanal", "Solomon", "Pacific/Guadalcanal", + "America/Barbados", "Atlantic", "America/Halifax", + "America/Aruba", "Atlantic", "America/Halifax", + "Europe/Andorra", "Europe_Central", "Europe/Paris", + "Pacific/Chatham", "Chatham", "Pacific/Chatham", + "America/Santo_Domingo", "Atlantic", "America/Halifax", + "America/Indiana/Vincennes", "America_Eastern", "America/New_York", + "Europe/Kiev", "Europe_Eastern", "Europe/Bucharest", + "Pacific/Funafuti", "Tuvalu", "Pacific/Funafuti", + "America/Mexico_City", "America_Central", "America/Chicago", + "America/Kentucky/Monticello", "America_Eastern", "America/New_York", + "America/Argentina/Catamarca", "Argentina", "America/Buenos_Aires", + "Pacific/Johnston", "Hawaii_Aleutian", "Pacific/Honolulu", + "Europe/Podgorica", "Europe_Central", "Europe/Paris", + "Europe/Zagreb", "Europe_Central", "Europe/Paris", + "Pacific/Pohnpei", "Ponape", "Pacific/Ponape", + "Antarctica/Palmer", "Chile", "America/Santiago", + "America/Argentina/Mendoza", "Argentina", "America/Buenos_Aires", + "America/Lima", "Peru", "America/Lima", + "Antarctica/Macquarie", "Macquarie", "Antarctica/Macquarie", + "Europe/Malta", "Europe_Central", "Europe/Paris", + "America/Danmarkshavn", "GMT", "Atlantic/Reykjavik", + }; + private static final String[] mzoneMap = new String[] { + "America_Eastern", "TC", "America/Grand_Turk", + "America_Eastern", "BS", "America/Nassau", + "America_Eastern", "CA", "America/Toronto", + "America_Eastern", "KY", "America/Cayman", + "America_Eastern", "PA", "America/Panama", + "America_Eastern", "JM", "America/Jamaica", + "America_Pacific", "CA", "America/Vancouver", + "America_Pacific", "MX", "America/Tijuana", + "Europe_Western", "FO", "Atlantic/Faeroe", + "Arabian", "YE", "Asia/Aden", + "Arabian", "BH", "Asia/Bahrain", + "Arabian", "KW", "Asia/Kuwait", + "Arabian", "QA", "Asia/Qatar", + "Arabian", "IQ", "Asia/Baghdad", + "Korea", "KP", "Asia/Pyongyang", + "Africa_Central", "ZW", "Africa/Harare", + "Africa_Central", "ZM", "Africa/Lusaka", + "Africa_Central", "MW", "Africa/Blantyre", + "Africa_Central", "BW", "Africa/Gaborone", + "Africa_Central", "CD", "Africa/Lubumbashi", + "Africa_Central", "BI", "Africa/Bujumbura", + "Africa_Central", "RW", "Africa/Kigali", + "Africa_Western", "CF", "Africa/Bangui", + "Africa_Western", "AO", "Africa/Luanda", + "Africa_Western", "NE", "Africa/Niamey", + "Africa_Western", "CD", "Africa/Kinshasa", + "Africa_Western", "CM", "Africa/Douala", + "Africa_Western", "CG", "Africa/Brazzaville", + "Africa_Western", "GQ", "Africa/Malabo", + "Africa_Western", "TD", "Africa/Ndjamena", + "Africa_Western", "GA", "Africa/Libreville", + "Atlantic", "PR", "America/Puerto_Rico", + "Atlantic", "AN", "America/Curacao", + "Atlantic", "VI", "America/St_Thomas", + "Atlantic", "GP", "America/Guadeloupe", + "Atlantic", "TT", "America/Port_of_Spain", + "Atlantic", "AG", "America/Antigua", + "Atlantic", "MF", "America/Marigot", + "Atlantic", "DM", "America/Dominica", + "Atlantic", "VG", "America/Tortola", + "Atlantic", "MQ", "America/Martinique", + "Atlantic", "GL", "America/Thule", + "Atlantic", "AI", "America/Anguilla", + "Atlantic", "BB", "America/Barbados", + "Atlantic", "BM", "Atlantic/Bermuda", + "Atlantic", "BQ", "America/Kralendijk", + "Atlantic", "LC", "America/St_Lucia", + "Atlantic", "MS", "America/Montserrat", + "Atlantic", "SX", "America/Lower_Princes", + "Atlantic", "GD", "America/Grenada", + "Atlantic", "VC", "America/St_Vincent", + "Atlantic", "KN", "America/St_Kitts", + "Atlantic", "AW", "America/Aruba", + "GMT", "GM", "Africa/Banjul", + "GMT", "LR", "Africa/Monrovia", + "GMT", "ML", "Africa/Bamako", + "GMT", "SH", "Atlantic/St_Helena", + "GMT", "TG", "Africa/Lome", + "GMT", "GB", "Europe/London", + "GMT", "MR", "Africa/Nouakchott", + "GMT", "GN", "Africa/Conakry", + "GMT", "SL", "Africa/Freetown", + "GMT", "BF", "Africa/Ouagadougou", + "GMT", "ST", "Africa/Sao_Tome", + "GMT", "SN", "Africa/Dakar", + "GMT", "CI", "Africa/Abidjan", + "GMT", "IE", "Europe/Dublin", + "GMT", "GH", "Africa/Accra", + "Chile", "AQ", "Antarctica/Palmer", + "America_Central", "CR", "America/Costa_Rica", + "America_Central", "HN", "America/Tegucigalpa", + "America_Central", "CA", "America/Winnipeg", + "America_Central", "SV", "America/El_Salvador", + "America_Central", "MX", "America/Mexico_City", + "America_Central", "BZ", "America/Belize", + "America_Central", "GT", "America/Guatemala", + "America_Mountain", "CA", "America/Edmonton", + "America_Mountain", "MX", "America/Hermosillo", + "New_Zealand", "AQ", "Antarctica/McMurdo", + "India", "LK", "Asia/Colombo", + "Gulf", "OM", "Asia/Muscat", + "China", "MO", "Asia/Macau", + "Africa_Eastern", "ER", "Africa/Asmera", + "Africa_Eastern", "TZ", "Africa/Dar_es_Salaam", + "Africa_Eastern", "SO", "Africa/Mogadishu", + "Africa_Eastern", "DJ", "Africa/Djibouti", + "Africa_Eastern", "MG", "Indian/Antananarivo", + "Africa_Eastern", "KM", "Indian/Comoro", + "Africa_Eastern", "UG", "Africa/Kampala", + "Africa_Eastern", "YT", "Indian/Mayotte", + "Africa_Eastern", "ET", "Africa/Addis_Ababa", + "Chamorro", "GU", "Pacific/Guam", + "Africa_Southern", "LS", "Africa/Maseru", + "Africa_Southern", "SZ", "Africa/Mbabane", + "Indochina", "KH", "Asia/Phnom_Penh", + "Indochina", "TH", "Asia/Bangkok", + "Indochina", "LA", "Asia/Vientiane", + "Europe_Central", "AT", "Europe/Vienna", + "Europe_Central", "SK", "Europe/Bratislava", + "Europe_Central", "BA", "Europe/Sarajevo", + "Europe_Central", "CZ", "Europe/Prague", + "Europe_Central", "BE", "Europe/Brussels", + "Europe_Central", "RS", "Europe/Belgrade", + "Europe_Central", "SE", "Europe/Stockholm", + "Europe_Central", "MT", "Europe/Malta", + "Europe_Central", "IT", "Europe/Rome", + "Europe_Central", "LU", "Europe/Luxembourg", + "Europe_Central", "HU", "Europe/Budapest", + "Europe_Central", "NO", "Europe/Oslo", + "Europe_Central", "ME", "Europe/Podgorica", + "Europe_Central", "MK", "Europe/Skopje", + "Europe_Central", "NL", "Europe/Amsterdam", + "Europe_Central", "LI", "Europe/Vaduz", + "Europe_Central", "PL", "Europe/Warsaw", + "Europe_Central", "ES", "Europe/Madrid", + "Europe_Central", "TN", "Africa/Tunis", + "Europe_Central", "SI", "Europe/Ljubljana", + "Europe_Central", "DE", "Europe/Berlin", + "Europe_Central", "GI", "Europe/Gibraltar", + "Europe_Central", "CH", "Europe/Zurich", + "Europe_Central", "MC", "Europe/Monaco", + "Europe_Central", "VA", "Europe/Vatican", + "Europe_Central", "HR", "Europe/Zagreb", + "Europe_Central", "AL", "Europe/Tirane", + "Europe_Central", "AD", "Europe/Andorra", + "Europe_Central", "DK", "Europe/Copenhagen", + "Europe_Central", "SM", "Europe/San_Marino", + "Europe_Eastern", "SY", "Asia/Damascus", + "Europe_Eastern", "FI", "Europe/Helsinki", + "Europe_Eastern", "AX", "Europe/Mariehamn", + "Europe_Eastern", "BG", "Europe/Sofia", + "Europe_Eastern", "EG", "Africa/Cairo", + "Europe_Eastern", "LB", "Asia/Beirut", + "Europe_Eastern", "GR", "Europe/Athens", + "Europe_Eastern", "JO", "Asia/Amman", + "Europe_Eastern", "CY", "Asia/Nicosia", + }; + private static final String[] aliasMap = new String[] { + "Mexico/BajaNorte", "America/Tijuana", + "Antarctica/South_Pole", "Antarctica/McMurdo", + "US/Michigan", "America/Detroit", + "America/Porto_Acre", "America/Rio_Branco", + "US/Alaska", "America/Anchorage", + "Asia/Ujung_Pandang", "Asia/Makassar", + "Canada/Atlantic", "America/Halifax", + "W-SU", "Europe/Moscow", + "Kwajalein", "Pacific/Kwajalein", + "Europe/Bratislava", "Europe/Prague", + "Canada/Central", "America/Winnipeg", + "Canada/Mountain", "America/Edmonton", + "Iceland", "Atlantic/Reykjavik", + "Asia/Ulan_Bator", "Asia/Ulaanbaatar", + "UTC", "Etc/UTC", + "Europe/Guernsey", "Europe/London", + "Singapore", "Asia/Singapore", + "Atlantic/Faeroe", "Atlantic/Faroe", + "Greenwich", "Etc/GMT", + "America/Fort_Wayne", "America/Indiana/Indianapolis", + "Etc/Universal", "Etc/UTC", + "Chile/EasterIsland", "Pacific/Easter", + "Pacific/Samoa", "Pacific/Pago_Pago", + "Europe/Nicosia", "Asia/Nicosia", + "Etc/Zulu", "Etc/UTC", + "Asia/Ashkhabad", "Asia/Ashgabat", + "America/Louisville", "America/Kentucky/Louisville", + "Australia/North", "Australia/Darwin", + "America/Atka", "America/Adak", + "America/Marigot", "America/Guadeloupe", + "Brazil/DeNoronha", "America/Noronha", + "Turkey", "Europe/Istanbul", + "Zulu", "Etc/UTC", + "Europe/Vatican", "Europe/Rome", + "Israel", "Asia/Jerusalem", + "America/Rosario", "America/Argentina/Cordoba", + "Jamaica", "America/Jamaica", + "Asia/Katmandu", "Asia/Kathmandu", + "Canada/East-Saskatchewan", "America/Regina", + "ROK", "Asia/Seoul", + "Asia/Macao", "Asia/Macau", + "Australia/South", "Australia/Adelaide", + "US/Arizona", "America/Phoenix", + "Australia/Yancowinna", "Australia/Broken_Hill", + "Canada/Pacific", "America/Vancouver", + "Libya", "Africa/Tripoli", + "Japan", "Asia/Tokyo", + "Arctic/Longyearbyen", "Europe/Oslo", + "Africa/Timbuktu", "Africa/Bamako", + "America/Indianapolis", "America/Indiana/Indianapolis", + "Etc/Greenwich", "Etc/GMT", + "Australia/ACT", "Australia/Sydney", + "GMT", "Etc/GMT", + "Mexico/BajaSur", "America/Mazatlan", + "Cuba", "America/Havana", + "Brazil/West", "America/Manaus", + "Asia/Saigon", "Asia/Ho_Chi_Minh", + "America/Jujuy", "America/Argentina/Jujuy", + "Australia/Victoria", "Australia/Melbourne", + "America/Catamarca", "America/Argentina/Catamarca", + "America/Ensenada", "America/Tijuana", + "Europe/San_Marino", "Europe/Rome", + "Europe/Isle_of_Man", "Europe/London", + "Mexico/General", "America/Mexico_City", + "US/Hawaii", "Pacific/Honolulu", + "Europe/Mariehamn", "Europe/Helsinki", + "US/Indiana-Starke", "America/Indiana/Knox", + "Australia/NSW", "Australia/Sydney", + "Australia/West", "Australia/Perth", + "Brazil/Acre", "America/Rio_Branco", + "Australia/Tasmania", "Australia/Hobart", + "Atlantic/Jan_Mayen", "Europe/Oslo", + "America/Buenos_Aires", "America/Argentina/Buenos_Aires", + "Europe/Jersey", "Europe/London", + "Brazil/East", "America/Sao_Paulo", + "America/Virgin", "America/St_Thomas", + "Navajo", "America/Denver", + "GB", "Europe/London", + "Poland", "Europe/Warsaw", + "Pacific/Yap", "Pacific/Chuuk", + "America/Argentina/ComodRivadavia", "America/Argentina/Catamarca", + "Asia/Calcutta", "Asia/Kolkata", + "America/Mendoza", "America/Argentina/Mendoza", + "Universal", "Etc/UTC", + "Australia/Queensland", "Australia/Brisbane", + "Asia/Dacca", "Asia/Dhaka", + "US/Pacific", "America/Los_Angeles", + "Asia/Chungking", "Asia/Chongqing", + "Pacific/Truk", "Pacific/Chuuk", + "ROC", "Asia/Taipei", + "US/Aleutian", "America/Adak", + "Pacific/Ponape", "Pacific/Pohnpei", + "Canada/Yukon", "America/Whitehorse", + "PRC", "Asia/Shanghai", + "Africa/Asmera", "Africa/Asmara", + "GB-Eire", "Europe/London", + "America/St_Barthelemy", "America/Guadeloupe", + "US/Central", "America/Chicago", + "Egypt", "Africa/Cairo", + "Chile/Continental", "America/Santiago", + "Portugal", "Europe/Lisbon", + "Europe/Tiraspol", "Europe/Chisinau", + "America/Coral_Harbour", "America/Atikokan", + "Europe/Belfast", "Europe/London", + "America/Cordoba", "America/Argentina/Cordoba", + "America/Shiprock", "America/Denver", + "NZ-CHAT", "Pacific/Chatham", + "Eire", "Europe/Dublin", + "US/East-Indiana", "America/Indiana/Indianapolis", + "Australia/Canberra", "Australia/Sydney", + "Canada/Newfoundland", "America/St_Johns", + "UCT", "Etc/UCT", + "Australia/LHI", "Australia/Lord_Howe", + "Iran", "Asia/Tehran", + "US/Eastern", "America/New_York", + "Canada/Eastern", "America/Toronto", + "US/Samoa", "Pacific/Pago_Pago", + "America/Knox_IN", "America/Indiana/Knox", + "Canada/Saskatchewan", "America/Regina", + "Asia/Thimbu", "Asia/Thimphu", + "US/Mountain", "America/Denver", + "NZ", "Pacific/Auckland", + "Asia/Tel_Aviv", "Asia/Jerusalem", + "Hongkong", "Asia/Hong_Kong", + }; + + private static final Map zidToMzone = new HashMap<>(); + private static final Map mzoneToZid = new HashMap<>(); + private static final Map> mzoneToZidL = new HashMap<>(); + private static final Map aliases = new HashMap<>(); + + static { + for (int i = 0; i < zidMap.length; i += 3) { + zidToMzone.put(zidMap[i], zidMap[i + 1]); + mzoneToZid.put(zidMap[i + 1], zidMap[i + 2]); + } + + for (int i = 0; i < mzoneMap.length; i += 3) { + String mzone = mzoneMap[i]; + Map map = mzoneToZidL.get(mzone); + if (map == null) { + map = new HashMap<>(); + mzoneToZidL.put(mzone, map); + } + map.put(mzoneMap[i + 1], mzoneMap[i + 2]); + } + + for (int i = 0; i < aliasMap.length; i += 2) { + aliases.put(aliasMap[i], aliasMap[i + 1]); + } + } +} diff --git a/jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java b/jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java index 255735db006..eb97313ae19 100644 --- a/jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java +++ b/jdk/test/java/time/test/java/time/temporal/MockFieldNoValue.java @@ -59,13 +59,15 @@ */ package test.java.time.temporal; -import java.time.format.DateTimeBuilder; -import java.time.temporal.*; - import static java.time.temporal.ChronoUnit.MONTHS; import static java.time.temporal.ChronoUnit.WEEKS; import java.time.DateTimeException; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalAccessor; +import java.time.temporal.TemporalField; +import java.time.temporal.TemporalUnit; +import java.time.temporal.ValueRange; /** * Mock TemporalField that returns null. @@ -96,29 +98,23 @@ public enum MockFieldNoValue implements TemporalField { //----------------------------------------------------------------------- @Override - public boolean doIsSupported(TemporalAccessor temporal) { + public boolean isSupportedBy(TemporalAccessor temporal) { return true; } @Override - public ValueRange doRange(TemporalAccessor temporal) { + public ValueRange rangeRefinedBy(TemporalAccessor temporal) { return ValueRange.of(1, 20); } @Override - public long doGet(TemporalAccessor temporal) { + public long getFrom(TemporalAccessor temporal) { throw new DateTimeException("Mock"); } @Override - public R doWith(R temporal, long newValue) { + public R adjustInto(R temporal, long newValue) { throw new DateTimeException("Mock"); } - //----------------------------------------------------------------------- - @Override - public boolean resolve(DateTimeBuilder dateTimeBuilder, long value) { - return false; - } - } diff --git a/jdk/test/java/time/test/java/time/temporal/MockFieldValue.java b/jdk/test/java/time/test/java/time/temporal/MockFieldValue.java index 7f478a9a539..cceb4c89958 100644 --- a/jdk/test/java/time/test/java/time/temporal/MockFieldValue.java +++ b/jdk/test/java/time/test/java/time/temporal/MockFieldValue.java @@ -90,7 +90,7 @@ public final class MockFieldValue implements TemporalAccessor { } throw new DateTimeException("Unsupported field: " + field.getName()); } - return field.doRange(this); + return field.rangeRefinedBy(this); } @Override diff --git a/jdk/test/java/time/test/java/time/temporal/TestChronoUnit.java b/jdk/test/java/time/test/java/time/temporal/TestChronoUnit.java index b282cda2f85..0f84d39591c 100644 --- a/jdk/test/java/time/test/java/time/temporal/TestChronoUnit.java +++ b/jdk/test/java/time/test/java/time/temporal/TestChronoUnit.java @@ -106,35 +106,33 @@ public class TestChronoUnit { @Test(dataProvider = "yearsBetween") public void test_yearsBetween(LocalDate start, LocalDate end, long expected) { - assertEquals(YEARS.between(start, end).getAmount(), expected); - assertEquals(YEARS.between(start, end).getUnit(), YEARS); + assertEquals(YEARS.between(start, end), expected); } @Test(dataProvider = "yearsBetween") public void test_yearsBetweenReversed(LocalDate start, LocalDate end, long expected) { - assertEquals(YEARS.between(end, start).getAmount(), -expected); - assertEquals(YEARS.between(end, start).getUnit(), YEARS); + assertEquals(YEARS.between(end, start), -expected); } @Test(dataProvider = "yearsBetween") public void test_yearsBetween_LocalDateTimeSameTime(LocalDate start, LocalDate end, long expected) { - assertEquals(YEARS.between(start.atTime(12, 30), end.atTime(12, 30)).getAmount(), expected); + assertEquals(YEARS.between(start.atTime(12, 30), end.atTime(12, 30)), expected); } @Test(dataProvider = "yearsBetween") public void test_yearsBetween_LocalDateTimeLaterTime(LocalDate start, LocalDate end, long expected) { - assertEquals(YEARS.between(start.atTime(12, 30), end.atTime(12, 31)).getAmount(), expected); + assertEquals(YEARS.between(start.atTime(12, 30), end.atTime(12, 31)), expected); } @Test(dataProvider = "yearsBetween") public void test_yearsBetween_ZonedDateSameOffset(LocalDate start, LocalDate end, long expected) { - assertEquals(YEARS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(2))).getAmount(), expected); + assertEquals(YEARS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(2))), expected); } @Test(dataProvider = "yearsBetween") public void test_yearsBetween_ZonedDateLaterOffset(LocalDate start, LocalDate end, long expected) { // +01:00 is later than +02:00 - assertEquals(YEARS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(1))).getAmount(), expected); + assertEquals(YEARS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(1))), expected); } //----------------------------------------------------------------------- @@ -173,35 +171,33 @@ public class TestChronoUnit { @Test(dataProvider = "monthsBetween") public void test_monthsBetween(LocalDate start, LocalDate end, long expected) { - assertEquals(MONTHS.between(start, end).getAmount(), expected); - assertEquals(MONTHS.between(start, end).getUnit(), MONTHS); + assertEquals(MONTHS.between(start, end), expected); } @Test(dataProvider = "monthsBetween") public void test_monthsBetweenReversed(LocalDate start, LocalDate end, long expected) { - assertEquals(MONTHS.between(end, start).getAmount(), -expected); - assertEquals(MONTHS.between(end, start).getUnit(), MONTHS); + assertEquals(MONTHS.between(end, start), -expected); } @Test(dataProvider = "monthsBetween") public void test_monthsBetween_LocalDateTimeSameTime(LocalDate start, LocalDate end, long expected) { - assertEquals(MONTHS.between(start.atTime(12, 30), end.atTime(12, 30)).getAmount(), expected); + assertEquals(MONTHS.between(start.atTime(12, 30), end.atTime(12, 30)), expected); } @Test(dataProvider = "monthsBetween") public void test_monthsBetween_LocalDateTimeLaterTime(LocalDate start, LocalDate end, long expected) { - assertEquals(MONTHS.between(start.atTime(12, 30), end.atTime(12, 31)).getAmount(), expected); + assertEquals(MONTHS.between(start.atTime(12, 30), end.atTime(12, 31)), expected); } @Test(dataProvider = "monthsBetween") public void test_monthsBetween_ZonedDateSameOffset(LocalDate start, LocalDate end, long expected) { - assertEquals(MONTHS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(2))).getAmount(), expected); + assertEquals(MONTHS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(2))), expected); } @Test(dataProvider = "monthsBetween") public void test_monthsBetween_ZonedDateLaterOffset(LocalDate start, LocalDate end, long expected) { // +01:00 is later than +02:00 - assertEquals(MONTHS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(1))).getAmount(), expected); + assertEquals(MONTHS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(1))), expected); } //----------------------------------------------------------------------- @@ -234,14 +230,12 @@ public class TestChronoUnit { @Test(dataProvider = "weeksBetween") public void test_weeksBetween(LocalDate start, LocalDate end, long expected) { - assertEquals(WEEKS.between(start, end).getAmount(), expected); - assertEquals(WEEKS.between(start, end).getUnit(), WEEKS); + assertEquals(WEEKS.between(start, end), expected); } @Test(dataProvider = "weeksBetween") public void test_weeksBetweenReversed(LocalDate start, LocalDate end, long expected) { - assertEquals(WEEKS.between(end, start).getAmount(), -expected); - assertEquals(WEEKS.between(end, start).getUnit(), WEEKS); + assertEquals(WEEKS.between(end, start), -expected); } //----------------------------------------------------------------------- @@ -279,35 +273,33 @@ public class TestChronoUnit { @Test(dataProvider = "daysBetween") public void test_daysBetween(LocalDate start, LocalDate end, long expected) { - assertEquals(DAYS.between(start, end).getAmount(), expected); - assertEquals(DAYS.between(start, end).getUnit(), DAYS); + assertEquals(DAYS.between(start, end), expected); } @Test(dataProvider = "daysBetween") public void test_daysBetweenReversed(LocalDate start, LocalDate end, long expected) { - assertEquals(DAYS.between(end, start).getAmount(), -expected); - assertEquals(DAYS.between(end, start).getUnit(), DAYS); + assertEquals(DAYS.between(end, start), -expected); } @Test(dataProvider = "daysBetween") public void test_daysBetween_LocalDateTimeSameTime(LocalDate start, LocalDate end, long expected) { - assertEquals(DAYS.between(start.atTime(12, 30), end.atTime(12, 30)).getAmount(), expected); + assertEquals(DAYS.between(start.atTime(12, 30), end.atTime(12, 30)), expected); } @Test(dataProvider = "daysBetween") public void test_daysBetween_LocalDateTimeLaterTime(LocalDate start, LocalDate end, long expected) { - assertEquals(DAYS.between(start.atTime(12, 30), end.atTime(12, 31)).getAmount(), expected); + assertEquals(DAYS.between(start.atTime(12, 30), end.atTime(12, 31)), expected); } @Test(dataProvider = "daysBetween") public void test_daysBetween_ZonedDateSameOffset(LocalDate start, LocalDate end, long expected) { - assertEquals(DAYS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(2))).getAmount(), expected); + assertEquals(DAYS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(2))), expected); } @Test(dataProvider = "daysBetween") public void test_daysBetween_ZonedDateLaterOffset(LocalDate start, LocalDate end, long expected) { // +01:00 is later than +02:00 - assertEquals(DAYS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(1))).getAmount(), expected); + assertEquals(DAYS.between(start.atStartOfDay(ZoneOffset.ofHours(2)), end.atStartOfDay(ZoneOffset.ofHours(1))), expected); } //----------------------------------------------------------------------- diff --git a/jdk/test/java/time/test/java/time/temporal/TestDateTimeBuilderCombinations.java b/jdk/test/java/time/test/java/time/temporal/TestDateTimeBuilderCombinations.java index 328ead5e4e2..941e08e3be7 100644 --- a/jdk/test/java/time/test/java/time/temporal/TestDateTimeBuilderCombinations.java +++ b/jdk/test/java/time/test/java/time/temporal/TestDateTimeBuilderCombinations.java @@ -71,9 +71,13 @@ import static java.time.temporal.ChronoField.EPOCH_MONTH; import static java.time.temporal.ChronoField.MONTH_OF_YEAR; import static java.time.temporal.ChronoField.YEAR; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; +import java.time.DateTimeException; import java.time.LocalDate; -import java.time.format.DateTimeBuilder; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; import org.testng.annotations.DataProvider; @@ -98,74 +102,110 @@ public class TestDateTimeBuilderCombinations { } @Test(dataProvider = "combine") - public void test_derive(TemporalField field1, Number value1, TemporalField field2, Number value2, - TemporalField field3, Number value3, TemporalField field4, Number value4, Class query, Object expectedVal) { - DateTimeBuilder builder = new DateTimeBuilder(field1, value1.longValue()); + public void test_derive(final TemporalField field1, final Number value1, + final TemporalField field2, final Number value2, + final TemporalField field3, final Number value3, + final TemporalField field4, final Number value4, + Class query, Object expectedVal) { + // mock for testing that does not fully comply with TemporalAccessor contract + TemporalAccessor test = new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + return field == field1 || field == field2 || field == field3 || field == field4; + } + @Override + public long getLong(TemporalField field) { + if (field == field1) { + return value1.longValue(); + } + if (field == field2) { + return value2.longValue(); + } + if (field == field3) { + return value3.longValue(); + } + if (field == field4) { + return value4.longValue(); + } + throw new DateTimeException("Unsupported"); + } + }; + String str = ""; + DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder(); + dtfb.appendValue(field1).appendLiteral('-'); + str += value1 + "-"; if (field2 != null) { - builder.addFieldValue(field2, value2.longValue()); + dtfb.appendValue(field2).appendLiteral('-'); + str += value2 + "-"; } if (field3 != null) { - builder.addFieldValue(field3, value3.longValue()); + dtfb.appendValue(field3).appendLiteral('-'); + str += value3 + "-"; } if (field4 != null) { - builder.addFieldValue(field4, value4.longValue()); + dtfb.appendValue(field4).appendLiteral('-'); + str += value4 + "-"; + } + TemporalAccessor parsed = dtfb.toFormatter().parse(str); + if (query == LocalDate.class) { + if (expectedVal != null) { + assertEquals(parsed.query(LocalDate::from), expectedVal); + } else { + try { + parsed.query(LocalDate::from); + fail(); + } catch (DateTimeException ex) { + // expected + } + } + } else { + throw new IllegalArgumentException(); } - builder.resolve(); - assertEquals(builder.extract((Class) query), expectedVal); } //----------------------------------------------------------------------- @DataProvider(name = "normalized") Object[][] data_normalized() { return new Object[][] { - {YEAR, 2127, null, null, null, null, YEAR, 2127}, - {MONTH_OF_YEAR, 12, null, null, null, null, MONTH_OF_YEAR, 12}, - {DAY_OF_YEAR, 127, null, null, null, null, DAY_OF_YEAR, 127}, - {DAY_OF_MONTH, 23, null, null, null, null, DAY_OF_MONTH, 23}, - {DAY_OF_WEEK, 127, null, null, null, null, DAY_OF_WEEK, 127L}, - {ALIGNED_WEEK_OF_YEAR, 23, null, null, null, null, ALIGNED_WEEK_OF_YEAR, 23}, - {ALIGNED_DAY_OF_WEEK_IN_YEAR, 4, null, null, null, null, ALIGNED_DAY_OF_WEEK_IN_YEAR, 4L}, - {ALIGNED_WEEK_OF_MONTH, 4, null, null, null, null, ALIGNED_WEEK_OF_MONTH, 4}, - {ALIGNED_DAY_OF_WEEK_IN_MONTH, 3, null, null, null, null, ALIGNED_DAY_OF_WEEK_IN_MONTH, 3}, - {EPOCH_MONTH, 15, null, null, null, null, EPOCH_MONTH, null}, - {EPOCH_MONTH, 15, null, null, null, null, YEAR, 1971}, - {EPOCH_MONTH, 15, null, null, null, null, MONTH_OF_YEAR, 4}, + {YEAR, 2127, YEAR, 2127}, + {MONTH_OF_YEAR, 12, MONTH_OF_YEAR, 12}, + {DAY_OF_YEAR, 127, DAY_OF_YEAR, 127}, + {DAY_OF_MONTH, 23, DAY_OF_MONTH, 23}, + {DAY_OF_WEEK, 127, DAY_OF_WEEK, 127L}, + {ALIGNED_WEEK_OF_YEAR, 23, ALIGNED_WEEK_OF_YEAR, 23}, + {ALIGNED_DAY_OF_WEEK_IN_YEAR, 4, ALIGNED_DAY_OF_WEEK_IN_YEAR, 4L}, + {ALIGNED_WEEK_OF_MONTH, 4, ALIGNED_WEEK_OF_MONTH, 4}, + {ALIGNED_DAY_OF_WEEK_IN_MONTH, 3, ALIGNED_DAY_OF_WEEK_IN_MONTH, 3}, + {EPOCH_MONTH, 15, EPOCH_MONTH, null}, + {EPOCH_MONTH, 15, YEAR, 1971}, + {EPOCH_MONTH, 15, MONTH_OF_YEAR, 4}, }; } @Test(dataProvider = "normalized") - public void test_normalized(TemporalField field1, Number value1, TemporalField field2, Number value2, - TemporalField field3, Number value3, TemporalField query, Number expectedVal) { - DateTimeBuilder builder = new DateTimeBuilder(field1, value1.longValue()); - if (field2 != null) { - builder.addFieldValue(field2, value2.longValue()); - } - if (field3 != null) { - builder.addFieldValue(field3, value3.longValue()); - } - builder.resolve(); + public void test_normalized(final TemporalField field1, final Number value1, TemporalField expectedField, Number expectedVal) { + // mock for testing that does not fully comply with TemporalAccessor contract + TemporalAccessor test = new TemporalAccessor() { + @Override + public boolean isSupported(TemporalField field) { + return field == field1; + } + @Override + public long getLong(TemporalField field) { + if (field == field1) { + return value1.longValue(); + } + throw new DateTimeException("Unsupported"); + } + }; + DateTimeFormatter f = new DateTimeFormatterBuilder().appendValue(field1).toFormatter(); + String str = value1.toString(); + TemporalAccessor temporal = f.parse(str); if (expectedVal != null) { - assertEquals(builder.getLong(query), expectedVal.longValue()); + assertEquals(temporal.getLong(expectedField), expectedVal.longValue()); } else { - assertEquals(builder.containsFieldValue(query), false); + assertEquals(temporal.isSupported(expectedField), false); } } - //----------------------------------------------------------------------- - // TODO: maybe reinstate -// public void test_split() { -// DateTimeBuilder builder = new DateTimeBuilder(); -// builder.addCalendrical(LocalDateTime.of(2012, 6, 30, 12, 30)); -// builder.addCalendrical(ZoneOffset.ofHours(2)); -// builder.resolve(); -// assertEquals(builder.build(LocalDate.class), LocalDate.of(2012, 6, 30)); -// assertEquals(builder.build(LocalTime.class), LocalTime.of(12, 30)); -// assertEquals(builder.build(ZoneOffset.class), ZoneOffset.ofHours(2)); -// -// assertEquals(builder.build(LocalDateTime.class), LocalDateTime.of(2012, 6, 30, 12, 30)); -// assertEquals(builder.build(OffsetDate.class), OffsetDate.of(LocalDate.of(2012, 6, 30), ZoneOffset.ofHours(2))); -// assertEquals(builder.build(OffsetTime.class), OffsetTime.of(LocalTime.of(12, 30), ZoneOffset.ofHours(2))); -//// assertEquals(builder.build(OffsetDateTime.class), OffsetDateTime.of(2012, 6, 30, 12, 30, ZoneOffset.ofHours(2))); -// } - } diff --git a/jdk/test/java/time/test/java/time/temporal/TestJapaneseChronoImpl.java b/jdk/test/java/time/test/java/time/temporal/TestJapaneseChronoImpl.java index cadd1a378c6..ababf14cb4a 100644 --- a/jdk/test/java/time/test/java/time/temporal/TestJapaneseChronoImpl.java +++ b/jdk/test/java/time/test/java/time/temporal/TestJapaneseChronoImpl.java @@ -63,12 +63,13 @@ import java.util.Locale; import java.util.TimeZone; import java.time.LocalDate; import java.time.LocalTime; -import java.time.temporal.OffsetDateTime; +import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.temporal.ChronoField; -import java.time.temporal.ChronoLocalDate; +import java.time.chrono.ChronoLocalDate; import java.time.temporal.ChronoUnit; -import java.time.calendar.JapaneseChrono; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.JapaneseDate; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -100,7 +101,7 @@ public class TestJapaneseChronoImpl { Calendar cal = java.util.Calendar.getInstance(locale); assertEquals(cal.getCalendarType(), "japanese", "Unexpected calendar type"); - ChronoLocalDate jDate = JapaneseChrono.INSTANCE.date(isoStartDate); + JapaneseDate jDate = JapaneseChronology.INSTANCE.date(isoStartDate); // Convert to millis and set Japanese Calendar to that start date (at GMT) OffsetDateTime jodt = OffsetDateTime.of(isoStartDate, LocalTime.MIN, ZoneOffset.UTC); diff --git a/jdk/test/java/time/test/java/time/temporal/TestOffsetDate.java b/jdk/test/java/time/test/java/time/temporal/TestJulianFields.java similarity index 84% rename from jdk/test/java/time/test/java/time/temporal/TestOffsetDate.java rename to jdk/test/java/time/test/java/time/temporal/TestJulianFields.java index 5ba00329b8f..0d9d79e3158 100644 --- a/jdk/test/java/time/test/java/time/temporal/TestOffsetDate.java +++ b/jdk/test/java/time/test/java/time/temporal/TestJulianFields.java @@ -59,20 +59,26 @@ */ package test.java.time.temporal; -import java.time.temporal.OffsetDate; +import static org.testng.Assert.assertEquals; + +import java.time.temporal.JulianFields; import org.testng.annotations.Test; -import test.java.time.AbstractTest; /** - * Test OffsetDate. + * Test. */ @Test -public class TestOffsetDate extends AbstractTest { +public class TestJulianFields { + //----------------------------------------------------------------------- + // toString() + //----------------------------------------------------------------------- @Test - public void test_immutable() { - assertImmutable(OffsetDate.class); + public void test_toString() { + assertEquals(JulianFields.JULIAN_DAY.toString(), "JulianDay"); + assertEquals(JulianFields.MODIFIED_JULIAN_DAY.toString(), "ModifiedJulianDay"); + assertEquals(JulianFields.RATA_DIE.toString(), "RataDie"); } } diff --git a/jdk/test/java/time/test/java/time/temporal/TestThaiBuddhistChronoImpl.java b/jdk/test/java/time/test/java/time/temporal/TestThaiBuddhistChronoImpl.java index 9fd69cfa76b..14b0a45fe0c 100644 --- a/jdk/test/java/time/test/java/time/temporal/TestThaiBuddhistChronoImpl.java +++ b/jdk/test/java/time/test/java/time/temporal/TestThaiBuddhistChronoImpl.java @@ -65,8 +65,9 @@ import java.util.TimeZone; import java.time.LocalDate; import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; -import java.time.temporal.ChronoLocalDate; -import java.time.calendar.ThaiBuddhistChrono; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.ThaiBuddhistChronology; +import java.time.chrono.ThaiBuddhistDate; import org.testng.annotations.Test; import org.testng.annotations.DataProvider; @@ -97,7 +98,7 @@ public class TestThaiBuddhistChronoImpl { Calendar cal = java.util.Calendar.getInstance(locale); assertEquals(cal.getCalendarType(), "buddhist", "Unexpected calendar type"); - ChronoLocalDate thaiDate = ThaiBuddhistChrono.INSTANCE.date(isoStartDate); + ThaiBuddhistDate thaiDate = ThaiBuddhistChronology.INSTANCE.date(isoStartDate); cal.setTimeZone(TimeZone.getTimeZone("GMT+00")); cal.set(Calendar.YEAR, thaiDate.get(ChronoField.YEAR)); diff --git a/jdk/test/java/time/test/java/time/zone/TestFixedZoneRules.java b/jdk/test/java/time/test/java/time/zone/TestFixedZoneRules.java index 80569674bb6..67b6e0a2c40 100644 --- a/jdk/test/java/time/test/java/time/zone/TestFixedZoneRules.java +++ b/jdk/test/java/time/test/java/time/zone/TestFixedZoneRules.java @@ -59,7 +59,7 @@ */ package test.java.time.zone; -import java.time.zone.*; +import java.time.zone.ZoneRules; import static org.testng.Assert.assertEquals; diff --git a/jdk/test/java/time/test/java/util/TestFormatter.java b/jdk/test/java/time/test/java/util/TestFormatter.java index 54331ed2c9b..69c55f22131 100644 --- a/jdk/test/java/time/test/java/util/TestFormatter.java +++ b/jdk/test/java/time/test/java/util/TestFormatter.java @@ -23,7 +23,7 @@ package test.java.util; import java.time.Instant; -import java.time.temporal.OffsetDateTime; +import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.time.temporal.ChronoField; @@ -129,10 +129,9 @@ public class TestFormatter { printFmtStr(locale, fmtStr); String expected = test(fmtStr, locale, null, cal); test(fmtStr, locale, expected, zdt); - test(fmtStr, locale, expected, OffsetDateTime.of(zdt)); - test(fmtStr, locale, expected, zdt.getDateTime()); - test(fmtStr, locale, expected, OffsetDateTime.of(zdt).toOffsetDate()); - test(fmtStr, locale, expected, zdt.getDate()); + test(fmtStr, locale, expected, zdt.toOffsetDateTime()); + test(fmtStr, locale, expected, zdt.toLocalDateTime()); + test(fmtStr, locale, expected, zdt.toLocalDate()); } private void testTime(String fmtStr, Locale locale, @@ -140,30 +139,34 @@ public class TestFormatter { printFmtStr(locale, fmtStr); String expected = test(fmtStr, locale, null, cal); test(fmtStr, locale, expected, zdt); - test(fmtStr, locale, expected, OffsetDateTime.of(zdt)); - test(fmtStr, locale, expected, zdt.getDateTime()); - test(fmtStr, locale, expected, OffsetDateTime.of(zdt).toOffsetTime()); - test(fmtStr, locale, expected, zdt.getTime()); + test(fmtStr, locale, expected, zdt.toOffsetDateTime()); + test(fmtStr, locale, expected, zdt.toLocalDateTime()); + test(fmtStr, locale, expected, zdt.toOffsetDateTime().toOffsetTime()); + test(fmtStr, locale, expected, zdt.toLocalTime()); + } + + private String toZoneIdStr(String expected) { + return expected.replaceAll("(?:GMT|UTC)(?[+\\-]?[0-9]{2}:[0-9]{2})", "${off}") + .replaceAll("GMT|UTC|UT", "Z"); } private void testZoneId(Locale locale, ZonedDateTime zdt, Calendar cal) { String fmtStr = "z:[%tz] z:[%1$Tz] Z:[%1$tZ] Z:[%1$TZ]"; printFmtStr(locale, fmtStr); - String expected = test(fmtStr, locale, null, cal); + String expected = toZoneIdStr(test(fmtStr, locale, null, cal)); test(fmtStr, locale, expected, zdt); // get a new cal with fixed tz Calendar cal0 = Calendar.getInstance(); cal0.setTimeInMillis(zdt.toInstant().toEpochMilli()); cal0.setTimeZone(TimeZone.getTimeZone("GMT" + zdt.getOffset().getId())); - expected = test(fmtStr, locale, null, cal0).replaceAll("GMT", ""); - test(fmtStr, locale, expected, OffsetDateTime.of(zdt)); - test(fmtStr, locale, expected, OffsetDateTime.of(zdt).toOffsetDate()); - test(fmtStr, locale, expected, OffsetDateTime.of(zdt).toOffsetTime()); + expected = toZoneIdStr(test(fmtStr, locale, null, cal0)); + test(fmtStr, locale, expected, zdt.toOffsetDateTime()); + test(fmtStr, locale, expected, zdt.toOffsetDateTime().toOffsetTime()); // datetime + zid fmtStr = "c:[%tc] c:[%1$Tc]"; printFmtStr(locale, fmtStr); - expected = test(fmtStr, locale, null, cal); + expected = toZoneIdStr(test(fmtStr, locale, null, cal)); test(fmtStr, locale, expected, zdt); } @@ -174,6 +177,6 @@ public class TestFormatter { String expected = test(fmtStr, locale, null, cal); test(fmtStr, locale, expected, instant); test(fmtStr, locale, expected, zdt); - test(fmtStr, locale, expected, OffsetDateTime.of(zdt)); + test(fmtStr, locale, expected, zdt.toOffsetDateTime()); } } diff --git a/jdk/test/java/util/Calendar/JavatimeTest.java b/jdk/test/java/util/Calendar/JavatimeTest.java new file mode 100644 index 00000000000..5b9a7101805 --- /dev/null +++ b/jdk/test/java/util/Calendar/JavatimeTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2013, 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 8007520 + *@summary Test those bridge methods to/from java.time date/time classes + */ + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Random; +import java.util.TimeZone; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZonedDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; + +public class JavatimeTest { + + static final int NANOS_PER_SECOND = 1000_000_000; + + public static void main(String[] args) throws Throwable { + + int N = 10000; + long t1970 = new java.util.Date(70, 0, 01).getTime(); + Random r = new Random(); + for (int i = 0; i < N; i++) { + int days = r.nextInt(50) * 365 + r.nextInt(365); + long secs = t1970 + days * 86400 + r.nextInt(86400); + int nanos = r.nextInt(NANOS_PER_SECOND); + int nanos_ms = nanos / 1000000 * 1000000; // millis precision + long millis = secs * 1000 + r.nextInt(1000); + + LocalDateTime ldt = LocalDateTime.ofEpochSecond(secs, nanos, ZoneOffset.UTC); + LocalDateTime ldt_ms = LocalDateTime.ofEpochSecond(secs, nanos_ms, ZoneOffset.UTC); + Instant inst = Instant.ofEpochSecond(secs, nanos); + Instant inst_ms = Instant.ofEpochSecond(secs, nanos_ms); + //System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + + ///////////// java.util.Date ///////////////////////// + Date jud = new java.util.Date(millis); + Instant inst0 = jud.toInstant(); + if (jud.getTime() != inst0.toEpochMilli() || + !jud.equals(Date.from(inst0))) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + throw new RuntimeException("FAILED: j.u.d -> instant -> j.u.d"); + } + // roundtrip only with millis precision + Date jud0 = Date.from(inst_ms); + if (jud0.getTime() != inst_ms.toEpochMilli() || + !inst_ms.equals(jud0.toInstant())) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + throw new RuntimeException("FAILED: instant -> j.u.d -> instant"); + } + //////////// java.util.GregorianCalendar ///////////// + GregorianCalendar cal = new GregorianCalendar(); + cal.setGregorianChange(new java.util.Date(Long.MIN_VALUE)); + cal.setFirstDayOfWeek(Calendar.MONDAY); + cal.setMinimalDaysInFirstWeek(4); + cal.setTimeInMillis(millis); + ZonedDateTime zdt0 = cal.toZonedDateTime(); + if (cal.getTimeInMillis() != zdt0.toInstant().toEpochMilli() || + !cal.equals(GregorianCalendar.from(zdt0))) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + throw new RuntimeException("FAILED: gcal -> zdt -> gcal"); + } + inst0 = cal.toInstant(); + if (cal.getTimeInMillis() != inst0.toEpochMilli()) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + throw new RuntimeException("FAILED: gcal -> zdt"); + } + ZonedDateTime zdt = ZonedDateTime.of(ldt_ms, ZoneId.systemDefault()); + GregorianCalendar cal0 = GregorianCalendar.from(zdt); + if (zdt.toInstant().toEpochMilli() != cal0.getTimeInMillis() || + !zdt.equals(GregorianCalendar.from(zdt).toZonedDateTime())) { + System.out.printf("ms: %16d ns: %10d ldt:[%s]%n", millis, nanos, ldt); + throw new RuntimeException("FAILED: zdt -> gcal -> zdt"); + } + } + + ///////////// java.util.TimeZone ///////////////////////// + for (String zidStr : TimeZone.getAvailableIDs()) { + // TBD: tzdt intergration + if (zidStr.startsWith("SystemV") || + zidStr.contains("Riyadh8") || + zidStr.equals("US/Pacific-New")) { + continue; + } + ZoneId zid = ZoneId.of(zidStr, ZoneId.OLD_IDS_POST_2005); + if (!zid.equals(TimeZone.getTimeZone(zid).toZoneId())) { + throw new RuntimeException("FAILED: zid -> tz -> zid :" + zidStr); + } + TimeZone tz = TimeZone.getTimeZone(zidStr); + // no round-trip for alias and "GMT" + if (!tz.equals(TimeZone.getTimeZone(tz.toZoneId())) && + !ZoneId.OLD_IDS_POST_2005.containsKey(zidStr) && + !zidStr.startsWith("GMT")) { + throw new RuntimeException("FAILED: tz -> zid -> tz :" + zidStr); + } + } + System.out.println("Passed!"); + } +} diff --git a/jdk/test/java/util/TimeZone/OldIDMappingTest.java b/jdk/test/java/util/TimeZone/OldIDMappingTest.java index e60ec53175a..35e19cbfc36 100644 --- a/jdk/test/java/util/TimeZone/OldIDMappingTest.java +++ b/jdk/test/java/util/TimeZone/OldIDMappingTest.java @@ -51,17 +51,7 @@ public class OldIDMappingTest { throw new RuntimeException("-old or -new must be specified; got " + arg); } - // Get a Field for TzIDOldMapping in sun.util.calendar. - Map oldmap = null; - try { - Class oldmapClass = Class.forName("sun.util.calendar.TzIDOldMapping"); - Field map = oldmapClass.getDeclaredField("MAP"); - map.setAccessible(true); - oldmap = (Map) map.get(null); - } catch (Exception e) { - throw new RuntimeException("can't get TzIDOldMapping.MAP", e); - } - + Map oldmap = TzIDOldMapping.MAP; String prop = System.getProperty(MAPPING_PROPERTY_NAME); System.out.println(MAPPING_PROPERTY_NAME + "=" + prop); diff --git a/jdk/src/share/classes/sun/util/calendar/TzIDOldMapping.java b/jdk/test/java/util/TimeZone/TzIDOldMapping.java similarity index 98% rename from jdk/src/share/classes/sun/util/calendar/TzIDOldMapping.java rename to jdk/test/java/util/TimeZone/TzIDOldMapping.java index 4f230074235..e9ea6b5dfe1 100644 --- a/jdk/src/share/classes/sun/util/calendar/TzIDOldMapping.java +++ b/jdk/test/java/util/TimeZone/TzIDOldMapping.java @@ -23,8 +23,6 @@ * questions. */ -package sun.util.calendar; - import java.util.Map; import java.util.HashMap; diff --git a/jdk/test/sun/util/calendar/zi/BackEnd.java b/jdk/test/sun/util/calendar/zi/BackEnd.java new file mode 100644 index 00000000000..29d0201b320 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/BackEnd.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2000, 2004, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +/** + * BackEnd is an abstract base class for a back-end of compiling + * Olson's zoneinfo database and generating Java zoneinfo database. + * + * @since 1.4 + */ +abstract class BackEnd { + + /** + * Receives each zone's TimeZone information which was created by + * {@link Zoneinfo#parse} in class Zoneinfo, + * and processes it. + * + * @param tz Timezone object for each zone + * @return 0 if no error occurred, otherwise 1. + */ + abstract int processZoneinfo(Timezone tz); + + /** + * Receives whole information which is generated by JavaZic's front-end + * in the form of Mapping object and generates all Java zone information + * files. + * + * @param m Mappings object which is generated by + * {@link Main#compile() Main.compile()}. + * @return 0 if no error occurred, otherwise 1. + */ + abstract int generateSrc(Mappings m); + + /** + * Decides which backend class should be used and returns its instance. + * @return an instance of backend class + */ + static BackEnd getBackEnd() { + if (Zoneinfo.isYearForTimeZoneDataSpecified) { + return new Simple(); + } else if (Main.outputDoc) { + return new GenDoc(); + } else { + return new Gen(); + } + } +} diff --git a/jdk/test/sun/util/calendar/zi/Checksum.java b/jdk/test/sun/util/calendar/zi/Checksum.java new file mode 100644 index 00000000000..01232503ac3 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/Checksum.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2000, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.zip.CRC32; + +/** + * Checksum provides methods for calculating a CRC32 value for a + * transitions table. + * + * @since 1.4 + */ +public class Checksum extends CRC32 +{ + /** + * Updates the CRC32 value from each byte of the given int + * value. The bytes are used in the big endian order. + * @param val the int value + */ + public void update(int val) { + byte[] b = new byte[4]; + b[0] = (byte)((val >>> 24) & 0xff); + b[1] = (byte)((val >>> 16) & 0xff); + b[2] = (byte)((val >>> 8) & 0xff); + b[3] = (byte)(val & 0xff); + update(b); + } + + /** + * Updates the CRC32 value from each byte of the given long + * value. The bytes are used in the big endian order. + * @param val the long value + */ + void update(long val) { + byte[] b = new byte[8]; + b[0] = (byte)((val >>> 56) & 0xff); + b[1] = (byte)((val >>> 48) & 0xff); + b[2] = (byte)((val >>> 40) & 0xff); + b[3] = (byte)((val >>> 32) & 0xff); + b[4] = (byte)((val >>> 24) & 0xff); + b[5] = (byte)((val >>> 16) & 0xff); + b[6] = (byte)((val >>> 8) & 0xff); + b[7] = (byte)(val & 0xff); + update(b); + } +} diff --git a/jdk/test/sun/util/calendar/zi/DayOfWeek.java b/jdk/test/sun/util/calendar/zi/DayOfWeek.java new file mode 100644 index 00000000000..9470d961b82 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/DayOfWeek.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2004, 2006, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +/** + * Day of week enum. + * + * @since 1.6 + */ + +enum DayOfWeek { + SUNDAY("Sun"), + MONDAY("Mon"), + TUESDAY("Tue"), + WEDNESDAY("Wed"), + THURSDAY("Thu"), + FRIDAY("Fri"), + SATURDAY("Sat"); + + private final String abbr; + + private DayOfWeek(String abbr) { + this.abbr = abbr; + } + + String getAbbr() { + return abbr; + } + + int value() { + return ordinal() + 1; + } +} diff --git a/jdk/test/sun/util/calendar/zi/Gen.java b/jdk/test/sun/util/calendar/zi/Gen.java new file mode 100644 index 00000000000..70ad6b572c0 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/Gen.java @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2000, 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.IOException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.DataOutputStream; +import java.io.RandomAccessFile; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Gen is one of back-end classes of javazic, and generates + * ZoneInfoMappings and zone-specific file for each zone. + */ +class Gen extends BackEnd { + + /** + * Generates datafile in binary TLV format for each time zone. + * Regarding contents of output files, see {@link ZoneInfoFile}. + * + * @param Timezone + * @return 0 if no errors, or 1 if error occurred. + */ + int processZoneinfo(Timezone tz) { + try { + int size; + String outputDir = Main.getOutputDir(); + String zonefile = ZoneInfoFile.getFileName(tz.getName()); + + /* If outputDir doesn't end with file-separator, adds it. */ + if (!outputDir.endsWith(File.separator)) { + outputDir += File.separatorChar; + } + + /* If zonefile includes file-separator, it's treated as part of + * pathname. And make directory if necessary. + */ + int index = zonefile.lastIndexOf(File.separatorChar); + if (index != -1) { + outputDir += zonefile.substring(0, index+1); + } + File outD = new File(outputDir); + outD.mkdirs(); + + FileOutputStream fos = + new FileOutputStream(outputDir + zonefile.substring(index+1)); + DataOutputStream dos = new DataOutputStream(fos); + + /* Output Label */ + dos.write(ZoneInfoFile.JAVAZI_LABEL, 0, + ZoneInfoFile.JAVAZI_LABEL.length); + + /* Output Version of ZoneInfoFile */ + dos.writeByte(ZoneInfoFile.JAVAZI_VERSION); + + List transitions = tz.getTransitions(); + if (transitions != null) { + List dstOffsets = tz.getDstOffsets(); + List offsets = tz.getOffsets(); + + if ((dstOffsets == null && offsets != null) || + (dstOffsets != null && offsets == null)) { + Main.panic("Data not exist. (dstOffsets or offsets)"); + return 1; + } + + /* Output Transition records */ + dos.writeByte(ZoneInfoFile.TAG_Transition); + size = transitions.size(); + dos.writeShort((size * 8) & 0xFFFF); + int dstoffset; + for (int i = 0; i < size; i++) { + /* if DST offset is 0, this means DST isn't used. + * (NOT: offset's index is 0.) + */ + if ((dstoffset = dstOffsets.get(i).intValue()) == -1) { + dstoffset = 0; + } + + dos.writeLong((transitions.get(i).longValue() << 12) + | (dstoffset << 4) + | offsets.get(i).intValue()); + + } + + /* Output data for GMTOffset */ + List gmtoffset = tz.getGmtOffsets(); + dos.writeByte(ZoneInfoFile.TAG_Offset); + size = gmtoffset.size(); + dos.writeShort((size * 4) & 0xFFFF); + for (int i = 0; i < size; i++) { + dos.writeInt(gmtoffset.get(i)); + } + } + + /* Output data for SimpleTimeZone */ + List stz = tz.getLastRules(); + if (stz != null) { + RuleRec[] rr = new RuleRec[2]; + boolean wall = true; + + rr[0] = stz.get(0); + rr[1] = stz.get(1); + + dos.writeByte(ZoneInfoFile.TAG_SimpleTimeZone); + wall = rr[0].getTime().isWall() && rr[1].getTime().isWall(); + if (wall) { + dos.writeShort(32); + } else { + dos.writeShort(40); + } + + for (int i = 0; i < 2; i++) { + dos.writeInt(rr[i].getMonthNum() - 1); // 0-based month number + dos.writeInt(rr[i].getDay().getDayForSimpleTimeZone()); + dos.writeInt(rr[i].getDay().getDayOfWeekForSimpleTimeZoneInt()); + dos.writeInt((int)rr[i].getTime().getTime()); + if (!wall) { + dos.writeInt((rr[i].getTime().getType() & 0xFF) - 1); + } + } + } + + /* Output RawOffset */ + dos.writeByte(ZoneInfoFile.TAG_RawOffset); + dos.writeShort(4); + dos.writeInt(tz.getRawOffset()); + + /* Output willGMTOffsetChange flag */ + if (tz.willGMTOffsetChange()) { + dos.writeByte(ZoneInfoFile.TAG_GMTOffsetWillChange); + dos.writeShort(1); + dos.writeByte(1); + } + + /* Output LastDSTSaving */ + dos.writeByte(ZoneInfoFile.TAG_LastDSTSaving); + dos.writeShort(2); + dos.writeShort(tz.getLastDSTSaving()/1000); + + /* Output checksum */ + dos.writeByte(ZoneInfoFile.TAG_CRC32); + dos.writeShort(4); + dos.writeInt(tz.getCRC32()); + + fos.close(); + dos.close(); + } catch(IOException e) { + Main.panic("IO error: "+e.getMessage()); + return 1; + } + + return 0; + } + + /** + * Generates ZoneInfoMappings in binary TLV format for each zone. + * Regarding contents of output files, see {@link ZoneInfoFile}. + * + * @param Mappings + * @return 0 if no errors, or 1 if error occurred. + */ + int generateSrc(Mappings map) { + try { + int index; + int block_size; + int roi_size; + long fp; + String outputDir = Main.getOutputDir(); + + /* If outputDir doesn't end with file-separator, adds it. */ + if (!outputDir.endsWith(File.separator)) { + outputDir += File.separatorChar; + } + + File outD = new File(outputDir); + outD.mkdirs(); + + /* Open ZoneInfoMapping file to write. */ + RandomAccessFile raf = + new RandomAccessFile(outputDir + ZoneInfoFile.JAVAZM_FILE_NAME, "rw"); + + /* Whether rawOffsetIndex list exists or not. */ + List roi = map.getRawOffsetsIndex(); + if (roi == null) { + Main.panic("Data not exist. (rawOffsetsIndex)"); + return 1; + } + roi_size = roi.size(); + + /* Whether rawOffsetIndexTable list exists or not. */ + List> roit = map.getRawOffsetsIndexTable(); + if (roit == null || roit.size() != roi_size) { + Main.panic("Data not exist. (rawOffsetsIndexTable) Otherwise, Invalid size"); + return 1; + } + + /* Output Label */ + raf.write(ZoneInfoFile.JAVAZM_LABEL, 0, + ZoneInfoFile.JAVAZM_LABEL.length); + + /* Output Version */ + raf.writeByte(ZoneInfoFile.JAVAZM_VERSION); + + index = ZoneInfoFile.JAVAZM_LABEL.length + 2; + + /* Output Version of Olson's tzdata */ + byte[] b = Main.getVersionName().getBytes("UTF-8"); + raf.writeByte(ZoneInfoFile.TAG_TZDataVersion); + raf.writeShort((b.length+1) & 0xFFFF); + raf.write(b); + raf.writeByte(0x00); + index += b.length + 4; + + /* Output ID list. */ + raf.writeByte(ZoneInfoFile.TAG_ZoneIDs); + block_size = 2; + raf.writeShort(block_size & 0xFFFF); + short nID = 0; + raf.writeShort(nID & 0xFFFF); + for (int i = 0; i < roi_size; i++) { + for (String key : roit.get(i)) { + byte size = (byte)key.getBytes("UTF-8").length; + raf.writeByte(size & 0xFF); + raf.write(key.getBytes("UTF-8"), 0, size); + block_size += 1 + size; + nID++; + } + } + fp = raf.getFilePointer(); + raf.seek(index); + raf.writeShort((block_size) & 0xFFFF); + raf.writeShort(nID & 0xFFFF); + raf.seek(fp); + + /* Output sorted rawOffset list. */ + raf.writeByte(ZoneInfoFile.TAG_RawOffsets); + index += 3 + block_size; + block_size = roi_size * 4; + raf.writeShort(block_size & 0xFFFF); + for (int i = 0; i < roi_size; i++) { + raf.writeInt(Integer.parseInt(roi.get(i).toString())); + } + + /* Output sorted rawOffsetIndex list. */ + raf.writeByte(ZoneInfoFile.TAG_RawOffsetIndices); + index += 3 + block_size; + block_size = 0; + raf.writeShort(block_size & 0xFFFF); + int num; + for (int i = 0; i < roi_size; i++) { + num = roit.get(i).size(); + block_size += num; + for (int j = 0; j < num; j++) { + raf.writeByte(i); + } + } + fp = raf.getFilePointer(); + raf.seek(index); + raf.writeShort((block_size) & 0xFFFF); + raf.seek(fp); + + /* Whether alias list exists or not. */ + Map a = map.getAliases(); + if (a == null) { + Main.panic("Data not exist. (aliases)"); + return 0; + } + + /* Output ID list. */ + raf.writeByte(ZoneInfoFile.TAG_ZoneAliases); + index += 3 + block_size; + block_size = 2; + raf.writeShort(block_size & 0xFFFF); + raf.writeShort(a.size() & 0xFFFF); + for (String key : a.keySet()) { + String alias = a.get(key); + byte key_size = (byte)key.length(); + byte alias_size = (byte)alias.length(); + raf.writeByte(key_size & 0xFF); + raf.write(key.getBytes("UTF-8"), 0, key_size); + raf.writeByte(alias_size & 0xFF); + raf.write(alias.getBytes("UTF-8"), 0, alias_size); + block_size += 2 + key_size + alias_size; + } + fp = raf.getFilePointer(); + raf.seek(index); + raf.writeShort((block_size) & 0xFFFF); + raf.seek(fp); + + /* Output the exclude list if it exists. */ + List excludedZones = map.getExcludeList(); + if (excludedZones != null) { + raf.writeByte(ZoneInfoFile.TAG_ExcludedZones); + index += 3 + block_size; + block_size = 2; + raf.writeShort(block_size & 0xFFFF); // place holder + raf.writeShort(excludedZones.size()); // the number of excluded zones + for (String name : excludedZones) { + byte size = (byte) name.length(); + raf.writeByte(size); // byte length + raf.write(name.getBytes("UTF-8"), 0, size); // zone name + block_size += 1 + size; + } + fp = raf.getFilePointer(); + raf.seek(index); + raf.writeShort(block_size & 0xFFFF); + raf.seek(fp); + } + + /* Close ZoneInfoMapping file. */ + raf.close(); + } catch(IOException e) { + Main.panic("IO error: "+e.getMessage()); + return 1; + } + + return 0; + } +} diff --git a/jdk/test/sun/util/calendar/zi/GenDoc.java b/jdk/test/sun/util/calendar/zi/GenDoc.java new file mode 100644 index 00000000000..c3b520ce292 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/GenDoc.java @@ -0,0 +1,778 @@ +/* + * Copyright (c) 2001, 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.StringTokenizer; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * GenDoc is one of back-end classes of javazic, and generates + * index.html and other html files which prints the detailed time zone + * information for each zone. + */ +class GenDoc extends BackEnd { + + private static final String docDir = "doc"; + + private static final String header1 = + "\n" + + "\n\n\n\n" + + "Java Platform, Standard Edition - TimeZone information based on "; + private static final String header3 = + "-->\n<TITLE>\n" + + "Java Platform, Standard Edition TimeZone - "; + private static final String header4 = + "\n" + + "\n\n"; + + private static final String body1 = + "\n"; + private static final String body2 = + "\n"; + + private static final String footer = + "\n"; + + + // list of time zone name and zonefile name/real time zone name + // e.g. + // key (String) : value (String) + // "America/Denver" : "America/Denver.html" (real time zone) + // "America/Shiprock" : "America/Denver" (alias) + TreeMap timezoneList = new TreeMap(); + + // list of time zone's display name and time zone name + // e.g. + // key (String) : value (String) + // "Tokyo, Asia" : "Asia/Tokyo" + // "Marengo, Indiana, America" : "America/Indiana/Marengo" + // (aliases included) + TreeMap displayNameList = new TreeMap(); + + // list of top level regions + // e.g. + // key (String) : value (String) + // "America" : "America.html" + // (including entries in America/Indiana/, America/Kentucky/, ...) + TreeMap regionList = new TreeMap(); + + // mapping list from zone name to latitude & longitude + // This list is generated from zone.tab. + // e.g. + // key (String) : value (LatitudeAndLongitude object) + // "Asia/Tokyo" : latitude=35.3916, longitude=13.9444 + // (aliases not included) + HashMap mapList = null; + + // SortedMap of zone IDs sorted by their GMT offsets. If zone's GMT + // offset will change in the future, its last known offset is + // used. + SortedMap> zonesByOffset = new TreeMap>(); + + /** + * Generates HTML document for each zone. + * @param Timezone + * @return 0 if no errors, or 1 if error occurred. + */ + int processZoneinfo(Timezone tz) { + try { + int size; + int index; + String outputDir = Main.getOutputDir(); + String zonename = tz.getName(); + String zonefile = ZoneInfoFile.getFileName(zonename) + ".html"; + List stz = tz.getLastRules(); + timezoneList.put(zonename, zonefile); + displayNameList.put(transform(zonename), zonename); + + // Populate zonesByOffset. (Zones that will change their + // GMT offsets are also added to zonesByOffset here.) + int lastKnownOffset = tz.getRawOffset(); + Set set = zonesByOffset.get(lastKnownOffset); + if (set == null) { + set = new TreeSet(); + zonesByOffset.put(lastKnownOffset, set); + } + set.add(zonename); + + /* If outputDir doesn't end with file-separator, adds it. */ + if (!outputDir.endsWith(File.separator)) { + outputDir += File.separatorChar; + } + outputDir += docDir + File.separatorChar; + + index = zonename.indexOf('/'); + if (index != -1) { + regionList.put(zonename.substring(0, index), + zonename.substring(0, index) + ".html"); + } + + /* If zonefile includes file-separator, it's treated as part of + * pathname. And make directory if necessary. + */ + index = zonefile.lastIndexOf('/'); + if (index != -1) { + zonefile.replace('/', File.separatorChar); + outputDir += zonefile.substring(0, index+1); + } + File outD = new File(outputDir); + outD.mkdirs(); + + /* If mapfile is available, add a link to the appropriate map */ + if ((mapList == null) && (Main.getMapFile() != null)) { + FileReader fr = new FileReader(Main.getMapFile()); + BufferedReader in = new BufferedReader(fr); + mapList = new HashMap(); + String line; + while ((line = in.readLine()) != null) { + // skip blank and comment lines + if (line.length() == 0 || line.charAt(0) == '#') { + continue; + } + StringTokenizer tokens = new StringTokenizer(line); + String token = tokens.nextToken(); /* We don't use the first token. */ + token = tokens.nextToken(); + LatitudeAndLongitude location = new LatitudeAndLongitude(token); + token = tokens.nextToken(); + mapList.put(token, location); + } + in.close(); + } + + /* Open zoneinfo file to write. */ + FileWriter fw = new FileWriter(outputDir + zonefile.substring(index+1)); + BufferedWriter out = new BufferedWriter(fw); + + out.write(header1 + new Date() + header3 + zonename + header4); + out.write(body1 + "" + zonename + ""); + LatitudeAndLongitude location = mapList.get(zonename); + if (location != null) { + int deg, min, sec; + + deg = location.getLatDeg(); + min = location.getLatMin(); + sec = location.getLatSec(); + if (deg < 0) { + min = -min; + sec = -sec; + } else if (min < 0) { + sec = -sec; + } + out.write("   " + + "[map]"); + } + out.write("\n

    \n"); + + List zone = tz.getZones(); + List rule = tz.getRules(); + if (rule != null && zone != null) { + out.write("\n" + + "\n" + + "\n" + + "\n" + + "\n

    " + + "Rules
    " + + "
    Zone
    \n"); + } + + /* Output Rule records. */ + if (rule != null) { + size = rule.size(); + out.write("

    \n" + + "Rules\n" + + "\n" + + "\n" + + "" + + "" + + "\n\n"); + for (int i = 0; i < size; i++) { + out.write("\n"); + StringTokenizer st = new StringTokenizer(rule.get(i).getLine()); + String s; + if (st.hasMoreTokens()) { /* RULE - truncated */ + st.nextToken(); + } + if (st.hasMoreTokens()) { /* NAME */ + out.write(""); + } + if (st.hasMoreTokens()) { /* FROM */ + out.write(""); + } + if (st.hasMoreTokens()) { /* TO */ + s = st.nextToken(); + if (s.equals("min") || s.equals("max")) { + out.write(""); + } else { + out.write(""); + } + } + if (st.hasMoreTokens()) { /* TYPE */ + out.write(""); + } + if (st.hasMoreTokens()) { /* IN */ + out.write(""); + } + if (st.hasMoreTokens()) { /* ON */ + out.write(""); + } + if (st.hasMoreTokens()) { /* AT */ + out.write(""); + } + if (st.hasMoreTokens()) { /* SAVE */ + out.write(""); + } + if (st.hasMoreTokens()) { /* LETTER/S */ + out.write(""); + } + if (st.hasMoreTokens()) { /* NOTES */ + s = st.nextToken(); + while (st.hasMoreTokens()) { + s += " " + st.nextToken(); + } + index = s.indexOf('#'); + out.write("\n"); + } else { + out.write("\n"); + } + out.write("\n"); + } + out.write("
    NAMEFROMTOTYPEINONATSAVELETTER/SNOTES
    " + st.nextToken() + "" + st.nextToken() + "" + s + "" + s + "" + st.nextToken() + "" + st.nextToken() + "" + st.nextToken() + "" + st.nextToken() + "" + st.nextToken() + "" + st.nextToken() + "" + s.substring(index+1) + " 
    \n

     

    \n"); + } + + /* Output Zone records. */ + if (zone != null) { + size = zone.size(); + out.write("

    \n" + + "Zone\n" + + "\n" + + "\n" + + "" + + "\n\n"); + for (int i = 0; i < size; i++) { + out.write("\n"); + StringTokenizer st = new StringTokenizer(zone.get(i).getLine()); + String s = st.nextToken(); + if (s.equals("Zone")) { /* NAME */ + s = st.nextToken(); + s = st.nextToken(); + } + out.write(""); /* GMTOFFSET */ + if (st.hasMoreTokens()) { /* RULES */ + out.write(""); + } + if (st.hasMoreTokens()) { /* FORMAT */ + s = st.nextToken(); + index = s.indexOf('#'); + if (index != -1) { + if (index != 0) { + out.write(""); /* FORMAT */ + s = s.substring(index+1); + } else { + out.write(""); /* FORMAT */ + } + while (st.hasMoreTokens()) { + s += " " + st.nextToken(); + } + out.write(""); /* UNTIL */ + out.write("\n\n"); /* NOTES */ + continue; + } else { + out.write(""); /* FORMAT */ + } + } + + if (st.hasMoreTokens()) { /* UNTIL */ + s = st.nextToken(); + while (st.hasMoreTokens()) { + s += " " + st.nextToken(); + } + index = s.indexOf('#'); + if (index != -1) { + if (index != 0) { + out.write(""); /* UNTIL */ + } else { + out.write(""); /* UNTIL */ + } + out.write("\n"); /* NOTES */ + } else { + out.write(""); /* UNTIL */ + out.write("\n"); /* NOTES */ + } + } else { + out.write(""); /* UNTIL */ + out.write("\n"); /* NOTES */ + } + out.write("\n"); + } + out.write("
    GMTOFFRULESFORMATUNTILNOTES
    " + s + "" + st.nextToken() + "" + s.substring(0, index-1) + + "  " + s + "
    " + s + "" + s.substring(0, index-1) + + " " + s.substring(index+1) + + "" + s + "   
    \n"); + } + out.write(body2 + footer); + + out.close(); + fw.close(); + } catch(IOException e) { + Main.panic("IO error: "+e.getMessage()); + return 1; + } + + return 0; + } + + /** + * Generates index.html and other top-level frame files. + * @param Mappings + * @return 0 if no errors, or 1 if error occurred. + */ + int generateSrc(Mappings map) { + try { + int len; + Object o[]; + String outputDir = Main.getOutputDir(); + FileWriter fw1, fw2; + BufferedWriter out1, out2; + + /* Whether alias list exists or not. */ + Map a = map.getAliases(); + if (a == null) { + Main.panic("Data not exist. (aliases)"); + return 1; + } + + timezoneList.putAll(a); + + /* If outputDir doesn't end with file-separator, adds it. */ + if (!outputDir.endsWith(File.separator)) { + outputDir += File.separatorChar; + } + outputDir += docDir + File.separatorChar; + + File outD = new File(outputDir); + outD.mkdirs(); + + /* Creates index.html */ + fw1 = new FileWriter(outputDir + "index.html", false); + out1 = new BufferedWriter(fw1); + + out1.write(header1 + new Date() + header2 + Main.getVersionName() + + header4 + + "\n" + + "\n" + + "\n" + + "\n" + + "" + + "\n" + + "\n" + + "\n" + + "<H2>\nFrame Alert\n</H2>\n\n" + + "<P>\n\n" + + "This document is designed to be viewed using the frames feature. If you see this\n" + + "message, you are using a non-frame-capable web client.\n" + + "<BR>\n" + + "Link to<A HREF=\"overview-summary.html\">Non-frame version.</A>\n" + + "\n" + footer); + + out1.close(); + fw1.close(); + + + /* Creates overview-frame.html */ + fw1 = new FileWriter(outputDir + "overview-frame.html", false); + out1 = new BufferedWriter(fw1); + + out1.write(header1 + new Date() + header2 + Main.getVersionName() + + header4 + body1 + + "\n\n" + + "\n" + + "\n
    \n" + + "JavaTM Platform
    Standard Ed.
    \n\n" + + "\n\n\n
    " + + "

    \n\nAll Time Zones Sorted By:\n
    \n" + + "  GMT offsets\n
    \n" + + "  Zone names\n
    " + + "  City names\n" + + "

    \n\nContinents and Oceans\n
    \n"); + + for (String regionKey : regionList.keySet()) { + out1.write("  " + regionKey + + "
    \n"); + + fw2 = new FileWriter(outputDir + regionList.get(regionKey), + false); + out2 = new BufferedWriter(fw2); + + out2.write(header1 + new Date() + header3 + regionKey + + header4 + body1 + "" + + regionKey + "\n
    \n\n\n\n\n
    "); + + boolean found = false; + for (String timezoneKey : timezoneList.keySet()) { + int regionIndex = timezoneKey.indexOf('/'); + if (regionIndex == -1 || + !regionKey.equals(timezoneKey.substring(0, regionIndex))) { + if (found) { + break; + } else { + continue; + } + } + + found = true; + if (a.containsKey(timezoneKey)) { + Object realName = a.get(timezoneKey); + while (a.containsKey(realName)) { + realName = a.get(realName); + } + out2.write(timezoneKey + + " (alias for " + "" + + realName + ")"); + } else { + out2.write("" + timezoneKey + + ""); + } + out2.write("
    \n"); + } + out2.write("
    \n" + body2 + footer); + + out2.close(); + fw2.close(); + } + out1.write("

    \n" + body2 + footer); + + out1.close(); + fw1.close(); + + + /* Creates allTimeZone-frame1.html (Sorted by GMT offsets) */ + fw1 = new FileWriter(outputDir + "allTimeZone-frame1.html", false); + out1 = new BufferedWriter(fw1); + + out1.write(header1 + new Date() + header2 + Main.getVersionName() + + header4 + body1 + + "Sorted by GMT offsets\n" + + "
    \n\n" + "\n" + + "\n\n\n\n\n"); + } + } + out1.write("\n\n
    \n"); + + List roi = map.getRawOffsetsIndex(); + List> roit = map.getRawOffsetsIndexTable(); + + int index = 0; + for (Integer offset : zonesByOffset.keySet()) { + int off = roi.get(index); + Set perRO = zonesByOffset.get(offset); + if (offset == off) { + // Merge aliases into zonesByOffset + perRO.addAll(roit.get(index)); + } + index++; + + for (String timezoneKey : perRO) { + out1.write("
    (" + + Time.toGMTFormat(offset.toString()) + + ")"); + + if (a.containsKey(timezoneKey)) { + Object realName = a.get(timezoneKey); + while (a.containsKey(realName)) { + realName = a.get(realName); + } + out1.write(timezoneKey + + " (alias for " + "" + realName + + ")"); + } else { + out1.write("" + timezoneKey + + ""); + } + out1.write("
    \n" + body2 + footer); + + out1.close(); + fw1.close(); + + + /* Creates allTimeZone-frame2.html (Sorted by zone names) */ + fw1 = new FileWriter(outputDir + "allTimeZone-frame2.html", false); + out1 = new BufferedWriter(fw1); + + out1.write(header1 + new Date() + header2 + Main.getVersionName() + + header4 + body1 + + "Sorted by zone names\n" + + "
    \n\n" + "\n" + + "\n\n\n
    \n"); + o = timezoneList.keySet().toArray(); + len = timezoneList.size(); + for (int i = 0; i < len; i++) { + Object timezoneKey = o[i]; + if (a.containsKey(timezoneKey)) { + Object realName = a.get(timezoneKey); + while (a.containsKey(realName)) { + realName = a.get(realName); + } + out1.write(timezoneKey + + " (alias for " + + "" + realName + + ")"); + } else { + out1.write("" + timezoneKey + + ""); + } + out1.write("
    \n"); + } + out1.write("
    \n" + body2 + footer); + + out1.close(); + fw1.close(); + + /* Creates allTimeZone-frame3.html (Sorted by city names) */ + fw1 = new FileWriter(outputDir + "allTimeZone-frame3.html", false); + out1 = new BufferedWriter(fw1); + + out1.write(header1 + new Date() + header2 + Main.getVersionName() + + header4 + body1 + + "Sorted by city names\n" + + "
    \n\n" + "\n" + + "\n\n\n
    \n"); + + Set aliasSet = a.keySet(); + len = aliasSet.size(); + String aliasNames[] = aliasSet.toArray(new String[0]); + for (int i = 0; i < len; i++) { + displayNameList.put(transform(aliasNames[i]), + aliasNames[i]); + } + + o = displayNameList.keySet().toArray(); + len = displayNameList.size(); + for (int i = 0; i < len; i++) { + Object displayName = o[i]; + Object timezoneKey = displayNameList.get(o[i]); + if (a.containsKey(timezoneKey)) { + Object realName = a.get(timezoneKey); + while (a.containsKey(realName)) { + realName = a.get(realName); + } + out1.write(displayName + + " (alias for " + + "" + realName + + ")"); + } else { + out1.write("" + displayName + + ""); + } + out1.write("
    \n"); + } + + out1.write("
    \n" + body2 + footer); + + out1.close(); + fw1.close(); + + /* Creates overview-summary.html */ + fw1 = new FileWriter(outputDir + "overview-summary.html", false); + out1 = new BufferedWriter(fw1); + + out1.write(header1 + new Date() + header2 + Main.getVersionName() + + header4 + body1 + + "

    This is the list of time zones generated from " + + Main.getVersionName() + " for Java Platform, " + + "Standard Edition. The source code can be obtained " + + "from ftp site " + + "ftp://elsie.nci.nih.gov/pub/. A total of " + + len + + " time zones and aliases are supported " + + "in this edition. For the " + + "format of rules and zones, refer to the zic " + + "(zoneinfo compiler) man page on " + + "Solaris or Linux.

    \n" + + "

    Note that the time zone data is not " + + "a public interface of the Java Platform. No " + + "applications should rely on the time zone data of " + + "this document. Time zone names and data " + + "may change without any prior notice.

    \n" + + body2 + footer); + + out1.close(); + fw1.close(); + } catch(IOException e) { + Main.panic("IO error: "+e.getMessage()); + return 1; + } + + return 0; + } + + String transform(String s) { + int index = s.lastIndexOf("/"); + + /* If the string doesn't include any delimiter, return */ + if (index == -1) { + return s; + } + + int lastIndex = index; + String str = s.substring(index+1); + do { + index = s.substring(0, lastIndex).lastIndexOf('/'); + str += ", " + s.substring(index+1, lastIndex); + lastIndex = index; + } while (index > -1); + + return str; + } + + static class LatitudeAndLongitude { + + private int latDeg, latMin, latSec, longDeg, longMin, longSec; + + LatitudeAndLongitude(String s) { + try { + // First of all, check the string has the correct format: + // either +-DDMM+-DDDMM or +-DDMMSS+-DDDMMSS + + if (!s.startsWith("+") && !s.startsWith("-")) { + Main.warning("Wrong latitude&longitude data: " + s); + return; + } + int index; + if (((index = s.lastIndexOf("+")) <= 0) && + ((index = s.lastIndexOf("-")) <= 0)) { + Main.warning("Wrong latitude&longitude data: " + s); + return; + } + + if (index == 5) { + latDeg = Integer.parseInt(s.substring(1, 3)); + latMin = Integer.parseInt(s.substring(3, 5)); + latSec = 0; + } else if (index == 7) { + latDeg = Integer.parseInt(s.substring(1, 3)); + latMin = Integer.parseInt(s.substring(3, 5)); + latSec = Integer.parseInt(s.substring(5, 7)); + } else { + Main.warning("Wrong latitude&longitude data: " + s); + return; + } + if (s.startsWith("-")){ + latDeg = -latDeg; + latMin = -latMin; + latSec = -latSec; + } + + int len = s.length(); + if (index == 5 && len == 11) { + longDeg = Integer.parseInt(s.substring(index+1, index+4)); + longMin = Integer.parseInt(s.substring(index+4, index+6)); + longSec = 0; + } else if (index == 7 && len == 15) { + longDeg = Integer.parseInt(s.substring(index+1, index+4)); + longMin = Integer.parseInt(s.substring(index+4, index+6)); + longSec = Integer.parseInt(s.substring(index+6, index+8)); + } else { + Main.warning("Wrong latitude&longitude data: " + s); + return; + } + if (s.charAt(index) == '-'){ + longDeg = -longDeg; + longMin = -longMin; + longSec = -longSec; + } + } catch(Exception e) { + Main.warning("LatitudeAndLongitude() Parse error: " + s); + } + } + + int getLatDeg() { + return latDeg; + } + + int getLatMin() { + return latMin; + } + + int getLatSec() { + return latSec; + } + + int getLongDeg() { + return longDeg; + } + + int getLongMin() { + return longMin; + } + + int getLongSec() { + return longSec; + } + } +} diff --git a/jdk/test/sun/util/calendar/zi/Main.java b/jdk/test/sun/util/calendar/zi/Main.java new file mode 100644 index 00000000000..6fde7cd147d --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/Main.java @@ -0,0 +1,234 @@ +/* + * Copyright (c) 2000, 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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; + +/** + * Main class for the javazic time zone data compiler. + * + * @since 1.4 + */ +public class Main { + + private static boolean verbose = false; + static boolean outputDoc = false; + + private List ziFiles = new ArrayList(); + private static String zoneNamesFile = null; + private static String versionName = "unknown"; + private static String outputDir = "zoneinfo"; + private static String mapFile = null; + + /** + * Parses the specified arguments and sets up the variables. + * @param argv the arguments + */ + void processArgs(String[] argv) { + for (int i = 0; i < argv.length; i++) { + String arg = argv[i]; + if (arg.startsWith("-h")) { + usage(); + System.exit(0); + } else if (arg.equals("-d")) { + outputDir = argv[++i]; + } else if (arg.equals("-v")) { + verbose = true; + } else if (arg.equals("-V")) { + versionName = argv[++i]; + } else if (arg.equals("-doc")) { + outputDoc = true; + } else if (arg.equals("-map")) { + outputDoc = true; + mapFile = argv[++i]; + } else if (arg.equals("-f")) { + zoneNamesFile = argv[++i]; + } else if (arg.equals("-S")) { + try { + Zoneinfo.setYear(Integer.parseInt(argv[++i])); + } catch (Exception e) { + error("invalid year: " + argv[i]); + usage(); + System.exit(1); + } + } else { + boolean isStartYear = arg.equals("-s"); + if (isStartYear || arg.equals("-e")) { + try { + int year = Integer.parseInt(argv[++i]); + if (isStartYear) { + Zoneinfo.setStartYear(year); + } else { + Zoneinfo.setEndYear(year); + } + } catch (Exception e) { + error("invalid year: " + argv[i]); + usage(); + System.exit(1); + } + } else { + // the rest of args are zoneinfo source files + while (i < argv.length) { + ziFiles.add(argv[i++]); + } + } + } + } + } + + /** + * Parses zoneinfo source files + */ + int compile() { + int nFiles = ziFiles.size(); + int status = 0; + Mappings maps = new Mappings(); + BackEnd backend = BackEnd.getBackEnd(); + + for (int i = 0; i < nFiles; i++) { + Zoneinfo frontend = Zoneinfo.parse(ziFiles.get(i)); + + for (String key : frontend.getZones().keySet()) { + info(key); + + Timezone tz = frontend.phase2(key); + status |= backend.processZoneinfo(tz); + } + + maps.add(frontend); + } + + // special code for dealing with the conflicting name "MET" + Zone.addMET(); + + maps.resolve(); + + status |= backend.generateSrc(maps); + + return status; + } + + public static void main(String[] argv) { + Main zic = new Main(); + + /* + * Parse args + */ + zic.processArgs(argv); + + /* + * Read target zone names + */ + if (zoneNamesFile != null) { + Zone.readZoneNames(zoneNamesFile); + } + + zic.compile(); + } + + void usage() { + System.err.println("Usage: javazic [options] file...\n"+ + " -f namefile file containing zone names\n"+ + " to be generated (ie, generating subset)\n"+ + " -d dir output directory\n"+ + " -v verbose\n"+ + " -V datavers specifies the tzdata version string\n"+ + " (eg, \"tzdata2000g\")"+ + " -S year output only SimleTimeZone data of that year\n"+ + " -s year start year (default: 1900)\n"+ + " -e year end year (default: 2037)\n"+ + " -doc generates HTML documents\n"+ + " -map mapfile generates HTML documents with map information\n"+ + " file... zoneinfo source file(s)"); + } + + /** + * @return the output directory path name + */ + static String getOutputDir() { + return outputDir; + } + + /** + * @return the map file's path and name + */ + static String getMapFile() { + return mapFile; + } + + /** + * Returns the time zone data version string specified by the -V + * option. If it is not specified, "unknown" is returned. + * @return the time zone data version string + */ + static String getVersionName() { + return versionName; + } + + /** + * Prints out the specified fatal error message and calls {@link + * java.lang.System#exit System.exit(1)}. + * @param msg the fatal error message + */ + static void panic(String msg) { + printMessage("fatal error", msg); + System.exit(1); + } + + /** + * Prints out the specified error message. + * @param msg the error message + */ + static void error(String msg) { + printMessage("error", msg); + } + + /** + * Prints out the specified warning message. + * @param msg the warning message + */ + static void warning(String msg) { + printMessage("warning", msg); + } + + /** + * Prints out the informative message. + * @param msg the informative message + */ + static void info(String msg) { + if (verbose) { + printMessage(null, msg); + } + } + + private static void printMessage(String type, String msg) { + if (type != null) { + type += ": "; + } else { + type = ""; + } + System.err.println("javazic: " + type + msg); + } +} diff --git a/jdk/test/sun/util/calendar/zi/Mappings.java b/jdk/test/sun/util/calendar/zi/Mappings.java new file mode 100644 index 00000000000..2e12d8659e2 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/Mappings.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2000, 2012, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * Mappings generates two Maps and a List which are used by + * javazic BackEnd. + * + * @since 1.4 + */ +class Mappings { + // All aliases specified by Link statements. It's alias name to + // real name mappings. + private Map aliases; + + private List rawOffsetsIndex; + + private List> rawOffsetsIndexTable; + + // Zone names to be excluded from rawOffset table. Those have GMT + // offsets to change some future time. + private List excludeList; + + /** + * Constructor creates some necessary instances. + */ + Mappings() { + aliases = new TreeMap(); + rawOffsetsIndex = new LinkedList(); + rawOffsetsIndexTable = new LinkedList>(); + } + + /** + * Generates aliases and rawOffsets tables. + * @param zi a Zoneinfo containing Zones + */ + void add(Zoneinfo zi) { + Map zones = zi.getZones(); + + for (String zoneName : zones.keySet()) { + Zone zone = zones.get(zoneName); + String zonename = zone.getName(); + int rawOffset = zone.get(zone.size()-1).getGmtOffset(); + + // If the GMT offset of this Zone will change in some + // future time, this Zone is added to the exclude list. + boolean isExcluded = false; + for (int i = 0; i < zone.size(); i++) { + ZoneRec zrec = zone.get(i); + if ((zrec.getGmtOffset() != rawOffset) + && (zrec.getUntilTime(0) > Time.getCurrentTime())) { + if (excludeList == null) { + excludeList = new ArrayList(); + } + excludeList.add(zone.getName()); + isExcluded = true; + break; + } + } + + if (!rawOffsetsIndex.contains(new Integer(rawOffset))) { + // Find the index to insert this raw offset zones + int n = rawOffsetsIndex.size(); + int i; + for (i = 0; i < n; i++) { + if (rawOffsetsIndex.get(i) > rawOffset) { + break; + } + } + rawOffsetsIndex.add(i, rawOffset); + + Set perRawOffset = new TreeSet(); + if (!isExcluded) { + perRawOffset.add(zonename); + } + rawOffsetsIndexTable.add(i, perRawOffset); + } else if (!isExcluded) { + int i = rawOffsetsIndex.indexOf(new Integer(rawOffset)); + Set perRawOffset = rawOffsetsIndexTable.get(i); + perRawOffset.add(zonename); + } + } + + Map a = zi.getAliases(); + // If there are time zone names which refer to any of the + // excluded zones, add those names to the excluded list. + if (excludeList != null) { + for (String zoneName : a.keySet()) { + String realname = a.get(zoneName); + if (excludeList.contains(realname)) { + excludeList.add(zoneName); + } + } + } + aliases.putAll(a); + } + + /** + * Adds valid aliases to one of per-RawOffset table and removes + * invalid aliases from aliases List. Aliases referring to + * excluded zones are not added to a per-RawOffset table. + */ + void resolve() { + int index = rawOffsetsIndexTable.size(); + List toBeRemoved = new ArrayList(); + for (String key : aliases.keySet()) { + boolean validname = false; + for (int j = 0; j < index; j++) { + Set perRO = rawOffsetsIndexTable.get(j); + boolean isExcluded = (excludeList == null) ? + false : excludeList.contains(key); + + if ((perRO.contains(aliases.get(key)) || isExcluded) + && Zone.isTargetZone(key)) { + validname = true; + if (!isExcluded) { + perRO.add(key); + Main.info("Alias <"+key+"> added to the list."); + } + break; + } + } + + if (!validname) { + Main.info("Alias <"+key+"> removed from the list."); + toBeRemoved.add(key); + } + } + + // Remove zones, if any, from the list. + for (String key : toBeRemoved) { + aliases.remove(key); + } + // Eliminate any alias-to-alias mappings. For example, if + // there are A->B and B->C, A->B is changed to A->C. + Map newMap = new HashMap(); + for (String key : aliases.keySet()) { + String realid = aliases.get(key); + String leaf = realid; + while (aliases.get(leaf) != null) { + leaf = aliases.get(leaf); + } + if (!realid.equals(leaf)) { + newMap.put(key, leaf); + } + } + aliases.putAll(newMap); + } + + Map getAliases() { + return(aliases); + } + + List getRawOffsetsIndex() { + return(rawOffsetsIndex); + } + + List> getRawOffsetsIndexTable() { + return(rawOffsetsIndexTable); + } + + List getExcludeList() { + return excludeList; + } +} diff --git a/jdk/test/sun/util/calendar/zi/Month.java b/jdk/test/sun/util/calendar/zi/Month.java new file mode 100644 index 00000000000..f2db5f135d1 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/Month.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2000, 2004, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Month enum handles month related manipulation. + * + * @since 1.4 + */ +enum Month { + JANUARY("Jan"), + FEBRUARY("Feb"), + MARCH("Mar"), + APRIL("Apr"), + MAY("May"), + JUNE("Jun"), + JULY("Jul"), + AUGUST("Aug"), + SEPTEMBER("Sep"), + OCTOBER("Oct"), + NOVEMBER("Nov"), + DECEMBER("Dec"); + + private final String abbr; + + private static final Map abbreviations + = new HashMap(12); + + static { + for (Month m : Month.values()) { + abbreviations.put(m.abbr, m); + } + } + + private Month(String abbr) { + this.abbr = abbr; + } + + int value() { + return ordinal() + 1; + } + + /** + * Parses the specified string as a month abbreviation. + * @param name the month abbreviation + * @return the Month value + */ + static Month parse(String name) { + Month m = abbreviations.get(name); + if (m != null) { + return m; + } + return null; + } + + /** + * @param month the nunmth number (1-based) + * @return the month name in uppercase of the specified month + */ + static String toString(int month) { + if (month >= JANUARY.value() && month <= DECEMBER.value()) { + return "Calendar." + Month.values()[month - 1]; + } + throw new IllegalArgumentException("wrong month number: " + month); + } +} diff --git a/jdk/test/sun/util/calendar/zi/Rule.java b/jdk/test/sun/util/calendar/zi/Rule.java new file mode 100644 index 00000000000..8e3a1189bb9 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/Rule.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2000, 2004, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.StringTokenizer; + +/** + * Rule manipulates Rule records. + * + * @since 1.4 + */ +class Rule { + + private List list; + private String name; + + /** + * Constructs a Rule which consists of a Rule record list. The + * specified name is given to this Rule. + * @param name the Rule name + */ + Rule(String name) { + this.name = name; + list = new ArrayList(); + } + + /** + * Added a RuleRec to the Rule record list. + */ + void add(RuleRec rec) { + list.add(rec); + } + + /** + * @return the Rule name + */ + String getName() { + return name; + } + + /** + * Gets all rule records that cover the given year. + * + * @param year the year number for which the rule is applicable. + * @return rules in List that are collated in time. If no rule is found, an empty + * List is returned. + */ + List getRules(int year) { + List rules = new ArrayList(3); + for (RuleRec rec : list) { + if (year >= rec.getFromYear() && year <= rec.getToYear()) { + if ((rec.isOdd() && year % 2 == 0) || (rec.isEven() && year % 2 == 1)) + continue; + rules.add(rec); + } + } + int n = rules.size(); + if (n <= 1) { + return rules; + } + if (n == 2) { + RuleRec rec1 = rules.get(0); + RuleRec rec2 = rules.get(1); + if (rec1.getMonthNum() > rec2.getMonthNum()) { + rules.set(0, rec2); + rules.set(1, rec1); + } else if (rec1.getMonthNum() == rec2.getMonthNum()) { + // TODO: it's not accurate to ignore time types (STD, WALL, UTC) + long t1 = Time.getLocalTime(year, rec1.getMonth(), + rec1.getDay(), rec1.getTime().getTime()); + long t2 = Time.getLocalTime(year, rec2.getMonth(), + rec2.getDay(), rec2.getTime().getTime()); + if (t1 > t2) { + rules.set(0, rec2); + rules.set(1, rec1); + } + } + return rules; + } + + final int y = year; + RuleRec[] recs = new RuleRec[rules.size()]; + rules.toArray(recs); + Arrays.sort(recs, new Comparator() { + public int compare(RuleRec r1, RuleRec r2) { + int n = r1.getMonthNum() - r2.getMonthNum(); + if (n != 0) { + return n; + } + // TODO: it's not accurate to ignore time types (STD, WALL, UTC) + long t1 = Time.getLocalTime(y, r1.getMonth(), + r1.getDay(), r1.getTime().getTime()); + long t2 = Time.getLocalTime(y, r2.getMonth(), + r2.getDay(), r2.getTime().getTime()); + return (int)(t1 - t2); + } + public boolean equals(Object o) { + return this == o; + } + }); + rules.clear(); + for (int i = 0; i < n; i++) { + rules.add(recs[i]); + } + return rules; + } + + /** + * Gets rule records that have either "max" or cover the endYear + * value in its DST schedule. + * + * @return rules that contain last DST schedule. An empty + * ArrayList is returned if no last rules are found. + */ + List getLastRules() { + RuleRec start = null; + RuleRec end = null; + + for (int i = 0; i < list.size(); i++) { + RuleRec rec = list.get(i); + if (rec.isLastRule()) { + if (rec.getSave() > 0) { + start = rec; + } else { + end = rec; + } + } + } + if (start == null || end == null) { + int endYear = Zoneinfo.getEndYear(); + for (int i = 0; i < list.size(); i++) { + RuleRec rec = list.get(i); + if (endYear >= rec.getFromYear() && endYear <= rec.getToYear()) { + if (start == null && rec.getSave() > 0) { + start = rec; + } else { + if (end == null && rec.getSave() == 0) { + end = rec; + } + } + } + } + } + + List r = new ArrayList(2); + if (start == null || end == null) { + if (start != null || end != null) { + Main.warning("found last rules for "+name+" inconsistent."); + } + return r; + } + + r.add(start); + r.add(end); + return r; + } +} diff --git a/jdk/test/sun/util/calendar/zi/RuleDay.java b/jdk/test/sun/util/calendar/zi/RuleDay.java new file mode 100644 index 00000000000..a9e83aceb10 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/RuleDay.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2000, 2010, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.HashMap; +import java.util.List; +import java.util.Map; + +/** + * RuleDay class represents the value of the "ON" field. The day of + * week values start from 1 following the {@link java.util.Calendar} + * convention. + * + * @since 1.4 + */ +class RuleDay { + private static final Map abbreviations = new HashMap(7); + static { + for (DayOfWeek day : DayOfWeek.values()) { + abbreviations.put(day.getAbbr(), day); + } + } + + private String dayName = null; + private DayOfWeek dow; + private boolean lastOne = false; + private int soonerOrLater = 0; + private int thanDayOfMonth; // day of month (e.g., 8 for "Sun>=8") + + RuleDay() { + } + + RuleDay(int day) { + thanDayOfMonth = day; + } + + int getDay() { + return thanDayOfMonth; + } + + /** + * @return the day of week value (1-based) + */ + int getDayOfWeekNum() { + return dow.value(); + } + + /** + * @return true if this rule day represents the last day of + * week. (e.g., lastSun). + */ + boolean isLast() { + return lastOne; + } + + /** + * @return true if this rule day represents the day of week on or + * later than (after) the {@link #getDay}. (e.g., Sun>=1) + */ + boolean isLater() { + return soonerOrLater > 0; + } + + /** + * @return true if this rule day represents the day of week on or + * earlier than (before) the {@link #getDay}. (e.g., Sun<=15) + */ + boolean isEarlier() { + return soonerOrLater < 0; + } + + /** + * @return true if this rule day represents an exact day. + */ + boolean isExact() { + return soonerOrLater == 0; + } + + /** + * Parses the "ON" field and constructs a RuleDay. + * @param day an "ON" field string (e.g., "Sun>=1") + * @return a RuleDay representing the given "ON" field + */ + static RuleDay parse(String day) { + RuleDay d = new RuleDay(); + if (day.startsWith("last")) { + d.lastOne = true; + d.dayName = day.substring(4); + d.dow = getDOW(d.dayName); + } else { + int index; + if ((index = day.indexOf(">=")) != -1) { + d.dayName = day.substring(0, index); + d.dow = getDOW(d.dayName); + d.soonerOrLater = 1; // greater or equal + d.thanDayOfMonth = Integer.parseInt(day.substring(index+2)); + } else if ((index = day.indexOf("<=")) != -1) { + d.dayName = day.substring(0, index); + d.dow = getDOW(d.dayName); + d.soonerOrLater = -1; // less or equal + d.thanDayOfMonth = Integer.parseInt(day.substring(index+2)); + } else { + // it should be an integer value. + d.thanDayOfMonth = Integer.parseInt(day); + } + } + return d; + } + + /** + * Converts this RuleDay to the SimpleTimeZone day rule. + * @return the converted SimpleTimeZone day rule + */ + int getDayForSimpleTimeZone() { + if (isLast()) { + return -1; + } + return isEarlier() ? -getDay() : getDay(); + } + + /** + * Converts this RuleDay to the SimpleTimeZone day-of-week rule. + * @return the SimpleTimeZone day-of-week rule value + */ + int getDayOfWeekForSimpleTimeZoneInt() { + if (isEarlier() || isLater()) { + return -getDayOfWeekNum(); + } + return isLast() ? getDayOfWeekNum() : 0; + } + + /** + * @return the string representation of the {@link + * #getDayOfWeekForSimpleTimeZoneInt} value + */ + String getDayOfWeekForSimpleTimeZone() { + int d = getDayOfWeekForSimpleTimeZoneInt(); + if (d == 0) { + return "0"; + } + String sign = ""; + if (d < 0) { + sign = "-"; + d = -d; + } + return sign + toString(d); + } + + private static DayOfWeek getDOW(String abbr) { + return abbreviations.get(abbr); + } + + /** + * Converts the specified day of week value to the day-of-week + * name defined in {@link java.util.Calenda}. + * @param dow 1-based day of week value + * @return the Calendar day of week name with "Calendar." prefix. + * @throws IllegalArgumentException if the specified dow value is out of range. + */ + static String toString(int dow) { + if (dow >= DayOfWeek.SUNDAY.value() && dow <= DayOfWeek.SATURDAY.value()) { + return "Calendar." + DayOfWeek.values()[dow - 1]; + } + throw new IllegalArgumentException("wrong Day_of_Week number: " + dow); + } +} diff --git a/jdk/test/sun/util/calendar/zi/RuleRec.java b/jdk/test/sun/util/calendar/zi/RuleRec.java new file mode 100644 index 00000000000..c0a578554c5 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/RuleRec.java @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2000, 2004, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.StringTokenizer; + +/** + * RuleRec class represents one record of the Rule set. + * + * @since 1.4 + */ +class RuleRec { + private int fromYear; + private int toYear; + private String type; + private Month inMonth; + private RuleDay onDay; + private Time atTime; + private int save; + private String letters; + private String line; + private boolean isLastRule; + + int getFromYear() { + return fromYear; + } + + int getToYear() { + return toYear; + } + + Month getMonth() { + return inMonth; + } + + int getMonthNum() { + return inMonth.value(); + } + + RuleDay getDay() { + return onDay; + } + + Time getTime() { + return atTime; + } + + int getSave() { + return save; + } + + String getLine() { + return line; + } + + /** + * Sets the line from the text file. + * @param line the text of the line + */ + void setLine(String line) { + this.line = line; + } + + /** + * @return true if the rule type is "odd". + */ + boolean isOdd() { + return "odd".equals(type); + } + + /** + * @return true if the rule type is "even". + */ + boolean isEven() { + return "even".equals(type); + } + + /** + * Determines if this rule record is the last DST schedule rule. + * + * @return true if this rule record has "max" as TO (year). + */ + boolean isLastRule() { + return isLastRule; + } + + /** + * Determines if the unadjusted until time of the specified ZoneRec + * is the same as the transition time of this rule in the same + * year as the ZoneRec until year. + * + * @param zrec ZoneRec to compare to + * @param save the amount of daylight saving in milliseconds + * @param gmtOffset the GMT offset value in milliseconds + * @return true if the unadjusted until time is the same as rule's + * transition time. + */ + boolean isSameTransition(ZoneRec zrec, int save, int gmtOffset) { + long until, transition; + + if (zrec.getUntilTime().getType() != atTime.getType()) { + until = zrec.getLocalUntilTime(save, gmtOffset); + transition = Time.getLocalTime(zrec.getUntilYear(), + getMonth(), + getDay(), + save, + gmtOffset, + atTime); + } else { + until = zrec.getLocalUntilTime(); + transition = Time.getLocalTime(zrec.getUntilYear(), + getMonth(), + getDay(), + atTime.getTime()); + } + + return until == transition; + } + + /** + * Parses a Rule line and returns a RuleRec object. + * + * @param tokens a StringTokenizer object that should contain a + * token for the "FROM" field and the rest. + * @return a RuleRec object. + */ + static RuleRec parse(StringTokenizer tokens) { + RuleRec rec = new RuleRec(); + try { + // FROM + String token = tokens.nextToken(); + try { + rec.fromYear = Integer.parseInt(token); + } catch (NumberFormatException e) { + // it's not integer + if ("min".equals(token) || "minimum".equals(token)) { + rec.fromYear = Zoneinfo.getMinYear(); + } else if ("max".equals(token) || "maximum".equals(token)) { + rec.fromYear = Zoneinfo.getMaxYear(); + } else { + Main.panic("invalid year value: "+token); + } + } + + // TO + token = tokens.nextToken(); + rec.isLastRule = false; + try { + rec.toYear = Integer.parseInt(token); + } catch (NumberFormatException e) { + // it's not integer + if ("min".equals(token) || "minimum".equals(token)) { + rec.fromYear = Zoneinfo.getMinYear(); + } else if ("max".equals(token) || "maximum".equals(token)) { + rec.toYear = Integer.MAX_VALUE; + rec.isLastRule = true; + } else if ("only".equals(token)) { + rec.toYear = rec.fromYear; + } else { + Main.panic("invalid year value: "+token); + } + } + + // TYPE + rec.type = tokens.nextToken(); + + // IN + rec.inMonth = Month.parse(tokens.nextToken()); + + // ON + rec.onDay = RuleDay.parse(tokens.nextToken()); + + // AT + rec.atTime = Time.parse(tokens.nextToken()); + + // SAVE + rec.save = (int) Time.parse(tokens.nextToken()).getTime(); + + // LETTER/S + rec.letters = tokens.nextToken(); + } catch (Exception e) { + e.printStackTrace(); + } + return rec; + } + + /** + * Calculates the transition time of the given year under this rule. + * @param year the year value + * @param gmtOffset the GMT offset value in milliseconds + * @param save the amount of daylight save time + * @return the transition time in milliseconds of the given year in UTC. + */ + long getTransitionTime(int year, int gmtOffset, int save) { + long time = Time.getLocalTime(year, getMonth(), + getDay(), atTime.getTime()); + if (atTime.isSTD()) { + time -= gmtOffset; + } else if (atTime.isWall()) { + time -= gmtOffset + save; + } + return time; + } + + private static int getInt(StringTokenizer tokens) { + String token = tokens.nextToken(); + return Integer.parseInt(token); + } +} diff --git a/jdk/test/sun/util/calendar/zi/Simple.java b/jdk/test/sun/util/calendar/zi/Simple.java new file mode 100644 index 00000000000..b61ffeaf229 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/Simple.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2000, 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * Simple generates TimeZoneData, which had been used as internal + * data of TimeZone before J2SDK1.3. + * Since J2SDK1.4 doesn't need TimeZoneData, this class is for maintenance + * of old JDK release. + */ +class Simple extends BackEnd { + + /** + * Zone records which are applied for given year. + */ + private static Map lastZoneRecs = new HashMap<>(); + + /** + * Rule records which are applied for given year. + */ + private static Map> lastRules = new TreeMap<>(); + + /** + * zone IDs sorted by their GMT offsets. If zone's GMT + * offset will change in the future, its last known offset is + * used. + */ + private SortedMap> zonesByOffset = new TreeMap<>(); + + /** + * Sets last Rule records and Zone records for given timezone to + * each Map. + * + * @param tz Timezone object for each zone + * @return always 0 + */ + int processZoneinfo(Timezone tz) { + String zonename = tz.getName(); + + lastRules.put(zonename, tz.getLastRules()); + lastZoneRecs.put(zonename, tz.getLastZoneRec()); + + // Populate zonesByOffset. (Zones that will change their + // GMT offsets are also added to zonesByOffset here.) + int lastKnownOffset = tz.getRawOffset(); + Set set = zonesByOffset.get(lastKnownOffset); + if (set == null) { + set = new TreeSet<>(); + zonesByOffset.put(lastKnownOffset, set); + } + set.add(zonename); + + return 0; + } + + /** + * Generates TimeZoneData to output SimpleTimeZone data. + * @param map Mappings object which is generated by {@link Main#compile}. + * @return 0 if no error occurred, otherwise 1. + */ + int generateSrc(Mappings map) { + try { + File outD = new File(Main.getOutputDir()); + outD.mkdirs(); + + FileWriter fw = + new FileWriter(new File(outD, "TimeZoneData.java"), false); + BufferedWriter out = new BufferedWriter(fw); + + out.write("import java.util.SimpleTimeZone;\n\n"); + out.write(" static SimpleTimeZone zones[] = {\n"); + + Map a = map.getAliases(); + List roi = map.getRawOffsetsIndex(); + List> roit = map.getRawOffsetsIndexTable(); + + int index = 0; + for (int offset : zonesByOffset.keySet()) { + int o = roi.get(index); + Set set = zonesByOffset.get(offset); + if (offset == o) { + // Merge aliases into zonesByOffset + set.addAll(roit.get(index)); + } + index++; + + for (String key : set) { + ZoneRec zrec; + String realname; + List stz; + if ((realname = a.get(key)) != null) { + // if this alias is not targeted, ignore it. + if (!Zone.isTargetZone(key)) { + continue; + } + stz = lastRules.get(realname); + zrec = lastZoneRecs.get(realname); + } else { + stz = lastRules.get(key); + zrec = lastZoneRecs.get(key); + } + + out.write("\t//--------------------------------------------------------------------\n"); + String s = Time.toFormedString(offset); + out.write("\tnew SimpleTimeZone(" + + Time.toFormedString(offset) + ", \"" + key + "\""); + if (realname != null) { + out.write(" /* " + realname + " */"); + } + + if (stz == null) { + out.write("),\n"); + } else { + RuleRec rr0 = stz.get(0); + RuleRec rr1 = stz.get(1); + + out.write(",\n\t " + Month.toString(rr0.getMonthNum()) + + ", " + rr0.getDay().getDayForSimpleTimeZone() + ", " + + rr0.getDay().getDayOfWeekForSimpleTimeZone() + ", " + + Time.toFormedString((int)rr0.getTime().getTime()) + ", " + + rr0.getTime().getTypeForSimpleTimeZone() + ",\n" + + + "\t " + Month.toString(rr1.getMonthNum()) + ", " + + rr1.getDay().getDayForSimpleTimeZone() + ", " + + rr1.getDay().getDayOfWeekForSimpleTimeZone() + ", " + + Time.toFormedString((int)rr1.getTime().getTime())+ ", " + + rr1.getTime().getTypeForSimpleTimeZone() + ",\n" + + + "\t " + Time.toFormedString(rr0.getSave()) + "),\n"); + + out.write("\t// " + rr0.getLine() + "\n"); + out.write("\t// " + rr1.getLine() + "\n"); + } + + String zline = zrec.getLine(); + if (zline.indexOf("Zone") == -1) { + zline = "Zone " + key + "\t" + zline.trim(); + } + out.write("\t// " + zline + "\n"); + } + } + out.write(" };\n"); + + out.close(); + fw.close(); + } catch(IOException e) { + Main.panic("IO error: "+e.getMessage()); + return 1; + } + + return 0; + } +} diff --git a/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java b/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java new file mode 100644 index 00000000000..c9e2bd9e6f7 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2012, 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 8007572 + *@summary Test whether the TimeZone generated from JSR310 tzdb is the same + *as the one from the tz data from javazic + */ + +import java.io.File; +import java.lang.reflect.*; +import java.nio.file.*; +import java.util.*; +import java.util.regex.*; +import java.time.zone.*; +import java.time.ZoneId; + +public class TestZoneInfo310 { + + public static void main(String[] args) throws Throwable { + + String TESTDIR = System.getProperty("test.dir", "."); + String SRCDIR = System.getProperty("test.src", "."); + String tzdir = SRCDIR + File.separator + "tzdata"; + String tzfiles = "africa antarctica asia australasia europe northamerica pacificnew southamerica backward etcetera systemv"; + String jdk_tzdir = SRCDIR + File.separator + "tzdata_jdk"; + String jdk_tzfiles = "gmt jdk11_backward"; + String zidir = TESTDIR + File.separator + "zi"; + File fZidir = new File(zidir); + if (!fZidir.exists()) { + fZidir.mkdirs(); + } + Matcher m = Pattern.compile("tzdata(?[0-9]{4}[A-z])") + .matcher(new String(Files.readAllBytes(Paths.get(tzdir, "VERSION")), "ascii")); + String ver = m.find() ? m.group("ver") : "NULL"; + + ArrayList alist = new ArrayList<>(); + alist.add("-V"); + alist.add(ver); + alist.add("-d"); + alist.add(zidir); + for (String f : tzfiles.split(" ")) { + alist.add(tzdir + File.separator + f); + } + for (String f : jdk_tzfiles.split(" ")) { + alist.add(jdk_tzdir + File.separator + f); + } + System.out.println("Compiling tz files!"); + Main.main(alist.toArray(new String[alist.size()])); + ////////////////////////////////// + + System.out.println("testing!"); + ZoneInfoFile.ziDir = zidir; + long t0, t1; + + t0 = System.nanoTime(); + ZoneInfoOld.getTimeZone("America/Los_Angeles"); + t1 = System.nanoTime(); + System.out.printf("OLD.getZoneInfoOld()[1]=%d%n", (t1 - t0) / 1000); + + t0 = System.nanoTime(); + ZoneInfoOld.getTimeZone("America/New_York"); + t1 = System.nanoTime(); + System.out.printf("OLD.getZoneInfoOld()[2]=%d%n", (t1 - t0) / 1000); + + t0 = System.nanoTime(); + ZoneInfoOld.getTimeZone("America/Denver"); + t1 = System.nanoTime(); + System.out.printf("OLD.getZoneInfoOld()[3]=%d%n", (t1 - t0) / 1000); + + t0 = System.nanoTime(); + String[] zids_old = ZoneInfoOld.getAvailableIDs(); + t1 = System.nanoTime(); + System.out.printf("OLD.getAvailableIDs()=%d, total=%d%n", + (t1 - t0) / 1000, zids_old.length); + Arrays.sort(zids_old); + + t0 = System.nanoTime(); + ZoneId.of("America/Los_Angeles").getRules(); + t1 = System.nanoTime(); + System.out.printf("NEW.getTimeZone()[1]=%d%n", (t1 - t0) / 1000); + + t0 = System.nanoTime(); + TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles"); + t1 = System.nanoTime(); + System.out.printf("NEW.getTimeZone()[1]=%d%n", (t1 - t0) / 1000); + + t0 = System.nanoTime(); + tz = TimeZone.getTimeZone("America/New_York"); + t1 = System.nanoTime(); + System.out.printf("NEW.getTimeZone()[2]=%d%n", (t1 - t0) / 1000); + + t0 = System.nanoTime(); + tz = TimeZone.getTimeZone("America/Denver"); + t1 = System.nanoTime(); + System.out.printf("NEW.getTimeZone()[3]=%d%n", (t1 - t0) / 1000); + + t0 = System.nanoTime(); + String[] zids_new = TimeZone.getAvailableIDs(); + t1 = System.nanoTime(); + System.out.printf("NEW.getAvailableIDs()=%d, total=%d%n", + (t1 - t0) / 1000, zids_new.length); + Arrays.sort(zids_new); + + t0 = System.currentTimeMillis(); + for (String zid : zids_new) { + TimeZone.getTimeZone(zid); + } + t1 = System.currentTimeMillis(); + System.out.printf("NEW.TotalTZ()=%d (ms)%n", t1 - t0); + + t0 = System.currentTimeMillis(); + for (String zid : zids_old) { + ZoneInfoOld.getTimeZone(zid); + } + t1 = System.currentTimeMillis(); + System.out.printf("OLD.TotalTZ()=%d (ms)%n", t1 - t0); + + if (!Arrays.equals(zids_old, zids_new)) { + throw new RuntimeException(" FAILED: availableIds don't match"); + } + for (String zid : zids_new) { + ZoneInfoOld zi = toZoneInfoOld(TimeZone.getTimeZone(zid)); + ZoneInfoOld ziOLD = (ZoneInfoOld)ZoneInfoOld.getTimeZone(zid); + if (! zi.equalsTo(ziOLD)) { + System.out.println(zi.diffsTo(ziOLD)); + throw new RuntimeException(" FAILED: " + zid); + } + } + delete(fZidir); + + // test tzdb version + if (!ver.equals(sun.util.calendar.ZoneInfoFile.getVersion())) { + System.out.printf(" FAILED: ver=%s, expected=%s%n", + sun.util.calendar.ZoneInfoFile.getVersion(), ver); + throw new RuntimeException("Version test failed"); + } + } + + private static void delete(File f) { + if (f.isDirectory()) { + for (File f0 : f.listFiles()) { + delete(f0); + } + } + f.delete(); + } + + // to access sun.util.calendar.ZoneInfo's private fields + static Class ziClz; + static Field rawOffset; + static Field checksum; + static Field dstSavings; + static Field transitions; + static Field offsets; + static Field simpleTimeZoneParams; + static Field willGMTOffsetChange; + static { + try { + ziClz = Class.forName("sun.util.calendar.ZoneInfo"); + rawOffset = ziClz.getDeclaredField("rawOffset"); + checksum = ziClz.getDeclaredField("checksum"); + dstSavings = ziClz.getDeclaredField("dstSavings"); + transitions = ziClz.getDeclaredField("transitions"); + offsets = ziClz.getDeclaredField("offsets"); + simpleTimeZoneParams = ziClz.getDeclaredField("simpleTimeZoneParams"); + willGMTOffsetChange = ziClz.getDeclaredField("willGMTOffsetChange"); + rawOffset.setAccessible(true); + checksum.setAccessible(true); + dstSavings.setAccessible(true); + transitions.setAccessible(true); + offsets.setAccessible(true); + simpleTimeZoneParams.setAccessible(true); + willGMTOffsetChange.setAccessible(true); + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + private static ZoneInfoOld toZoneInfoOld(TimeZone tz) throws Exception { + return new ZoneInfoOld(tz.getID(), + rawOffset.getInt(tz), + dstSavings.getInt(tz), + checksum.getInt(tz), + (long[])transitions.get(tz), + (int[])offsets.get(tz), + (int[])simpleTimeZoneParams.get(tz), + willGMTOffsetChange.getBoolean(tz)); + } + + +} diff --git a/jdk/test/sun/util/calendar/zi/Time.java b/jdk/test/sun/util/calendar/zi/Time.java new file mode 100644 index 00000000000..8f82e1459c5 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/Time.java @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2000, 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.Locale; +import sun.util.calendar.CalendarDate; +import sun.util.calendar.CalendarSystem; +import sun.util.calendar.Gregorian; + +/** + * Time class represents the "AT" field and other time related information. + * + * @since 1.4 + */ +class Time { + + static final Gregorian gcal = CalendarSystem.getGregorianCalendar(); + + // type is wall clock time + private static final int WALL = 1; + + // type is standard time + private static final int STD = 2; + + // type is UTC + private static final int UTC = 3; + + // type of representing time + private int type; + + /** + * Time from the EPOCH in milliseconds + */ + private long time; + + /** + * Current time in milliseconds + */ + private static final long currentTime = System.currentTimeMillis(); + + Time() { + time = 0L; + } + + Time(long time) { + this.time = time; + } + + void setType(int type) { + this.type = type; + } + + long getTime() { + return time; + } + + int getType() { + return type; + } + + static long getCurrentTime() { + return currentTime; + } + + /** + * @return true if the time is represented in wall-clock time. + */ + boolean isWall() { + return type == WALL; + } + + /** + * @return true if the time is represented in standard time. + */ + boolean isSTD() { + return type == STD; + } + + /** + * @return true if the time is represented in UTC time. + */ + boolean isUTC() { + return type == UTC; + } + + /** + * Converts the type to a string that represents the type in the + * SimpleTimeZone time mode. (e.g., "SimpleTimeZone.WALL_TIME"). + * @return the converted string or null if the type is undefined. + */ + String getTypeForSimpleTimeZone() { + String stz = "SimpleTimeZone."; + if (isWall()) { + return stz+"WALL_TIME"; + } + else if (isSTD()) { + return stz+"STANDARD_TIME"; + } + else if (isUTC()) { + return stz+"UTC_TIME"; + } + else { + return null; + } + } + + /** + * Converts the given Gregorian calendar field values to local time. + * Local time is represented by the amount of milliseconds from + * January 1, 1970 0:00 GMT. + * @param year the year value + * @param month the Month value + * @param day the day represented by {@link RuleDay} + * @param save the amount of daylight time in milliseconds + * @param gmtOffset the GMT offset in milliseconds + * @param time the time of the day represented by {@link Time} + * @return local time + */ + static long getLocalTime(int year, Month month, RuleDay day, int save, + int gmtOffset, Time time) { + long t = time.getTime(); + + if (time.isSTD()) + t = time.getTime() + save; + else if (time.isUTC()) + t = time.getTime() + save + gmtOffset; + + return getLocalTime(year, month, day, t); + } + + /** + * Converts the given Gregorian calendar field values to local time. + * Local time is represented by the amount of milliseconds from + * January 1, 1970 0:00 GMT. + * @param year the year value + * @param month the Month value + * @param day the day value + * @param time the time of the day in milliseconds + * @return local time + */ + static long getLocalTime(int year, Month month, int day, long time) { + CalendarDate date = gcal.newCalendarDate(null); + date.setDate(year, month.value(), day); + long millis = gcal.getTime(date); + return millis + time; + } + + /** + * Equivalent to getLocalTime(year, month, day, (long)time). + * @param year the year value + * @param month the Month value + * @param day the day value + * @param time the time of the day in milliseconds + * @return local time + */ + static long getLocalTime(int year, Month month, int day, int time) { + return getLocalTime(year, month, day, (long)time); + } + + /** + * Equivalent to {@link #getLocalTime(int, Month, RuleDay, int) + * getLocalTime(year, month, day, (int) time)}. + * @param year the year value + * @param month the Month value + * @param day the day represented by {@link RuleDay} + * @param time the time of the day represented by {@link Time} + * @return local time + */ + static long getLocalTime(int year, Month month, RuleDay day, long time) { + return getLocalTime(year, month, day, (int) time); + } + + /** + * Converts the given Gregorian calendar field values to local time. + * Local time is represented by the amount of milliseconds from + * January 1, 1970 0:00 GMT. + * @param year the year value + * @param month the Month value + * @param day the day represented by {@link RuleDay} + * @param time the time of the day represented by {@link Time} + * @return local time + */ + static long getLocalTime(int year, Month month, RuleDay day, int time) { + CalendarDate cdate = gcal.newCalendarDate(null); + int monthValue = month.value(); + + if (day.isLast()) { // e.g., "lastSun" + cdate.setDate(year, monthValue, 1); + cdate.setDayOfMonth(gcal.getMonthLength(cdate)); + cdate = gcal.getNthDayOfWeek(-1, day.getDayOfWeekNum(), cdate); + } else if (day.isLater()) { // e.g., "Sun>=1" + cdate.setDate(year, monthValue, day.getDay()); + cdate = gcal.getNthDayOfWeek(1, day.getDayOfWeekNum(), cdate); + } else if (day.isExact()) { + cdate.setDate(year, monthValue, day.getDay()); + } else if (day.isEarlier()) { // e.g., "Sun<=15" + cdate.setDate(year, monthValue, day.getDay()); + cdate = gcal.getNthDayOfWeek(-1, day.getDayOfWeekNum(), cdate); + } else { + Main.panic("invalid day type: " + day); + } + return gcal.getTime(cdate) + time; + } + + /** + * Parses the given "AT" field and constructs a Time object. + * @param the "AT" field string + * @return the Time object + */ + static Time parse(String time) { + int sign; + int index = 0; + Time tm; + + if (time.charAt(0) == '-') { + sign = -1; + index++; + } else { + sign = 1; + } + int val = 0; + int num = 0; + int countDelim = 0; + while (index < time.length()) { + char c = time.charAt(index++); + if (c == ':') { + val = val * 60 + num; + countDelim++; + num = 0; + continue; + } + int d = Character.digit(c, 10); + if (d == -1) { + --index; + break; + } + num = num * 10 + d; + } + val = val * 60 + num; + // convert val to second + for (; countDelim < 2; countDelim++) { + val *= 60; + } + tm = new Time((long)val * 1000 * sign); + if (index < time.length()) { + char c = time.charAt(index++); + if (c == 's') { + tm.setType(Time.STD); + } else if (c == 'u' || c == 'g' || c == 'z') { + tm.setType(Time.UTC); + } else if (c == 'w') { + tm.setType(Time.WALL); + } else { + Main.panic("unknown time mode: "+c); + } + } else { + tm.setType(Time.WALL); + } + return tm; + } + + /** + * Converts the given milliseconds string to a "[+-]hh:mm" string. + * @param ms the milliseconds string + */ + static String toGMTFormat(String ms) { + long sec = Long.parseLong(ms) / 1000; + char sign; + if (sec < 0) { + sign = '-'; + sec = -sec; + } else { + sign = '+'; + } + return String.format((Locale)null, "%c%02d:%02d", + sign, sec/3600, (sec%3600)/60); + } + + /** + * Converts the given millisecond value to a string for a + * SimpleTimeZone parameter. + * @param ms the millisecond value + * @return the string in a human readable form + */ + static String toFormedString(int ms) { + StringBuilder s = new StringBuilder(); + boolean minus = false; + + if (ms < 0) { + s.append("-"); + minus = true; + ms = -ms; + } else if (ms == 0) { + return "0"; + } + + int hour = ms / (60 * 60 * 1000); + ms %= (60 * 60 * 1000); + int minute = ms / (60 * 1000); + + if (hour != 0) { + if (minus && minute != 0) { + s.append("("); + } + s.append(Integer.toString(hour) + "*ONE_HOUR"); + } + + if (minute != 0) { + if (hour != 0) { + s.append("+"); + } + s.append(Integer.toString(minute) + "*ONE_MINUTE"); + if (minus && hour != 0) { + s.append(")"); + } + } + + return s.toString(); + } +} diff --git a/jdk/test/sun/util/calendar/zi/Timezone.java b/jdk/test/sun/util/calendar/zi/Timezone.java new file mode 100644 index 00000000000..04518a944f5 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/Timezone.java @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2000, 2004, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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; + +/** + * Timezone represents all information of a single point of time to + * generate its time zone database. + * + * @since 1.4 + */ +class Timezone { + /** + * zone name of this time zone + */ + private String name; + + /** + * transition time values in UTC (millisecond) + */ + private List transitions; + + /** + * All offset values in millisecond + * @see sun.util.calendar.ZoneInfo + */ + private List offsets; + + /** + * Indices of GMT offset values (both raw and raw+saving) + * at transitions + */ + private List gmtOffsets; + + /** + * Indices of regular or "direct" saving time values + * at transitions + */ + private List dstOffsets; + + /** + * Zone records of this time zone + */ + private List usedZoneRecs; + + /** + * Rule records referred to by this time zone + */ + private List usedRuleRecs; + + /** + * Type of DST rules in this time zone + */ + private int dstType; + static final int UNDEF_DST = 0; // DST type not set yet + static final int NO_DST = 1; // never observed DST + static final int LAST_DST = 2; // last rule ends in DST (all year round DST-only) + static final int X_DST = 3; // used to observe DST + static final int DST = 4; // observing DST regularly + + /** + * Raw GMT offset of this time zone in the last rule + */ + private int rawOffset; + + /** + * The CRC32 value of the transitions data + */ + private int crc32; + + /** + * The last ZoneRec + */ + private ZoneRec lastZoneRec; + + /** + * The last DST rules. lastRules[0] is the DST start + * rule. lastRules[1] is the DST end rules. + */ + private List lastRules; + + /** + * The amount of DST saving value (millisecond) in the last DST + * rule. + */ + private int lastSaving; + + /** + * true if the raw offset will change in the future time. + */ + private boolean willRawOffsetChange = false; + + + /** + * Constracts a Timezone object with the given zone name. + * @param name the zone name + */ + Timezone(String name) { + this.name = name; + } + + /** + * @return the number of transitions + */ + int getNTransitions() { + if (transitions == null) { + return 0; + } + return transitions.size(); + } + + /** + * @return the zone name + */ + String getName() { + return name; + } + + /** + * Returns the list of all rule records that have been referred to + * by this time zone. + * @return the rule records list + */ + List getRules() { + return usedRuleRecs; + } + + /** + * Returns the list of all zone records that have been referred to + * by this time zone. + * @return the zone records list + */ + List getZones() { + return usedZoneRecs; + } + + /** + * @return the transition table (list) + */ + List getTransitions() { + return transitions; + } + + /** + * @return the offsets list + */ + List getOffsets() { + return offsets; + } + + /** + * @return the DST saving offsets list + */ + List getDstOffsets() { + return dstOffsets; + } + + /** + * @return the GMT offsets list + */ + List getGmtOffsets() { + return gmtOffsets; + } + + /** + * @return the checksum (crc32) value of the trasition table + */ + int getCRC32() { + return crc32; + } + + /** + * @return true if the GMT offset of this time zone would change + * after the time zone database has been generated, false, otherwise. + */ + boolean willGMTOffsetChange() { + return willRawOffsetChange; + } + + /** + * @return the last known GMT offset value in milliseconds + */ + int getRawOffset() { + return rawOffset; + } + + /** + * Sets time zone's GMT offset to offset. + * @param offset the GMT offset value in milliseconds + */ + void setRawOffset(int offset) { + rawOffset = offset; + } + + /** + * Sets time zone's GMT offset value to offset. If + * startTime is future time, then the {@link + * #willRawOffsetChange} value is set to true. + * @param offset the GMT offset value in milliseconds + * @param startTime the UTC time at which the GMT offset is in effective + */ + void setRawOffset(int offset, long startTime) { + // if this rawOffset is for the future time, let the run-time + // look for the current GMT offset. + if (startTime > Time.getCurrentTime()) { + willRawOffsetChange = true; + } + setRawOffset(offset); + } + + /** + * Adds the specified transition information to the end of the transition table. + * @param time the UTC time at which this transition happens + * @param offset the total amount of the offset from GMT in milliseconds + * @param dstOffset the amount of time in milliseconds saved at this transition + */ + void addTransition(long time, int offset, int dstOffset) { + if (transitions == null) { + transitions = new ArrayList(); + offsets = new ArrayList(); + dstOffsets = new ArrayList(); + } + transitions.add(time); + offsets.add(offset); + dstOffsets.add(dstOffset); + } + + /** + * Sets the type of historical daylight saving time + * observation. For example, China used to observed daylight + * saving time, but it no longer does. Then, X_DST is set to the + * China time zone. + * @param type the type of daylight saving time + */ + void setDSTType(int type) { + dstType = type; + } + + /** + * @return the type of historical daylight saving time + * observation. + */ + int getDSTType() { + return dstType; + } + + /** + * Adds the specified zone record to the zone records list. + * @param rec the zone record + */ + void addUsedRec(ZoneRec rec) { + if (usedZoneRecs == null) { + usedZoneRecs = new ArrayList(); + } + usedZoneRecs.add(rec); + } + + /** + * Adds the specified rule record to the rule records list. + * @param rec the rule record + */ + void addUsedRec(RuleRec rec) { + if (usedRuleRecs == null) { + usedRuleRecs = new ArrayList(); + } + // if the last used rec is the same as the given rec, avoid + // putting the same rule. + int n = usedRuleRecs.size(); + for (int i = 0; i < n; i++) { + if (usedRuleRecs.get(i).equals(rec)) { + return; + } + } + usedRuleRecs.add(rec); + } + + /** + * Sets the last zone record for this time zone. + * @param the last zone record + */ + void setLastZoneRec(ZoneRec zrec) { + lastZoneRec = zrec; + } + + /** + * @return the last zone record for this time zone. + */ + ZoneRec getLastZoneRec() { + return lastZoneRec; + } + + /** + * Sets the last rule records for this time zone. Those are used + * for generating SimpleTimeZone parameters. + * @param rules the last rule records + */ + void setLastRules(List rules) { + int n = rules.size(); + if (n > 0) { + lastRules = rules; + RuleRec rec = rules.get(0); + int offset = rec.getSave(); + if (offset > 0) { + setLastDSTSaving(offset); + } else { + System.err.println("\t No DST starting rule in the last rules."); + } + } + } + + /** + * @return the last rule records for this time zone. + */ + List getLastRules() { + return lastRules; + } + + /** + * Sets the last daylight saving amount. + * @param the daylight saving amount + */ + void setLastDSTSaving(int offset) { + lastSaving = offset; + } + + /** + * @return the last daylight saving amount. + */ + int getLastDSTSaving() { + return lastSaving; + } + + /** + * Calculates the CRC32 value from the transition table and sets + * the value to crc32. + */ + void checksum() { + if (transitions == null) { + crc32 = 0; + return; + } + Checksum sum = new Checksum(); + for (int i = 0; i < transitions.size(); i++) { + int offset = offsets.get(i); + // adjust back to make the transition in local time + sum.update(transitions.get(i) + offset); + sum.update(offset); + sum.update(dstOffsets.get(i)); + } + crc32 = (int)sum.getValue(); + } + + /** + * Removes unnecessary transitions for Java time zone support. + */ + void optimize() { + // if there is only one offset, delete all transitions. This + // could happen if only time zone abbreviations changed. + if (gmtOffsets.size() == 1) { + transitions = null; + usedRuleRecs = null; + setDSTType(NO_DST); + return; + } + for (int i = 0; i < (transitions.size() - 2); i++) { // don't remove the last one + if (transitions.get(i) == transitions.get(i+1)) { + transitions.remove(i); + offsets.remove(i); + dstOffsets.remove(i); + i--; + } + } + + for (int i = 0; i < (transitions.size() - 2); i++) { // don't remove the last one + if (offsets.get(i) == offsets.get(i+1) + && dstOffsets.get(i) == dstOffsets.get(i+1)) { + transitions.remove(i+1); + offsets.remove(i+1); + dstOffsets.remove(i+1); + i--; + } + } + } + + /** + * Stores the specified offset value from GMT in the GMT offsets + * table and returns its index. The offset value includes the base + * GMT offset and any additional daylight saving if applicable. If + * the same value as the specified offset is already in the table, + * its index is returned. + * @param offset the offset value in milliseconds + * @return the index to the offset value in the GMT offsets table. + */ + int getOffsetIndex(int offset) { + return getOffsetIndex(offset, 0); + } + + /** + * Stores the specified daylight saving value in the GMT offsets + * table and returns its index. If the same value as the specified + * offset is already in the table, its index is returned. If 0 is + * specified, it's not stored in the table and -1 is returned. + * @param offset the offset value in milliseconds + * @return the index to the specified offset value in the GMT + * offsets table, or -1 if 0 is specified. + */ + int getDstOffsetIndex(int offset) { + if (offset == 0) { + return -1; + } + return getOffsetIndex(offset, 1); + } + + private int getOffsetIndex(int offset, int index) { + if (gmtOffsets == null) { + gmtOffsets = new ArrayList(); + } + for (int i = index; i < gmtOffsets.size(); i++) { + if (offset == gmtOffsets.get(i)) { + return i; + } + } + if (gmtOffsets.size() < index) { + gmtOffsets.add(0); + } + gmtOffsets.add(offset); + return gmtOffsets.size() - 1; + } +} diff --git a/jdk/test/sun/util/calendar/zi/TzIDOldMapping.java b/jdk/test/sun/util/calendar/zi/TzIDOldMapping.java new file mode 100644 index 00000000000..e9ea6b5dfe1 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/TzIDOldMapping.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2008, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.Map; +import java.util.HashMap; + +class TzIDOldMapping { + static final Map MAP = new HashMap(); + static { + String[][] oldmap = { + { "ACT", "Australia/Darwin" }, + { "AET", "Australia/Sydney" }, + { "AGT", "America/Argentina/Buenos_Aires" }, + { "ART", "Africa/Cairo" }, + { "AST", "America/Anchorage" }, + { "BET", "America/Sao_Paulo" }, + { "BST", "Asia/Dhaka" }, + { "CAT", "Africa/Harare" }, + { "CNT", "America/St_Johns" }, + { "CST", "America/Chicago" }, + { "CTT", "Asia/Shanghai" }, + { "EAT", "Africa/Addis_Ababa" }, + { "ECT", "Europe/Paris" }, + { "EST", "America/New_York" }, + { "HST", "Pacific/Honolulu" }, + { "IET", "America/Indianapolis" }, + { "IST", "Asia/Calcutta" }, + { "JST", "Asia/Tokyo" }, + { "MIT", "Pacific/Apia" }, + { "MST", "America/Denver" }, + { "NET", "Asia/Yerevan" }, + { "NST", "Pacific/Auckland" }, + { "PLT", "Asia/Karachi" }, + { "PNT", "America/Phoenix" }, + { "PRT", "America/Puerto_Rico" }, + { "PST", "America/Los_Angeles" }, + { "SST", "Pacific/Guadalcanal" }, + { "VST", "Asia/Saigon" }, + }; + for (String[] pair : oldmap) { + MAP.put(pair[0], pair[1]); + } + } +} diff --git a/jdk/test/sun/util/calendar/zi/Zone.java b/jdk/test/sun/util/calendar/zi/Zone.java new file mode 100644 index 00000000000..79520085d31 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/Zone.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2000, 2004, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.BufferedReader; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + +/** + * Zone holds information corresponding to a "Zone" part of a time + * zone definition file. + * + * @since 1.4 + */ +class Zone { + // zone name (e.g., "America/Los_Angeles") + private String name; + + // zone records + private List list; + + // target zone names for this compilation + private static Set targetZones; + + /** + * Constructs a Zone with the specified zone name. + * @param name the zone name + */ + Zone(String name) { + this.name = name; + list = new ArrayList(); + } + + /** + * Reads time zone names to be generated, called "target zone + * name", from the specified text file and creats an internal hash + * table to keep those names. It's assumed that one text line + * contains a zone name or comments if it starts with + * '#'. Comments can't follow a zone name in a single line. + * @param fileName the text file name + */ + static void readZoneNames(String fileName) { + if (fileName == null) { + return; + } + BufferedReader in = null; + try { + FileReader fr = new FileReader(fileName); + in = new BufferedReader(fr); + } catch (FileNotFoundException e) { + Main.panic("can't open file: " + fileName); + } + targetZones = new HashSet(); + String line; + + try { + while ((line = in.readLine()) != null) { + line = line.trim(); + if (line.length() == 0 || line.charAt(0) == '#') { + continue; + } + if (!targetZones.add(line)) { + Main.warning("duplicated target zone name: " + line); + } + } + in.close(); + } catch (IOException e) { + Main.panic("IO error: "+e.getMessage()); + } + } + + /** + * Determines whether the specified zone is one of the target zones. + * If no target zones are specified, this method always returns + * true for any zone name. + * @param zoneName the zone name + * @return true if the specified name is a target zone. + */ + static boolean isTargetZone(String zoneName) { + if (targetZones == null) { + return true; + } + return targetZones.contains(zoneName); + } + + /** + * Forces to add "MET" to the target zone table. This is because + * there is a conflict between Java zone name "WET" and Olson zone + * name. + */ + static void addMET() { + if (targetZones != null) { + targetZones.add("MET"); + } + } + + /** + * @return the zone name + */ + String getName() { + return name; + } + + /** + * Adds the specified zone record to the zone record list. + */ + void add(ZoneRec rec) { + list.add(rec); + } + + /** + * @param index the index at which the zone record in the list is returned. + * @return the zone record specified by the index. + */ + ZoneRec get(int index) { + return list.get(index); + } + + /** + * @return the size of the zone record list + */ + int size() { + return list.size(); + } + + /** + * Resolves the reference to a rule in each zone record. + * @param zi the Zoneinfo object with which the rule reference is + * resolved. + */ + void resolve(Zoneinfo zi) { + for (int i = 0; i < list.size(); i++) { + ZoneRec rec = list.get(i); + rec.resolve(zi); + } + } +} diff --git a/jdk/test/sun/util/calendar/zi/ZoneInfoFile.java b/jdk/test/sun/util/calendar/zi/ZoneInfoFile.java new file mode 100644 index 00000000000..f0dda48c0a9 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/ZoneInfoFile.java @@ -0,0 +1,1051 @@ +/* + * Copyright (c) 2000, 2012, 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. Oracle designates this + * particular file as subject to the "Class-path" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.lang.ref.SoftReference; +import java.nio.file.FileSystems; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import sun.util.calendar.*; + +/** + * ZoneInfoFile reads Zone information files in the + * <java.home>/lib/zi directory and provides time zone + * information in the form of a {@link ZoneInfo} object. Also, it + * reads the ZoneInfoMappings file to obtain time zone IDs information + * that is used by the {@link ZoneInfo} class. The directory layout + * and data file formats are as follows. + * + *

    Directory layout

    + * + * All zone data files and ZoneInfoMappings are put under the + * <java.home>/lib/zi directory. A path name for a given time + * zone ID is a concatenation of <java.home>/lib/zi/ and the + * time zone ID. (The file separator is replaced with the platform + * dependent value. e.g., '\' for Win32.) An example layout will look + * like as follows. + *

    + *
    + * <java.home>/lib/zi/Africa/Addis_Ababa
    + *                   /Africa/Dakar
    + *                   /America/Los_Angeles
    + *                   /Asia/Singapore
    + *                   /EET
    + *                   /Europe/Oslo
    + *                   /GMT
    + *                   /Pacific/Galapagos
    + *                       ...
    + *                   /ZoneInfoMappings
    + * 
    + *
    + * + * A zone data file has specific information of each zone. + * ZoneInfoMappings has global information of zone IDs so + * that the information can be obtained without instantiating all time + * zones. + * + *

    File format

    + * + * Two binary-file formats based on a simple Tag-Length-Value format are used + * to describe TimeZone information. The generic format of a data file is: + *

    + *
    + *    DataFile {
    + *      u1              magic[7];
    + *      u1              version;
    + *      data_item       data[];
    + *    }
    + * 
    + *
    + * where magic is a magic number identifying a file + * format, version is the format version number, and + * data is one or more data_items. The + * data_item structure is: + *
    + *
    + *    data_item {
    + *      u1              tag;
    + *      u2              length;
    + *      u1              value[length];
    + *    }
    + * 
    + *
    + * where tag indicates the data type of the item, + * length is a byte count of the following + * value that is the content of item data. + *

    + * All data is stored in the big-endian order. There is no boundary + * alignment between date items. + * + *

    1. ZoneInfo data file

    + * + * Each ZoneInfo data file consists of the following members. + *
    + *

    + *
    + *    ZoneInfoDataFile {
    + *      u1              magic[7];
    + *      u1              version;
    + *      SET OF1 {
    + *        transition            transitions2;
    + *        offset_table          offsets2;
    + *        simpletimezone        stzparams2;
    + *        raw_offset            rawoffset;
    + *        dstsaving             dst;
    + *        checksum              crc32;
    + *        gmtoffsetwillchange   gmtflag2;
    + *      }
    + *   }
    + *   1: an unordered collection of zero or one occurrences of each item
    + *   2: optional item
    + * 
    + *
    + * magic is a byte-string constant identifying the + * ZoneInfo data file. This field must be "javazi\0" + * defined as {@link #JAVAZI_LABEL}. + *

    + * version is the version number of the file format. This + * will be used for compatibility check. This field must be + * 0x01 in this version. + *

    + * transition, offset_table and + * simpletimezone have information of time transition + * from the past to the future. Therefore, these structures don't + * exist if the zone didn't change zone names and haven't applied DST in + * the past, and haven't planned to apply it. (e.g. Asia/Tokyo zone) + *

    + * raw_offset, dstsaving and checksum + * exist in every zoneinfo file. They are used by TimeZone.class indirectly. + * + *

    1.1 transition structure

    + *

    + *
    + *    transition {
    + *      u1      tag;              // 0x04 : constant
    + *      u2      length;           // byte length of whole values
    + *      s8      value[length/8];  // transitions in `long'
    + *    }
    + * 
    + *
    + * See {@link ZoneInfo#transitions ZoneInfo.transitions} about the value. + * + *

    1.2 offset_table structure

    + *

    + *
    + *    offset_table {
    + *      u1      tag;              // 0x05 : constant
    + *      u2      length;           // byte length of whole values
    + *      s4      value[length/4];  // offset values in `int'
    + *    }
    + * 
    + *
    + * + *

    1.3 simpletimezone structure

    + * See {@link ZoneInfo#simpleTimeZoneParams ZoneInfo.simpleTimeZoneParams} + * about the value. + *

    + *
    + *    simpletimezone {
    + *      u1      tag;              // 0x06 : constant
    + *      u2      length;           // byte length of whole values
    + *      s4      value[length/4];  // SimpleTimeZone parameters
    + *    }
    + * 
    + *
    + * See {@link ZoneInfo#offsets ZoneInfo.offsets} about the value. + * + *

    1.4 raw_offset structure

    + *

    + *
    + *    raw_offset {
    + *      u1      tag;              // 0x01 : constant
    + *      u2      length;           // must be 4.
    + *      s4      value;            // raw GMT offset [millisecond]
    + *    }
    + * 
    + *
    + * See {@link ZoneInfo#rawOffset ZoneInfo.rawOffset} about the value. + * + *

    1.5 dstsaving structure

    + * Value has dstSaving in seconds. + *

    + *
    + *    dstsaving {
    + *      u1      tag;              // 0x02 : constant
    + *      u2      length;           // must be 2.
    + *      s2      value;            // DST save value [second]
    + *    }
    + * 
    + *
    + * See {@link ZoneInfo#dstSavings ZoneInfo.dstSavings} about value. + * + *

    1.6 checksum structure

    + *

    + *
    + *    checksum {
    + *      u1      tag;              // 0x03 : constant
    + *      u2      length;           // must be 4.
    + *      s4      value;            // CRC32 value of transitions
    + *    }
    + * 
    + *
    + * See {@link ZoneInfo#checksum ZoneInfo.checksum}. + * + *

    1.7 gmtoffsetwillchange structure

    + * This record has a flag value for {@link ZoneInfo#rawOffsetWillChange}. + * If this record is not present in a zoneinfo file, 0 is assumed for + * the value. + *

    + *
    + *    gmtoffsetwillchange {
    + *      u1      tag;             // 0x07 : constant
    + *      u2      length;          // must be 1.
    + *      u1      value;           // 1: if the GMT raw offset will change
    + *                               // in the future, 0, otherwise.
    + *     }
    + * 
    + *
    + * + * + *

    2. ZoneInfoMappings file

    + * + * The ZoneInfoMappings file consists of the following members. + *
    + *

    + *
    + *    ZoneInfoMappings {
    + *      u1      magic[7];
    + *      u1      version;
    + *      SET OF {
    + *        versionName                   version;
    + *        zone_id_table                 zoneIDs;
    + *        raw_offset_table              rawoffsets;
    + *        raw_offset_index_table        rawoffsetindices;
    + *        alias_table                   aliases;
    + *        excluded_list                 excludedList;
    + *      }
    + *   }
    + * 
    + *
    + * + * magic is a byte-string constant which has the file type. + * This field must be "javazm\0" defined as {@link #JAVAZM_LABEL}. + *

    + * version is the version number of this file + * format. This will be used for compatibility check. This field must + * be 0x01 in this version. + *

    + * versionName shows which version of Olson's data has been used + * to generate this ZoneInfoMappings. (e.g. tzdata2000g)
    + * This field is for trouble-shooting and isn't usually used in runtime. + *

    + * zone_id_table, raw_offset_index_table and + * alias_table are general information of supported + * zones. + * + *

    2.1 zone_id_table structure

    + * The list of zone IDs included in the zi database. The list does + * not include zone IDs, if any, listed in excludedList. + *
    + *

    + *
    + *    zone_id_table {
    + *      u1      tag;              // 0x40 : constant
    + *      u2      length;           // byte length of whole values
    + *      u2      zone_id_count;
    + *      zone_id value[zone_id_count];
    + *    }
    + *
    + *    zone_id {
    + *      u1      byte_length;      // byte length of id
    + *      u1      id[byte_length];  // zone name string
    + *    }
    + * 
    + *
    + * + *

    2.2 raw_offset_table structure

    + *
    + *

    + *
    + *    raw_offset_table {
    + *      u1      tag;              // 0x41 : constant
    + *      u2      length;           // byte length of whole values
    + *      s4      value[length/4];  // raw GMT offset in milliseconds
    + *   }
    + * 
    + *
    + * + *

    2.3 raw_offset_index_table structure

    + *
    + *

    + *
    + *    raw_offset_index_table {
    + *      u1      tag;              // 0x42 : constant
    + *      u2      length;           // byte length of whole values
    + *      u1      value[length];
    + *    }
    + * 
    + *
    + * + *

    2.4 alias_table structure

    + *
    + *

    + *
    + *   alias_table {
    + *      u1      tag;              // 0x43 : constant
    + *      u2      length;           // byte length of whole values
    + *      u2      nentries;         // number of id-pairs
    + *      id_pair value[nentries];
    + *   }
    + *
    + *   id_pair {
    + *      zone_id aliasname;
    + *      zone_id ID;
    + *   }
    + * 
    + *
    + * + *

    2.5 versionName structure

    + *
    + *

    + *
    + *   versionName {
    + *      u1      tag;              // 0x44 : constant
    + *      u2      length;           // byte length of whole values
    + *      u1      value[length];
    + *   }
    + * 
    + *
    + * + *

    2.6 excludeList structure

    + * The list of zone IDs whose zones will change their GMT offsets + * (a.k.a. raw offsets) some time in the future. Those IDs must be + * added to the list of zone IDs for getAvailableIDs(). Also they must + * be examined for getAvailableIDs(int) to determine the + * current GMT offsets. + *
    + *

    + *
    + *   excluded_list {
    + *      u1      tag;              // 0x45 : constant
    + *      u2      length;           // byte length of whole values
    + *      u2      nentries;         // number of zone_ids
    + *      zone_id value[nentries];  // excluded zone IDs
    + *   }
    + * 
    + *
    + * + * @since 1.4 + */ + +public class ZoneInfoFile { + + /** + * The magic number for the ZoneInfo data file format. + */ + public static final byte[] JAVAZI_LABEL = { + (byte)'j', (byte)'a', (byte)'v', (byte)'a', (byte)'z', (byte)'i', (byte)'\0' + }; + private static final int JAVAZI_LABEL_LENGTH = JAVAZI_LABEL.length; + + /** + * The ZoneInfo data file format version number. Must increase + * one when any incompatible change has been made. + */ + public static final byte JAVAZI_VERSION = 0x01; + + /** + * Raw offset data item tag. + */ + public static final byte TAG_RawOffset = 1; + + /** + * Known last Daylight Saving Time save value data item tag. + */ + public static final byte TAG_LastDSTSaving = 2; + + /** + * Checksum data item tag. + */ + public static final byte TAG_CRC32 = 3; + + /** + * Transition data item tag. + */ + public static final byte TAG_Transition = 4; + + /** + * Offset table data item tag. + */ + public static final byte TAG_Offset = 5; + + /** + * SimpleTimeZone parameters data item tag. + */ + public static final byte TAG_SimpleTimeZone = 6; + + /** + * Raw GMT offset will change in the future. + */ + public static final byte TAG_GMTOffsetWillChange = 7; + + + /** + * The ZoneInfoMappings file name. + */ + public static final String JAVAZM_FILE_NAME = "ZoneInfoMappings"; + + /** + * The magic number for the ZoneInfoMappings file format. + */ + public static final byte[] JAVAZM_LABEL = { + (byte)'j', (byte)'a', (byte)'v', (byte)'a', (byte)'z', (byte)'m', (byte)'\0' + }; + private static final int JAVAZM_LABEL_LENGTH = JAVAZM_LABEL.length; + + /** + * The ZoneInfoMappings file format version number. Must increase + * one when any incompatible change has been made. + */ + public static final byte JAVAZM_VERSION = 0x01; + + /** + * Time zone IDs data item tag. + */ + public static final byte TAG_ZoneIDs = 64; + + /** + * Raw GMT offsets table data item tag. + */ + public static final byte TAG_RawOffsets = 65; + + /** + * Indices to the raw GMT offset table data item tag. + */ + public static final byte TAG_RawOffsetIndices = 66; + + /** + * Time zone aliases table data item tag. + */ + public static final byte TAG_ZoneAliases = 67; + + /** + * Olson's public zone information version tag. + */ + public static final byte TAG_TZDataVersion = 68; + + /** + * Excluded zones item tag. (Added in Mustang) + */ + public static final byte TAG_ExcludedZones = 69; + + private static Map zoneInfoObjects = null; + + private static final ZoneInfoOld GMT = new ZoneInfoOld("GMT", 0); + + static String ziDir; + + /** + * Converts the given time zone ID to a platform dependent path + * name. For example, "America/Los_Angeles" is converted to + * "America\Los_Angeles" on Win32. + * @return a modified ID replacing '/' with {@link + * java.io.File#separatorChar File.separatorChar} if needed. + */ + public static String getFileName(String ID) { + if (File.separatorChar == '/') { + return ID; + } + return ID.replace('/', File.separatorChar); + } + + /** + * Gets a ZoneInfo with the given GMT offset. The object + * has its ID in the format of GMT{+|-}hh:mm. + * + * @param originalId the given custom id (before normalized such as "GMT+9") + * @param gmtOffset GMT offset in milliseconds + * @return a ZoneInfo constructed with the given GMT offset + */ + public static ZoneInfoOld getCustomTimeZone(String originalId, int gmtOffset) { + String id = toCustomID(gmtOffset); + + ZoneInfoOld zi = getFromCache(id); + if (zi == null) { + zi = new ZoneInfoOld(id, gmtOffset); + zi = addToCache(id, zi); + if (!id.equals(originalId)) { + zi = addToCache(originalId, zi); + } + } + return (ZoneInfoOld) zi.clone(); + } + + public static String toCustomID(int gmtOffset) { + char sign; + int offset = gmtOffset / 60000; + + if (offset >= 0) { + sign = '+'; + } else { + sign = '-'; + offset = -offset; + } + int hh = offset / 60; + int mm = offset % 60; + + char[] buf = new char[] { 'G', 'M', 'T', sign, '0', '0', ':', '0', '0' }; + if (hh >= 10) { + buf[4] += hh / 10; + } + buf[5] += hh % 10; + if (mm != 0) { + buf[7] += mm / 10; + buf[8] += mm % 10; + } + return new String(buf); + } + + /** + * @return a ZoneInfo instance created for the specified id, or + * null if there is no time zone data file found for the specified + * id. + */ + public static ZoneInfoOld getZoneInfoOld(String id) { + //treat GMT zone as special + if ("GMT".equals(id)) + return (ZoneInfoOld) GMT.clone(); + ZoneInfoOld zi = getFromCache(id); + if (zi == null) { + Map aliases = ZoneInfoOld.getCachedAliasTable(); + if (aliases != null && aliases.get(id) != null) { + return null; + } + zi = createZoneInfoOld(id); + if (zi == null) { + return null; + } + zi = addToCache(id, zi); + } + return (ZoneInfoOld) zi.clone(); + } + + synchronized static ZoneInfoOld getFromCache(String id) { + if (zoneInfoObjects == null) { + return null; + } + return zoneInfoObjects.get(id); + } + + synchronized static ZoneInfoOld addToCache(String id, ZoneInfoOld zi) { + if (zoneInfoObjects == null) { + zoneInfoObjects = new HashMap<>(); + } else { + ZoneInfoOld zone = zoneInfoObjects.get(id); + if (zone != null) { + return zone; + } + } + zoneInfoObjects.put(id, zi); + return zi; + } + + private static ZoneInfoOld createZoneInfoOld(String id) { + byte[] buf = readZoneInfoFile(getFileName(id)); + if (buf == null) { + return null; + } + + int index = 0; + int filesize = buf.length; + int rawOffset = 0; + int dstSavings = 0; + int checksum = 0; + boolean willGMTOffsetChange = false; + long[] transitions = null; + int[] offsets = null; + int[] simpleTimeZoneParams = null; + + try { + for (index = 0; index < JAVAZI_LABEL.length; index++) { + if (buf[index] != JAVAZI_LABEL[index]) { + System.err.println("ZoneInfoOld: wrong magic number: " + id); + return null; + } + } + if (buf[index++] > JAVAZI_VERSION) { + System.err.println("ZoneInfo: incompatible version (" + + buf[index - 1] + "): " + id); + return null; + } + + while (index < filesize) { + byte tag = buf[index++]; + int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); + + if (filesize < index+len) { + break; + } + + switch (tag) { + case TAG_CRC32: + { + int val = buf[index++] & 0xff; + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + checksum = val; + } + break; + + case TAG_LastDSTSaving: + { + short val = (short)(buf[index++] & 0xff); + val = (short)((val << 8) + (buf[index++] & 0xff)); + dstSavings = val * 1000; + } + break; + + case TAG_RawOffset: + { + int val = buf[index++] & 0xff; + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + rawOffset = val; + } + break; + + case TAG_Transition: + { + int n = len / 8; + transitions = new long[n]; + for (int i = 0; i < n; i ++) { + long val = buf[index++] & 0xff; + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + transitions[i] = val; + } + } + break; + + case TAG_Offset: + { + int n = len / 4; + offsets = new int[n]; + for (int i = 0; i < n; i ++) { + int val = buf[index++] & 0xff; + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + offsets[i] = val; + } + } + break; + + case TAG_SimpleTimeZone: + { + if (len != 32 && len != 40) { + System.err.println("ZoneInfo: wrong SimpleTimeZone parameter size"); + return null; + } + int n = len / 4; + simpleTimeZoneParams = new int[n]; + for (int i = 0; i < n; i++) { + int val = buf[index++] & 0xff; + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + simpleTimeZoneParams[i] = val; + } + } + break; + + case TAG_GMTOffsetWillChange: + { + if (len != 1) { + System.err.println("ZoneInfo: wrong byte length for TAG_GMTOffsetWillChange"); + } + willGMTOffsetChange = buf[index++] == 1; + } + break; + + default: + System.err.println("ZoneInfo: unknown tag < " + tag + ">. ignored."); + index += len; + break; + } + } + } catch (Exception e) { + System.err.println("ZoneInfo: corrupted zoneinfo file: " + id); + return null; + } + + if (index != filesize) { + System.err.println("ZoneInfo: wrong file size: " + id); + return null; + } + + return new ZoneInfoOld(id, rawOffset, dstSavings, checksum, + transitions, offsets, simpleTimeZoneParams, + willGMTOffsetChange); + } + + private volatile static SoftReference> zoneIDs = null; + + static List getZoneIDs() { + List ids = null; + SoftReference> cache = zoneIDs; + if (cache != null) { + ids = cache.get(); + if (ids != null) { + return ids; + } + } + byte[] buf = null; + buf = getZoneInfoOldMappings(); + int index = JAVAZM_LABEL_LENGTH + 1; + int filesize = buf.length; + try { + loop: + while (index < filesize) { + byte tag = buf[index++]; + int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); + + switch (tag) { + case TAG_ZoneIDs: + { + int n = (buf[index++] << 8) + (buf[index++] & 0xFF); + ids = new ArrayList<>(n); + + for (int i = 0; i < n; i++) { + byte m = buf[index++]; + ids.add(new String(buf, index, m, "UTF-8")); + index += m; + } + } + break loop; + + default: + index += len; + break; + } + } + } catch (Exception e) { + System.err.println("ZoneInfoOld: corrupted " + JAVAZM_FILE_NAME); + } + + zoneIDs = new SoftReference<>(ids); + return ids; + } + + /** + * @return an alias table in HashMap where a key is an alias ID + * (e.g., "PST") and its value is a real time zone ID (e.g., + * "America/Los_Angeles"). + */ + static Map getZoneAliases() { + byte[] buf = getZoneInfoOldMappings(); + int index = JAVAZM_LABEL_LENGTH + 1; + int filesize = buf.length; + Map aliases = null; + + try { + loop: + while (index < filesize) { + byte tag = buf[index++]; + int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); + + switch (tag) { + case TAG_ZoneAliases: + { + int n = (buf[index++] << 8) + (buf[index++] & 0xFF); + aliases = new HashMap<>(n); + for (int i = 0; i < n; i++) { + byte m = buf[index++]; + String name = new String(buf, index, m, "UTF-8"); + index += m; + m = buf[index++]; + String realName = new String(buf, index, m, "UTF-8"); + index += m; + aliases.put(name, realName); + } + } + break loop; + + default: + index += len; + break; + } + } + } catch (Exception e) { + System.err.println("ZoneInfoOld: corrupted " + JAVAZM_FILE_NAME); + return null; + } + return aliases; + } + + private volatile static SoftReference> excludedIDs = null; + private volatile static boolean hasNoExcludeList = false; + + /** + * @return a List of zone IDs for zones that will change their GMT + * offsets in some future time. + * + * @since 1.6 + */ + static List getExcludedZones() { + if (hasNoExcludeList) { + return null; + } + + List excludeList = null; + + SoftReference> cache = excludedIDs; + if (cache != null) { + excludeList = cache.get(); + if (excludeList != null) { + return excludeList; + } + } + + byte[] buf = getZoneInfoOldMappings(); + int index = JAVAZM_LABEL_LENGTH + 1; + int filesize = buf.length; + + try { + loop: + while (index < filesize) { + byte tag = buf[index++]; + int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); + + switch (tag) { + case TAG_ExcludedZones: + { + int n = (buf[index++] << 8) + (buf[index++] & 0xFF); + excludeList = new ArrayList<>(); + for (int i = 0; i < n; i++) { + byte m = buf[index++]; + String name = new String(buf, index, m, "UTF-8"); + index += m; + excludeList.add(name); + } + } + break loop; + + default: + index += len; + break; + } + } + } catch (Exception e) { + System.err.println("ZoneInfoOld: corrupted " + JAVAZM_FILE_NAME); + return null; + } + + if (excludeList != null) { + excludedIDs = new SoftReference<>(excludeList); + } else { + hasNoExcludeList = true; + } + return excludeList; + } + + private volatile static SoftReference rawOffsetIndices = null; + + static byte[] getRawOffsetIndices() { + byte[] indices = null; + + SoftReference cache = rawOffsetIndices; + if (cache != null) { + indices = cache.get(); + if (indices != null) { + return indices; + } + } + + byte[] buf = getZoneInfoOldMappings(); + int index = JAVAZM_LABEL_LENGTH + 1; + int filesize = buf.length; + + try { + loop: + while (index < filesize) { + byte tag = buf[index++]; + int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); + + switch (tag) { + case TAG_RawOffsetIndices: + { + indices = new byte[len]; + for (int i = 0; i < len; i++) { + indices[i] = buf[index++]; + } + } + break loop; + + default: + index += len; + break; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("ZoneInfoOld: corrupted " + JAVAZM_FILE_NAME); + } + + rawOffsetIndices = new SoftReference<>(indices); + return indices; + } + + private volatile static SoftReference rawOffsets = null; + + static int[] getRawOffsets() { + int[] offsets = null; + + SoftReference cache = rawOffsets; + if (cache != null) { + offsets = cache.get(); + if (offsets != null) { + return offsets; + } + } + + byte[] buf = getZoneInfoOldMappings(); + int index = JAVAZM_LABEL_LENGTH + 1; + int filesize = buf.length; + + try { + loop: + while (index < filesize) { + byte tag = buf[index++]; + int len = ((buf[index++] & 0xFF) << 8) + (buf[index++] & 0xFF); + + switch (tag) { + case TAG_RawOffsets: + { + int n = len/4; + offsets = new int[n]; + for (int i = 0; i < n; i++) { + int val = buf[index++] & 0xff; + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + val = (val << 8) + (buf[index++] & 0xff); + offsets[i] = val; + } + } + break loop; + + default: + index += len; + break; + } + } + } catch (ArrayIndexOutOfBoundsException e) { + System.err.println("ZoneInfoOld: corrupted " + JAVAZM_FILE_NAME); + } + + rawOffsets = new SoftReference<>(offsets); + return offsets; + } + + private volatile static SoftReference zoneInfoMappings = null; + + private static byte[] getZoneInfoOldMappings() { + byte[] data; + SoftReference cache = zoneInfoMappings; + if (cache != null) { + data = cache.get(); + if (data != null) { + return data; + } + } + data = readZoneInfoFile(JAVAZM_FILE_NAME); + if (data == null) { + throw new RuntimeException("ZoneInfoOldMapping " + + JAVAZM_FILE_NAME + " either doesn't exist or doesn't have data"); + } + + int index; + for (index = 0; index < JAVAZM_LABEL.length; index++) { + if (data[index] != JAVAZM_LABEL[index]) { + System.err.println("ZoneInfoOld: wrong magic number: " + JAVAZM_FILE_NAME); + return null; + } + } + if (data[index++] > JAVAZM_VERSION) { + System.err.println("ZoneInfoOld: incompatible version (" + + data[index - 1] + "): " + JAVAZM_FILE_NAME); + return null; + } + + zoneInfoMappings = new SoftReference<>(data); + return data; + } + + /** + * Reads the specified file under <java.home>/lib/zi into a buffer. + * @return the buffer, or null if any I/O error occurred. + */ + private static byte[] readZoneInfoFile(final String fileName) { + if (fileName.indexOf("..") >= 0) { + return null; + } + byte[] buffer = null; + File file = new File(ziDir, fileName); + try { + int filesize = (int)file.length(); + if (filesize > 0) { + FileInputStream fis = new FileInputStream(file); + buffer = new byte[filesize]; + try { + if (fis.read(buffer) != filesize) { + throw new IOException("read error on " + fileName); + } + } finally { + fis.close(); + } + } + } catch (Exception ex) { + if (!(ex instanceof FileNotFoundException) || JAVAZM_FILE_NAME.equals(fileName)) { + System.err.println("ZoneInfoOld: " + ex.getMessage()); + } + } + return buffer; + } + + private ZoneInfoFile() { + } +} diff --git a/jdk/test/sun/util/calendar/zi/ZoneInfoOld.java b/jdk/test/sun/util/calendar/zi/ZoneInfoOld.java new file mode 100644 index 00000000000..4a0a31e087d --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/ZoneInfoOld.java @@ -0,0 +1,1047 @@ +/* + * Copyright (c) 2000, 2012, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.IOException; +import java.io.ObjectInputStream; +import java.lang.ref.SoftReference; +import java.time.ZoneOffset; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.SimpleTimeZone; +import java.util.TimeZone; + +import sun.util.calendar.CalendarSystem; +import sun.util.calendar.CalendarDate; + +/** + * ZoneInfoOld is an implementation subclass of {@link + * java.util.TimeZone TimeZone} that represents GMT offsets and + * daylight saving time transitions of a time zone. + *

    + * The daylight saving time transitions are described in the {@link + * #transitions transitions} table consisting of a chronological + * sequence of transitions of GMT offset and/or daylight saving time + * changes. Since all transitions are represented in UTC, in theory, + * ZoneInfoOld can be used with any calendar systems except + * for the {@link #getOffset(int,int,int,int,int,int) getOffset} + * method that takes Gregorian calendar date fields. + *

    + * This table covers transitions from 1900 until 2037 (as of version + * 1.4), Before 1900, it assumes that there was no daylight saving + * time and the getOffset methods always return the + * {@link #getRawOffset} value. No Local Mean Time is supported. If a + * specified date is beyond the transition table and this time zone is + * supposed to observe daylight saving time in 2037, it delegates + * operations to a {@link java.util.SimpleTimeZone SimpleTimeZone} + * object created using the daylight saving time schedule as of 2037. + *

    + * The date items, transitions, GMT offset(s), etc. are read from a database + * file. See {@link ZoneInfoFile} for details. + * @see java.util.SimpleTimeZone + * @since 1.4 + */ + +public class ZoneInfoOld extends TimeZone { + + // The constants assume no leap seconds support. + static final int SECOND_IN_MILLIS = 1000; + static final int MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60; + static final int HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60; + static final int DAY_IN_MILLIS = HOUR_IN_MILLIS * 24; + + private static final int UTC_TIME = 0; + private static final int STANDARD_TIME = 1; + private static final int WALL_TIME = 2; + + private static final long OFFSET_MASK = 0x0fL; + private static final long DST_MASK = 0xf0L; + private static final int DST_NSHIFT = 4; + // this bit field is reserved for abbreviation support + private static final long ABBR_MASK = 0xf00L; + private static final int TRANSITION_NSHIFT = 12; + + // Flag for supporting JDK backward compatible IDs, such as "EST". + static final boolean USE_OLDMAPPING; + static { + String oldmapping = System.getProperty("sun.timezone.ids.oldmapping", "false").toLowerCase(Locale.ROOT); + USE_OLDMAPPING = (oldmapping.equals("yes") || oldmapping.equals("true")); + } + + // IDs having conflicting data between Olson and JDK 1.1 + static final String[] conflictingIDs = { + "EST", "MST", "HST" + }; + + private static final CalendarSystem gcal = CalendarSystem.getGregorianCalendar(); + + /** + * The raw GMT offset in milliseconds between this zone and GMT. + * Negative offsets are to the west of Greenwich. To obtain local + * standard time, add the offset to GMT time. + * @serial + */ + int rawOffset; + + /** + * Difference in milliseconds from the original GMT offset in case + * the raw offset value has been modified by calling {@link + * #setRawOffset}. The initial value is 0. + * @serial + */ + int rawOffsetDiff = 0; + + /** + * A CRC32 value of all pairs of transition time (in milliseconds + * in long) in local time and its GMT offset (in + * seconds in int) in the chronological order. Byte + * values of each long and int are taken + * in the big endian order (i.e., MSB to LSB). + * @serial + */ + int checksum; + + /** + * The amount of time in milliseconds saved during daylight saving + * time. If useDaylight is false, this value is 0. + * @serial + */ + int dstSavings; + + /** + * This array describes transitions of GMT offsets of this time + * zone, including both raw offset changes and daylight saving + * time changes. + * A long integer consists of four bit fields. + *

      + *
    • The most significant 52-bit field represents transition + * time in milliseconds from Gregorian January 1 1970, 00:00:00 + * GMT.
    • + *
    • The next 4-bit field is reserved and must be 0.
    • + *
    • The next 4-bit field is an index value to {@link #offsets + * offsets[]} for the amount of daylight saving at the + * transition. If this value is zero, it means that no daylight + * saving, not the index value zero.
    • + *
    • The least significant 4-bit field is an index value to + * {@link #offsets offsets[]} for total GMT offset at the + * transition.
    • + *
    + * If this time zone doesn't observe daylight saving time and has + * never changed any GMT offsets in the past, this value is null. + * @serial + */ + long[] transitions; + + /** + * This array holds all unique offset values in + * milliseconds. Index values to this array are stored in the + * transitions array elements. + * @serial + */ + int[] offsets; + + /** + * SimpleTimeZone parameter values. It has to have either 8 for + * {@link java.util.SimpleTimeZone#SimpleTimeZone(int, String, + * int, int , int , int , int , int , int , int , int) the + * 11-argument SimpleTimeZone constructor} or 10 for {@link + * java.util.SimpleTimeZone#SimpleTimeZone(int, String, int, int, + * int , int , int , int , int , int , int, int, int) the + * 13-argument SimpleTimeZone constructor} parameters. + * @serial + */ + int[] simpleTimeZoneParams; + + /** + * True if the raw GMT offset value would change after the time + * zone data has been generated; false, otherwise. The default + * value is false. + * @serial + */ + boolean willGMTOffsetChange = false; + + /** + * True if the object has been modified after its instantiation. + */ + transient private boolean dirty = false; + + private static final long serialVersionUID = 2653134537216586139L; + + /** + * A constructor. + */ + public ZoneInfoOld() { + } + + /** + * A Constructor for CustomID. + */ + public ZoneInfoOld(String ID, int rawOffset) { + this(ID, rawOffset, 0, 0, null, null, null, false); + } + + /** + * Constructs a ZoneInfoOld instance. + * + * @param ID time zone name + * @param rawOffset GMT offset in milliseconds + * @param dstSavings daylight saving value in milliseconds or 0 + * (zero) if this time zone doesn't observe Daylight Saving Time. + * @param checksum CRC32 value with all transitions table entry + * values + * @param transitions transition table + * @param offsets offset value table + * @param simpleTimeZoneParams parameter values for constructing + * SimpleTimeZone + * @param willGMTOffsetChange the value of willGMTOffsetChange + */ + ZoneInfoOld(String ID, + int rawOffset, + int dstSavings, + int checksum, + long[] transitions, + int[] offsets, + int[] simpleTimeZoneParams, + boolean willGMTOffsetChange) { + setID(ID); + this.rawOffset = rawOffset; + this.dstSavings = dstSavings; + this.checksum = checksum; + this.transitions = transitions; + this.offsets = offsets; + this.simpleTimeZoneParams = simpleTimeZoneParams; + this.willGMTOffsetChange = willGMTOffsetChange; + } + + /** + * Returns the difference in milliseconds between local time and UTC + * of given time, taking into account both the raw offset and the + * effect of daylight savings. + * + * @param date the milliseconds in UTC + * @return the milliseconds to add to UTC to get local wall time + */ + public int getOffset(long date) { + return getOffsets(date, null, UTC_TIME); + } + + public int getOffsets(long utc, int[] offsets) { + return getOffsets(utc, offsets, UTC_TIME); + } + + public int getOffsetsByStandard(long standard, int[] offsets) { + return getOffsets(standard, offsets, STANDARD_TIME); + } + + public int getOffsetsByWall(long wall, int[] offsets) { + return getOffsets(wall, offsets, WALL_TIME); + } + + private int getOffsets(long date, int[] offsets, int type) { + // if dst is never observed, there is no transition. + if (transitions == null) { + int offset = getLastRawOffset(); + if (offsets != null) { + offsets[0] = offset; + offsets[1] = 0; + } + return offset; + } + + date -= rawOffsetDiff; + int index = getTransitionIndex(date, type); + + // prior to the transition table, returns the raw offset. + // FIXME: should support LMT. + if (index < 0) { + int offset = getLastRawOffset(); + if (offsets != null) { + offsets[0] = offset; + offsets[1] = 0; + } + return offset; + } + + if (index < transitions.length) { + long val = transitions[index]; + int offset = this.offsets[(int)(val & OFFSET_MASK)] + rawOffsetDiff; + if (offsets != null) { + int dst = (int)((val >>> DST_NSHIFT) & 0xfL); + int save = (dst == 0) ? 0 : this.offsets[dst]; + offsets[0] = offset - save; + offsets[1] = save; + } + return offset; + } + + // beyond the transitions, delegate to SimpleTimeZone if there + // is a rule; otherwise, return rawOffset. + SimpleTimeZone tz = getLastRule(); + if (tz != null) { + int rawoffset = tz.getRawOffset(); + long msec = date; + if (type != UTC_TIME) { + msec -= rawOffset; + } + int dstoffset = tz.getOffset(msec) - rawOffset; + + // Check if it's in a standard-to-daylight transition. + if (dstoffset > 0 && tz.getOffset(msec - dstoffset) == rawoffset) { + dstoffset = 0; + } + + if (offsets != null) { + offsets[0] = rawoffset; + offsets[1] = dstoffset; + } + return rawoffset + dstoffset; + } + int offset = getLastRawOffset(); + if (offsets != null) { + offsets[0] = offset; + offsets[1] = 0; + } + return offset; + } + + private int getTransitionIndex(long date, int type) { + int low = 0; + int high = transitions.length - 1; + + while (low <= high) { + int mid = (low + high) / 2; + long val = transitions[mid]; + long midVal = val >> TRANSITION_NSHIFT; // sign extended + if (type != UTC_TIME) { + midVal += offsets[(int)(val & OFFSET_MASK)]; // wall time + } + if (type == STANDARD_TIME) { + int dstIndex = (int)((val >>> DST_NSHIFT) & 0xfL); + if (dstIndex != 0) { + midVal -= offsets[dstIndex]; // make it standard time + } + } + + if (midVal < date) { + low = mid + 1; + } else if (midVal > date) { + high = mid - 1; + } else { + return mid; + } + } + + // if beyond the transitions, returns that index. + if (low >= transitions.length) { + return low; + } + return low - 1; + } + + /** + * Returns the difference in milliseconds between local time and + * UTC, taking into account both the raw offset and the effect of + * daylight savings, for the specified date and time. This method + * assumes that the start and end month are distinct. This method + * assumes a Gregorian calendar for calculations. + *

    + * Note: In general, clients should use + * {@link Calendar#ZONE_OFFSET Calendar.get(ZONE_OFFSET)} + + * {@link Calendar#DST_OFFSET Calendar.get(DST_OFFSET)} + * instead of calling this method. + * + * @param era The era of the given date. The value must be either + * GregorianCalendar.AD or GregorianCalendar.BC. + * @param year The year in the given date. + * @param month The month in the given date. Month is 0-based. e.g., + * 0 for January. + * @param day The day-in-month of the given date. + * @param dayOfWeek The day-of-week of the given date. + * @param millis The milliseconds in day in standard local time. + * @return The milliseconds to add to UTC to get local time. + */ + public int getOffset(int era, int year, int month, int day, + int dayOfWeek, int milliseconds) { + if (milliseconds < 0 || milliseconds >= DAY_IN_MILLIS) { + throw new IllegalArgumentException(); + } + + if (era == java.util.GregorianCalendar.BC) { // BC + year = 1 - year; + } else if (era != java.util.GregorianCalendar.AD) { + throw new IllegalArgumentException(); + } + + CalendarDate date = gcal.newCalendarDate(null); + date.setDate(year, month + 1, day); + if (gcal.validate(date) == false) { + throw new IllegalArgumentException(); + } + + // bug-for-bug compatible argument checking + if (dayOfWeek < java.util.GregorianCalendar.SUNDAY + || dayOfWeek > java.util.GregorianCalendar.SATURDAY) { + throw new IllegalArgumentException(); + } + + if (transitions == null) { + return getLastRawOffset(); + } + + long dateInMillis = gcal.getTime(date) + milliseconds; + dateInMillis -= (long) rawOffset; // make it UTC + return getOffsets(dateInMillis, null, UTC_TIME); + } + + /** + * Sets the base time zone offset from GMT. This operation + * modifies all the transitions of this ZoneInfoOld object, including + * historical ones, if applicable. + * + * @param offsetMillis the base time zone offset to GMT. + * @see getRawOffset + */ + public synchronized void setRawOffset(int offsetMillis) { + if (offsetMillis == rawOffset + rawOffsetDiff) { + return; + } + rawOffsetDiff = offsetMillis - rawOffset; + if (lastRule != null) { + lastRule.setRawOffset(offsetMillis); + } + dirty = true; + } + + /** + * Returns the GMT offset of the current date. This GMT offset + * value is not modified during Daylight Saving Time. + * + * @return the GMT offset value in milliseconds to add to UTC time + * to get local standard time + */ + public int getRawOffset() { + if (!willGMTOffsetChange) { + return rawOffset + rawOffsetDiff; + } + + int[] offsets = new int[2]; + getOffsets(System.currentTimeMillis(), offsets, UTC_TIME); + return offsets[0]; + } + + public boolean isDirty() { + return dirty; + } + + int getLastRawOffset() { + return rawOffset + rawOffsetDiff; + } + + /** + * Queries if this time zone uses Daylight Saving Time in the last known rule. + */ + public boolean useDaylightTime() { + return (simpleTimeZoneParams != null); + } + + @Override + public boolean observesDaylightTime() { + if (simpleTimeZoneParams != null) { + return true; + } + if (transitions == null) { + return false; + } + + // Look up the transition table to see if it's in DST right + // now or if there's any standard-to-daylight transition at + // any future. + long utc = System.currentTimeMillis() - rawOffsetDiff; + int index = getTransitionIndex(utc, UTC_TIME); + + // before transitions in the transition table + if (index < 0) { + return false; + } + + // the time is in the table range. + for (int i = index; i < transitions.length; i++) { + if ((transitions[i] & DST_MASK) != 0) { + return true; + } + } + // No further DST is observed. + return false; + } + + /** + * Queries if the specified date is in Daylight Saving Time. + */ + public boolean inDaylightTime(Date date) { + if (date == null) { + throw new NullPointerException(); + } + + if (transitions == null) { + return false; + } + + long utc = date.getTime() - rawOffsetDiff; + int index = getTransitionIndex(utc, UTC_TIME); + + // before transitions in the transition table + if (index < 0) { + return false; + } + + // the time is in the table range. + if (index < transitions.length) { + return (transitions[index] & DST_MASK) != 0; + } + + // beyond the transition table + SimpleTimeZone tz = getLastRule(); + if (tz != null) { + return tz.inDaylightTime(date); + } + return false; + } + + /** + * Returns the amount of time in milliseconds that the clock is advanced + * during daylight saving time is in effect in its last daylight saving time rule. + * + * @return the number of milliseconds the time is advanced with respect to + * standard time when daylight saving time is in effect. + */ + public int getDSTSavings() { + return dstSavings; + } + +// /** +// * @return the last year in the transition table or -1 if this +// * time zone doesn't observe any daylight saving time. +// */ +// public int getMaxTransitionYear() { +// if (transitions == null) { +// return -1; +// } +// long val = transitions[transitions.length - 1]; +// int offset = this.offsets[(int)(val & OFFSET_MASK)] + rawOffsetDiff; +// val = (val >> TRANSITION_NSHIFT) + offset; +// CalendarDate lastDate = Gregorian.getCalendarDate(val); +// return lastDate.getYear(); +// } + + /** + * Returns a string representation of this time zone. + * @return the string + */ + public String toString() { + return getClass().getName() + + "[id=\"" + getID() + "\"" + + ",offset=" + getLastRawOffset() + + ",dstSavings=" + dstSavings + + ",useDaylight=" + useDaylightTime() + + ",transitions=" + ((transitions != null) ? transitions.length : 0) + + ",lastRule=" + (lastRule == null ? getLastRuleInstance() : lastRule) + + "]"; + } + + /** + * Gets all available IDs supported in the Java run-time. + * + * @return an array of time zone IDs. + */ + public static String[] getAvailableIDs() { + List idList = ZoneInfoFile.getZoneIDs(); + List excluded = ZoneInfoFile.getExcludedZones(); + if (excluded != null) { + // List all zones from the idList and excluded lists + List list = new ArrayList<>(idList.size() + excluded.size()); + list.addAll(idList); + list.addAll(excluded); + idList = list; + } + String[] ids = new String[idList.size()]; + return idList.toArray(ids); + } + + /** + * Gets all available IDs that have the same value as the + * specified raw GMT offset. + * + * @param rawOffset the GMT offset in milliseconds. This + * value should not include any daylight saving time. + * + * @return an array of time zone IDs. + */ + public static String[] getAvailableIDs(int rawOffset) { + String[] result; + List matched = new ArrayList<>(); + List IDs = ZoneInfoFile.getZoneIDs(); + int[] rawOffsets = ZoneInfoFile.getRawOffsets(); + + loop: + for (int index = 0; index < rawOffsets.length; index++) { + if (rawOffsets[index] == rawOffset) { + byte[] indices = ZoneInfoFile.getRawOffsetIndices(); + for (int i = 0; i < indices.length; i++) { + if (indices[i] == index) { + matched.add(IDs.get(i++)); + while (i < indices.length && indices[i] == index) { + matched.add(IDs.get(i++)); + } + break loop; + } + } + } + } + + // We need to add any zones from the excluded zone list that + // currently have the same GMT offset as the specified + // rawOffset. The zones returned by this method may not be + // correct as of return to the caller if any GMT offset + // transition is happening during this GMT offset checking... + List excluded = ZoneInfoFile.getExcludedZones(); + if (excluded != null) { + for (String id : excluded) { + TimeZone zi = getTimeZone(id); + if (zi != null && zi.getRawOffset() == rawOffset) { + matched.add(id); + } + } + } + + result = new String[matched.size()]; + matched.toArray(result); + return result; + } + + /** + * Gets the ZoneInfoOld for the given ID. + * + * @param ID the ID for a ZoneInfoOld. See TimeZone for detail. + * + * @return the specified ZoneInfoOld object, or null if there is no + * time zone of the ID. + */ + public static TimeZone getTimeZone(String ID) { + String givenID = null; + + /* + * If old JDK compatibility is specified, get the old alias + * name. + */ + if (USE_OLDMAPPING) { + String compatibleID = TzIDOldMapping.MAP.get(ID); + if (compatibleID != null) { + givenID = ID; + ID = compatibleID; + } + } + + ZoneInfoOld zi = ZoneInfoFile.getZoneInfoOld(ID); + if (zi == null) { + // if we can't create an object for the ID, try aliases. + try { + Map map = getAliasTable(); + String alias = ID; + while ((alias = map.get(alias)) != null) { + zi = ZoneInfoFile.getZoneInfoOld(alias); + if (zi != null) { + zi.setID(ID); + zi = ZoneInfoFile.addToCache(ID, zi); + zi = (ZoneInfoOld) zi.clone(); + break; + } + } + } catch (Exception e) { + // ignore exceptions + } + } + + if (givenID != null && zi != null) { + zi.setID(givenID); + } + return zi; + } + + private transient SimpleTimeZone lastRule; + + /** + * Returns a SimpleTimeZone object representing the last GMT + * offset and DST schedule or null if this time zone doesn't + * observe DST. + */ + synchronized SimpleTimeZone getLastRule() { + if (lastRule == null) { + lastRule = getLastRuleInstance(); + } + return lastRule; + } + + /** + * Returns a SimpleTimeZone object that represents the last + * known daylight saving time rules. + * + * @return a SimpleTimeZone object or null if this time zone + * doesn't observe DST. + */ + public SimpleTimeZone getLastRuleInstance() { + if (simpleTimeZoneParams == null) { + return null; + } + if (simpleTimeZoneParams.length == 10) { + return new SimpleTimeZone(getLastRawOffset(), getID(), + simpleTimeZoneParams[0], + simpleTimeZoneParams[1], + simpleTimeZoneParams[2], + simpleTimeZoneParams[3], + simpleTimeZoneParams[4], + simpleTimeZoneParams[5], + simpleTimeZoneParams[6], + simpleTimeZoneParams[7], + simpleTimeZoneParams[8], + simpleTimeZoneParams[9], + dstSavings); + } + return new SimpleTimeZone(getLastRawOffset(), getID(), + simpleTimeZoneParams[0], + simpleTimeZoneParams[1], + simpleTimeZoneParams[2], + simpleTimeZoneParams[3], + simpleTimeZoneParams[4], + simpleTimeZoneParams[5], + simpleTimeZoneParams[6], + simpleTimeZoneParams[7], + dstSavings); + } + + /** + * Returns a copy of this ZoneInfoOld. + */ + public Object clone() { + ZoneInfoOld zi = (ZoneInfoOld) super.clone(); + zi.lastRule = null; + return zi; + } + + /** + * Returns a hash code value calculated from the GMT offset and + * transitions. + * @return a hash code of this time zone + */ + public int hashCode() { + return getLastRawOffset() ^ checksum; + } + + /** + * Compares the equity of two ZoneInfoOld objects. + * + * @param obj the object to be compared with + * @return true if given object is same as this ZoneInfoOld object, + * false otherwise. + */ + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ZoneInfoOld)) { + return false; + } + ZoneInfoOld that = (ZoneInfoOld) obj; + return (getID().equals(that.getID()) + && (getLastRawOffset() == that.getLastRawOffset()) + && (checksum == that.checksum)); + } + + /** + * Returns true if this zone has the same raw GMT offset value and + * transition table as another zone info. If the specified + * TimeZone object is not a ZoneInfoOld instance, this method returns + * true if the specified TimeZone object has the same raw GMT + * offset value with no daylight saving time. + * + * @param other the ZoneInfoOld object to be compared with + * @return true if the given TimeZone has the same + * GMT offset and transition information; false, otherwise. + */ + public boolean hasSameRules(TimeZone other) { + if (this == other) { + return true; + } + if (other == null) { + return false; + } + if (!(other instanceof ZoneInfoOld)) { + if (getRawOffset() != other.getRawOffset()) { + return false; + } + // if both have the same raw offset and neither observes + // DST, they have the same rule. + if ((transitions == null) + && (useDaylightTime() == false) + && (other.useDaylightTime() == false)) { + return true; + } + return false; + } + if (getLastRawOffset() != ((ZoneInfoOld)other).getLastRawOffset()) { + return false; + } + return (checksum == ((ZoneInfoOld)other).checksum); + } + + private static SoftReference> aliasTable; + + static Map getCachedAliasTable() { + Map aliases = null; + + SoftReference> cache = aliasTable; + if (cache != null) { + aliases = cache.get(); + } + return aliases; + } + + /** + * Returns a Map from alias time zone IDs to their standard + * time zone IDs. + * + * @return the Map that holds the mappings from alias time zone IDs + * to their standard time zone IDs, or null if + * ZoneInfoOldMappings file is not available. + */ + public synchronized static Map getAliasTable() { + Map aliases = getCachedAliasTable(); + if (aliases == null) { + aliases = ZoneInfoFile.getZoneAliases(); + if (aliases != null) { + if (!USE_OLDMAPPING) { + // Remove the conflicting IDs from the alias table. + for (String key : conflictingIDs) { + aliases.remove(key); + } + } + aliasTable = new SoftReference>(aliases); + } + } + return aliases; + } + + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + // We don't know how this object from 1.4.x or earlier has + // been mutated. So it should always be marked as `dirty'. + dirty = true; + } + + ////////////////////////////////////////////////////////////// + public boolean equalsTo(ZoneInfoOld other) { + return (getID().equals(other.getID()) + && (getLastRawOffset() == other.getLastRawOffset()) + && (dstSavings == other.dstSavings) + && (willGMTOffsetChange == other.willGMTOffsetChange) + && (checksum == other.checksum) + && equalsTransOffsets(other) + && (Arrays.equals(simpleTimeZoneParams, other.simpleTimeZoneParams) || + getLastRule().equals(other.getLastRule()))); + } + + private boolean equalsTransOffsets(ZoneInfoOld other) { + if (transitions == null) { + return (other.transitions == null && + Arrays.equals(offsets, other.offsets)); + } + if (other.transitions == null || + transitions.length != other.transitions.length) { + return false; + } + // if offsets and other.offsets have different order + // the last 4-bit in trans are different. + for (int i = 0; i < transitions.length; i++) { + long val = transitions[i]; + int dst = (int)((val >>> DST_NSHIFT) & 0xfL); + int save = (dst == 0) ? 0 : offsets[dst] / 1000; + int off = offsets[(int)(val & OFFSET_MASK)]/1000; + long second = (val >> TRANSITION_NSHIFT)/1000; + + val = other.transitions[i]; + int dstO = (int)((val >>> DST_NSHIFT) & 0xfL); + int saveO = (dstO == 0) ? 0 : other.offsets[dstO] / 1000; + int offO = other.offsets[(int)(val & OFFSET_MASK)]/1000; + long secondO = (val >> TRANSITION_NSHIFT)/1000; + if ((dst == 0) != (dstO == 0) || save != saveO || off != offO || second != secondO) + return false; + } + return true; + } + + private int transToString(long val, int off_old, int[] offsets, StringBuilder sb) { + int dst = (int)((val >>> DST_NSHIFT) & 0xfL); + int save = (dst == 0) ? 0 : offsets[dst] / 1000; + int off = offsets[(int)(val & OFFSET_MASK)]/1000; + long second = (val >> TRANSITION_NSHIFT)/1000; + ZoneOffset offset_old = ZoneOffset.ofTotalSeconds(off_old); + ZoneOffset offset = ZoneOffset.ofTotalSeconds(off); + sb.append(" " + LocalDateTime.ofEpochSecond(second, 0, offset_old)); + + sb.append(" [utc=" + second + + " raw=" + Long.toHexString(val >> TRANSITION_NSHIFT) + + ", offset=" + off + "/" + offset + ", saving=" + save + "]"); + return off; + } + + public String diffsTo(ZoneInfoOld other) { + + int rawOffset0 = other.rawOffset; + int checksum0 = other.checksum; + int dstSavings0 = other.dstSavings; + long[] transitions0 = other.transitions; + int[] offsets0 = other.offsets; + int[] simpleTimeZoneParams0 = other.simpleTimeZoneParams; + boolean willGMTOffsetChange0 = other.willGMTOffsetChange; + + + //return getClass().getName() + + StringBuilder sb = new StringBuilder(); + sb.append("******************************\n" + + getID() + " : " + other.getID()); + // ROC is excluded by ZoneInfoOld + if ("ROC".equals(getID())) { + return sb.toString(); + } + if (rawOffset != rawOffset0 || + dstSavings != dstSavings0 || + checksum != checksum0 || + willGMTOffsetChange != willGMTOffsetChange0 || + (simpleTimeZoneParams != null ) != (simpleTimeZoneParams0 != null) || + (transitions != null && transitions0 != null && + transitions.length != transitions0.length)) + { + sb.append("\n offset=" + getLastRawOffset() + + ",dstSavings=" + dstSavings + + ",useDaylight=" + useDaylightTime() + + ",transitions=" + ((transitions != null) ? transitions.length : 0) + + ",offsets=" + ((offsets != null) ? offsets.length : 0) + + ",checksum=" + checksum + + ",gmtChanged=" + willGMTOffsetChange) + .append("\n[NG]offset=" + rawOffset0 + + ",dstSavings=" + dstSavings0 + + ",useDaylight=" + (simpleTimeZoneParams != null) + + ",transitions=" + ((transitions0 != null) ? transitions0.length : 0) + + ",offsets=" + ((offsets0 != null) ? offsets0.length : 0) + + ",checksum=" + checksum0 + + ",gmtChanged=" + willGMTOffsetChange0 + + ""); + } + // offsets + if (!Arrays.equals(offsets, offsets0)) { + sb.append("\n offset.len=" + ((offsets != null)? offsets.length : "null") + + " " + ((offsets0 != null)? offsets0.length : "null")); + if (offsets != null && offsets0.length != 0) { + int len = Math.min(offsets.length, offsets0.length); + int i = 0; + for (i = 0; i < len; i++) { + sb.append("\n " + + ZoneOffset.ofTotalSeconds(offsets[i]/1000) + " " + + ZoneOffset.ofTotalSeconds(offsets0[i]/1000)); + } + for (; i < offsets0.length; i++) { + sb.append("\n " + ZoneOffset.ofTotalSeconds(offsets0[i]/1000)); + } + } + } + // trans + int offset = 0; + int offset0 = 0; + if (!equalsTransOffsets(other)) { + sb.append("\n -------------"); + if ((transitions == null) != (transitions0 == null)) { + sb.append("\n (NG) Different trans(null) :" + + transitions + ", " + transitions0); + if (transitions != null) { + for (int i = 0; i < transitions.length; i++) { + sb.append("\n (NG)"); + offset = transToString(transitions[i], offset, offsets, sb); + } + } + } else { + if (transitions.length != transitions0.length) { + sb.append("\n (NG) Different trans size :" + + transitions.length + ", " + transitions0.length); + } + int length = Math.min(transitions.length, transitions0.length); + for (int i = 0; i < length; i++) { + // sb.append("\n[" + i + "] "); + // offset = transToString(transitions[i], offset, offsets, sb); + long val = transitions[i]; + int dst = (int)((val >>> DST_NSHIFT) & 0xfL); + int save = (dst == 0) ? 0 : offsets[dst] / 1000; + int off = offsets[(int)(val & OFFSET_MASK)]/1000; + long second = (val >> TRANSITION_NSHIFT)/1000; + sb.append("\n "); + offset = transToString(transitions[i], offset, offsets, sb); + if (transitions0 == null || i >= transitions0.length) { + sb.append("\n "); + offset = transToString(transitions[i], offset, offsets, sb); + sb.append("\n (NG) trans0 is null or < trans.length"); + } else { + long val0 = transitions0[i]; + int dst0 = (int)((val0 >>> DST_NSHIFT) & 0xfL); + int save0 = (dst0 == 0) ? 0 : offsets0[dst0] / 1000; + int off0 = offsets0[(int)(val0 & OFFSET_MASK)]/1000; + long second0 = (val0 >> TRANSITION_NSHIFT)/1000; + if (save != save0 || off != off0 || second != second0) { + sb.append("\n (NG)"); + } else { + sb.append("\n (OK)"); + } + offset0 = transToString(transitions0[i], offset0, offsets0, sb); + sb.append("\n -----"); + } + } + } + } + SimpleTimeZone stz = getLastRuleInstance(); + if (stz != null) { + SimpleTimeZone stz0 = other.getLastRule(); + if (!stz.hasSameRules(stz0)) { + sb.append("\n -------------") + .append("\n SimpleTimeZone (NG)") + .append("\n stz=" + stz) + .append("\n stz0=" + stz0); + } + } + sb.append("\n -------------"); + return sb.toString(); + } +} diff --git a/jdk/test/sun/util/calendar/zi/ZoneRec.java b/jdk/test/sun/util/calendar/zi/ZoneRec.java new file mode 100644 index 00000000000..e96346f4e2a --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/ZoneRec.java @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2000, 2004, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.BufferedReader; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + +/** + * ZoneRec hold information of time zone corresponding to each text + * line of the "Zone" part. + * + * @since 1.4 + */ +class ZoneRec { + private int gmtOffset; + private String ruleName; + private int directSave; + private Rule ruleRef; + private String format; + private boolean hasUntil; + private int untilYear; + private Month untilMonth; + private RuleDay untilDay; + private Time untilTime; + private long untilInMillis; + private String line; + + /** + * @return the "UNTIL" value in milliseconds + */ + Time getUntilTime() { + return untilTime; + } + + /** + * @return the GMT offset value in milliseconds + */ + int getGmtOffset() { + return gmtOffset; + } + + /** + * @return the rule name to which this zone record refers + */ + String getRuleName() { + return ruleName; + } + + /** + * @return the amount of saving time directly defined in the + * "RULES/SAVE" field. + */ + int getDirectSave() { + return directSave; + } + + /** + * @return true if this zone record has a reference to a rule + */ + boolean hasRuleReference() { + return ruleRef != null; + } + + /** + * Returns the "FORMAT" field string of this zone record. This + * @return the "FORMAT" field + */ + String getFormat() { + return format; + } + + /** + * @return the year in the "UNTIL" field + */ + int getUntilYear() { + return untilYear; + } + + /** + * Returns the "UNTIL" field value in milliseconds from Janurary + * 1, 1970 0:00 GMT. + * @param currentSave the amount of daylight saving in + * milliseconds that is used to adjust wall-clock time. + * @return the milliseconds value of the "UNTIL" field + */ + long getUntilTime(int currentSave) { + if (untilTime.isWall()) { + return untilInMillis - currentSave; + } + return untilInMillis; + } + + /** + * Returns the "UNTIL" time in milliseconds without adjusting GMT + * offsets or daylight saving. + * @return local "UNTIL" time in milliseconds + */ + long getLocalUntilTime() { + return Time.getLocalTime(untilYear, + untilMonth, + untilDay, + untilTime.getTime()); + } + + /** + * Returns the "UNTIL" time in milliseconds with adjusting GMT offsets and daylight saving. + * @return the "UNTIL" time after the adjustment + */ + long getLocalUntilTime(int save, int gmtOffset) { + return Time.getLocalTime(untilYear, + untilMonth, + untilDay, + save, + gmtOffset, + untilTime); + } + + /** + * @return the text line of this zone record + */ + String getLine() { + return line; + } + + /** + * Sets the specified text line to this zone record + */ + void setLine(String line) { + this.line = line; + } + + /** + * @return true if this zone record has the "UNTIL" field + */ + boolean hasUntil() { + return this.hasUntil; + } + + /** + * Adjusts the "UNTIL" time to GMT offset if this zone record has + * it. untilTime is not adjusted to daylight saving + * in this method. + */ + void adjustTime() { + if (!hasUntil()) { + return; + } + if (untilTime.isSTD() || untilTime.isWall()) { + // adjust to gmt offset only here. adjust to real + // wall-clock time when tracking rules + untilInMillis -= gmtOffset; + } + } + + /** + * @return the reference to the Rule object + */ + Rule getRuleRef() { + return ruleRef; + } + + /** + * Resolves the reference to a Rule and adjusts its "UNTIL" time + * to GMT offset. + */ + void resolve(Zoneinfo zi) { + if (ruleName != null && (!"-".equals(ruleName))) { + ruleRef = zi.getRule(ruleName); + } + adjustTime(); + } + + /** + * Parses a Zone text line that is described by a StringTokenizer. + * @param tokens represents tokens of a Zone text line + * @return the zone record produced by parsing the text + */ + static ZoneRec parse(StringTokenizer tokens) { + ZoneRec rec = new ZoneRec(); + try { + rec.gmtOffset = (int) Time.parse(tokens.nextToken()).getTime(); + String token = tokens.nextToken(); + char c = token.charAt(0); + if (c >= '0' && c <= '9') { + rec.directSave = (int) Time.parse(token).getTime(); + } else { + rec.ruleName = token; + } + rec.format = tokens.nextToken(); + if (tokens.hasMoreTokens()) { + rec.hasUntil = true; + rec.untilYear = Integer.parseInt(tokens.nextToken()); + if (tokens.hasMoreTokens()) { + rec.untilMonth = Month.parse(tokens.nextToken()); + } else { + rec.untilMonth = Month.JANUARY; + } + if (tokens.hasMoreTokens()) { + rec.untilDay = RuleDay.parse(tokens.nextToken()); + } else { + rec.untilDay = new RuleDay(1); + } + if (tokens.hasMoreTokens()) { + rec.untilTime = Time.parse(tokens.nextToken()); + } else { + rec.untilTime = Time.parse("0:00"); + } + rec.untilInMillis = rec.getLocalUntilTime(); + } + } catch (Exception e) { + // TODO: error reporting + e.printStackTrace(); + } + return rec; + } + + private static void panic(String msg) { + Main.panic(msg); + } +} diff --git a/jdk/test/sun/util/calendar/zi/Zoneinfo.java b/jdk/test/sun/util/calendar/zi/Zoneinfo.java new file mode 100644 index 00000000000..93242eb4013 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/Zoneinfo.java @@ -0,0 +1,567 @@ +/* + * Copyright (c) 2000, 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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.BufferedReader; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * Zoneinfo provides javazic compiler front-end functionality. + * @since 1.4 + */ +class Zoneinfo { + + private static final int minYear = 1900; + private static final int maxYear = 2037; + private static final long minTime = Time.getLocalTime(minYear, Month.JANUARY, 1, 0); + private static int startYear = minYear; + private static int endYear = maxYear; + + /** + * True if javazic should generate a list of SimpleTimeZone + * instances for the SimpleTimeZone-based time zone support. + */ + static boolean isYearForTimeZoneDataSpecified = false; + + /** + * Zone name to Zone mappings + */ + private Map zones; + + /** + * Rule name to Rule mappings + */ + private Map rules; + + /** + * Alias name to real name mappings + */ + private Map aliases; + + /** + * Constracts a Zoneinfo. + */ + Zoneinfo() { + zones = new HashMap(); + rules = new HashMap(); + aliases = new HashMap(); + } + + /** + * Adds the given zone to the list of Zones. + * @param zone Zone to be added to the list. + */ + void add(Zone zone) { + String name = zone.getName(); + zones.put(name, zone); + } + + /** + * Adds the given rule to the list of Rules. + * @param rule Rule to be added to the list. + */ + void add(Rule rule) { + String name = rule.getName(); + rules.put(name, rule); + } + + /** + * Puts the specifid name pair to the alias table. + * @param name1 an alias time zone name + * @param name2 the real time zone of the alias name + */ + void putAlias(String name1, String name2) { + aliases.put(name1, name2); + } + + /** + * Sets the given year for SimpleTimeZone list output. + * This method is called when the -S option is specified. + * @param year the year for which SimpleTimeZone list should be generated + */ + static void setYear(int year) { + setStartYear(year); + setEndYear(year); + isYearForTimeZoneDataSpecified = true; + } + + /** + * Sets the start year. + * @param year the start year value + * @throws IllegalArgumentException if the specified year value is + * smaller than the minimum year or greater than the end year. + */ + static void setStartYear(int year) { + if (year < minYear || year > endYear) { + throw new IllegalArgumentException("invalid start year specified: " + year); + } + startYear = year; + } + + /** + * @return the start year value + */ + static int getStartYear() { + return startYear; + } + + /** + * Sets the end year. + * @param year the end year value + * @throws IllegalArgumentException if the specified year value is + * smaller than the start year or greater than the maximum year. + */ + static void setEndYear(int year) { + if (year < startYear || year > maxYear) { + throw new IllegalArgumentException(); + } + endYear = year; + } + + /** + * @return the end year value + */ + static int getEndYear() { + return endYear; + } + + /** + * @return the minimum year value + */ + static int getMinYear() { + return minYear; + } + + /** + * @return the maximum year value + */ + static int getMaxYear() { + return maxYear; + } + + /** + * @return the alias table + */ + Map getAliases() { + return aliases; + } + + /** + * @return the Zone list + */ + Map getZones() { + return zones; + } + + /** + * @return a Zone specified by name. + * @param name a zone name + */ + Zone getZone(String name) { + return zones.get(name); + } + + /** + * @return a Rule specified by name. + * @param name a rule name + */ + Rule getRule(String name) { + return rules.get(name); + } + + private static String line; + + private static int lineNum; + + /** + * Parses the specified time zone data file and creates a Zoneinfo + * that has all Rules, Zones and Links (aliases) information. + * @param fname the time zone data file name + * @return a Zoneinfo object + */ + static Zoneinfo parse(String fname) { + BufferedReader in = null; + try { + FileReader fr = new FileReader(fname); + in = new BufferedReader(fr); + } catch (FileNotFoundException e) { + panic("can't open file: "+fname); + } + Zoneinfo zi = new Zoneinfo(); + boolean continued = false; + Zone zone = null; + String l; + lineNum = 0; + + try { + while ((line = in.readLine()) != null) { + lineNum++; + // skip blank and comment lines + if (line.length() == 0 || line.charAt(0) == '#') { + continue; + } + + // trim trailing comments + int rindex = line.lastIndexOf('#'); + if (rindex != -1) { + // take the data part of the line + l = line.substring(0, rindex); + } else { + l = line; + } + + StringTokenizer tokens = new StringTokenizer(l); + if (!tokens.hasMoreTokens()) { + continue; + } + String token = tokens.nextToken(); + + if (continued || "Zone".equals(token)) { + if (zone == null) { + if (!tokens.hasMoreTokens()) { + panic("syntax error: zone no more token"); + } + token = tokens.nextToken(); + // if the zone name is in "GMT+hh" or "GMT-hh" + // format, ignore it due to spec conflict. + if (token.startsWith("GMT+") || token.startsWith("GMT-")) { + continue; + } + zone = new Zone(token); + } else { + // no way to push the current token back... + tokens = new StringTokenizer(l); + } + + ZoneRec zrec = ZoneRec.parse(tokens); + zrec.setLine(line); + zone.add(zrec); + if ((continued = zrec.hasUntil()) == false) { + if (Zone.isTargetZone(zone.getName())) { + // zone.resolve(zi); + zi.add(zone); + } + zone = null; + } + } else if ("Rule".equals(token)) { + if (!tokens.hasMoreTokens()) { + panic("syntax error: rule no more token"); + } + token = tokens.nextToken(); + Rule rule = zi.getRule(token); + if (rule == null) { + rule = new Rule(token); + zi.add(rule); + } + RuleRec rrec = RuleRec.parse(tokens); + rrec.setLine(line); + rule.add(rrec); + } else if ("Link".equals(token)) { + // Link + try { + String name1 = tokens.nextToken(); + String name2 = tokens.nextToken(); + + // if the zone name is in "GMT+hh" or "GMT-hh" + // format, ignore it due to spec conflict with + // custom time zones. Also, ignore "ROC" for + // PC-ness. + if (name2.startsWith("GMT+") || name2.startsWith("GMT-") + || "ROC".equals(name2)) { + continue; + } + zi.putAlias(name2, name1); + } catch (Exception e) { + panic("syntax error: no more token for Link"); + } + } + } + in.close(); + } catch (IOException ex) { + panic("IO error: " + ex.getMessage()); + } + + return zi; + } + + /** + * Interprets a zone and constructs a Timezone object that + * contains enough information on GMT offsets and DST schedules to + * generate a zone info database. + * + * @param zoneName the zone name for which a Timezone object is + * constructed. + * + * @return a Timezone object that contains all GMT offsets and DST + * rules information. + */ + Timezone phase2(String zoneName) { + Timezone tz = new Timezone(zoneName); + Zone zone = getZone(zoneName); + zone.resolve(this); + + // TODO: merge phase2's for the regular and SimpleTimeZone ones. + if (isYearForTimeZoneDataSpecified) { + ZoneRec zrec = zone.get(zone.size()-1); + tz.setLastZoneRec(zrec); + tz.setRawOffset(zrec.getGmtOffset()); + if (zrec.hasRuleReference()) { + /* + * This part assumes that the specified year is covered by + * the rules referred to by the last zone record. + */ + List rrecs = zrec.getRuleRef().getRules(startYear); + + if (rrecs.size() == 2) { + // make sure that one is a start rule and the other is + // an end rule. + RuleRec r0 = rrecs.get(0); + RuleRec r1 = rrecs.get(1); + if (r0.getSave() == 0 && r1.getSave() > 0) { + rrecs.set(0, r1); + rrecs.set(1, r0); + } else if (!(r0.getSave() > 0 && r1.getSave() == 0)) { + rrecs = null; + Main.error(zoneName + ": rules for " + startYear + " not found."); + } + } else { + rrecs = null; + } + if (rrecs != null) { + tz.setLastRules(rrecs); + } + } + return tz; + } + + int gmtOffset; + int year = minYear; + int fromYear = year; + long fromTime = Time.getLocalTime(startYear, + Month.JANUARY, + 1, 0); + + // take the index 0 for the GMT offset of the last zone record + ZoneRec zrec = zone.get(zone.size()-1); + tz.getOffsetIndex(zrec.getGmtOffset()); + + int currentSave = 0; + boolean usedZone; + for (int zindex = 0; zindex < zone.size(); zindex++) { + zrec = zone.get(zindex); + usedZone = false; + gmtOffset = zrec.getGmtOffset(); + int stdOffset = zrec.getDirectSave(); + + // If this is the last zone record, take the last rule info. + if (!zrec.hasUntil()) { + tz.setRawOffset(gmtOffset, fromTime); + if (zrec.hasRuleReference()) { + tz.setLastRules(zrec.getRuleRef().getLastRules()); + } else if (stdOffset != 0) { + // in case the last rule is all year round DST-only + // (Asia/Amman once announced this rule.) + tz.setLastDSTSaving(stdOffset); + } + } + if (!zrec.hasRuleReference()) { + if (!zrec.hasUntil() || zrec.getUntilTime(stdOffset) >= fromTime) { + tz.addTransition(fromTime, + tz.getOffsetIndex(gmtOffset+stdOffset), + tz.getDstOffsetIndex(stdOffset)); + usedZone = true; + } + currentSave = stdOffset; + // optimization in case the last rule is fixed. + if (!zrec.hasUntil()) { + if (tz.getNTransitions() > 0) { + if (stdOffset == 0) { + tz.setDSTType(Timezone.X_DST); + } else { + tz.setDSTType(Timezone.LAST_DST); + } + long time = Time.getLocalTime(maxYear, + Month.JANUARY, 1, 0); + time -= zrec.getGmtOffset(); + tz.addTransition(time, + tz.getOffsetIndex(gmtOffset+stdOffset), + tz.getDstOffsetIndex(stdOffset)); + tz.addUsedRec(zrec); + } else { + tz.setDSTType(Timezone.NO_DST); + } + break; + } + } else { + Rule rule = zrec.getRuleRef(); + boolean fromTimeUsed = false; + currentSave = 0; + year_loop: + for (year = getMinYear(); year <= endYear; year++) { + if (zrec.hasUntil() && year > zrec.getUntilYear()) { + break; + } + List rules = rule.getRules(year); + if (rules.size() > 0) { + for (int i = 0; i < rules.size(); i++) { + RuleRec rrec = rules.get(i); + long transition = rrec.getTransitionTime(year, + gmtOffset, + currentSave); + if (zrec.hasUntil()) { + if (transition >= zrec.getUntilTime(currentSave)) { + break year_loop; + } + } + + if (fromTimeUsed == false) { + if (fromTime <= transition) { + fromTimeUsed = true; + + if (fromTime != minTime) { + int prevsave; + + ZoneRec prevzrec = zone.get(zindex - 1); + + // See if until time in the previous + // ZoneRec is the same thing as the + // local time in the next rule. + // (examples are Asia/Ashkhabad in 1991, + // Europe/Riga in 1989) + + if (i > 0) { + prevsave = rules.get(i-1).getSave(); + } else { + List prevrules = rule.getRules(year-1); + + if (prevrules.size() > 0) { + prevsave = prevrules.get(prevrules.size()-1).getSave(); + } else { + prevsave = 0; + } + } + + if (rrec.isSameTransition(prevzrec, prevsave, gmtOffset)) { + currentSave = rrec.getSave(); + tz.addTransition(fromTime, + tz.getOffsetIndex(gmtOffset+currentSave), + tz.getDstOffsetIndex(currentSave)); + tz.addUsedRec(rrec); + usedZone = true; + continue; + } + if (!prevzrec.hasRuleReference() + || rule != prevzrec.getRuleRef() + || (rule == prevzrec.getRuleRef() + && gmtOffset != prevzrec.getGmtOffset())) { + int save = (fromTime == transition) ? rrec.getSave() : currentSave; + tz.addTransition(fromTime, + tz.getOffsetIndex(gmtOffset+save), + tz.getDstOffsetIndex(save)); + tz.addUsedRec(rrec); + usedZone = true; + } + } else { // fromTime == minTime + int save = rrec.getSave(); + tz.addTransition(minTime, + tz.getOffsetIndex(gmtOffset), + tz.getDstOffsetIndex(0)); + + tz.addTransition(transition, + tz.getOffsetIndex(gmtOffset+save), + tz.getDstOffsetIndex(save)); + + tz.addUsedRec(rrec); + usedZone = true; + } + } else if (year == fromYear && i == rules.size()-1) { + int save = rrec.getSave(); + tz.addTransition(fromTime, + tz.getOffsetIndex(gmtOffset+save), + tz.getDstOffsetIndex(save)); + } + } + + currentSave = rrec.getSave(); + if (fromTime < transition) { + tz.addTransition(transition, + tz.getOffsetIndex(gmtOffset+currentSave), + tz.getDstOffsetIndex(currentSave)); + tz.addUsedRec(rrec); + usedZone = true; + } + } + } else { + if (year == fromYear) { + tz.addTransition(fromTime, + tz.getOffsetIndex(gmtOffset+currentSave), + tz.getDstOffsetIndex(currentSave)); + fromTimeUsed = true; + } + if (year == endYear && !zrec.hasUntil()) { + if (tz.getNTransitions() > 0) { + // Assume that this Zone stopped DST + tz.setDSTType(Timezone.X_DST); + long time = Time.getLocalTime(maxYear, Month.JANUARY, + 1, 0); + time -= zrec.getGmtOffset(); + tz.addTransition(time, + tz.getOffsetIndex(gmtOffset), + tz.getDstOffsetIndex(0)); + usedZone = true; + } else { + tz.setDSTType(Timezone.NO_DST); + } + } + } + } + } + if (usedZone) { + tz.addUsedRec(zrec); + } + if (zrec.hasUntil() && zrec.getUntilTime(currentSave) > fromTime) { + fromTime = zrec.getUntilTime(currentSave); + fromYear = zrec.getUntilYear(); + year = zrec.getUntilYear(); + } + } + + if (tz.getDSTType() == Timezone.UNDEF_DST) { + tz.setDSTType(Timezone.DST); + } + tz.optimize(); + tz.checksum(); + return tz; + } + + private static void panic(String msg) { + Main.panic(msg); + } +} diff --git a/jdk/test/sun/util/calendar/zi/tzdata/VERSION b/jdk/test/sun/util/calendar/zi/tzdata/VERSION new file mode 100644 index 00000000000..85db871ccf3 --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/tzdata/VERSION @@ -0,0 +1,24 @@ +# +# 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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. +# +tzdata2012i diff --git a/jdk/test/sun/util/calendar/zi/tzdata/africa b/jdk/test/sun/util/calendar/zi/tzdata/africa new file mode 100644 index 00000000000..7db9b3d269d --- /dev/null +++ b/jdk/test/sun/util/calendar/zi/tzdata/africa @@ -0,0 +1,1186 @@ +# +# 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# This data is by no means authoritative; if you think you know better,
    +# go ahead and edit the file (and please send any changes to
    +# tz@elsie.nci.nih.gov for general use in the future).
    +
    +# From Paul Eggert (2006-03-22):
    +#
    +# A good source for time zone historical data outside the U.S. is
    +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
    +# San Diego: ACS Publications, Inc. (2003).
    +#
    +# Gwillim Law writes that a good source
    +# for recent time zone data is the International Air Transport
    +# Association's Standard Schedules Information Manual (IATA SSIM),
    +# published semiannually.  Law sent in several helpful summaries
    +# of the IATA's data after 1990.
    +#
    +# Except where otherwise noted, Shanks & Pottenger is the source for
    +# entries through 1990, and IATA SSIM is the source for entries afterwards.
    +#
    +# Another source occasionally used is Edward W. Whitman, World Time Differences,
    +# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
    +# I found in the UCLA library.
    +#
    +# A reliable and entertaining source about time zones is
    +# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
    +#
    +# Previous editions of this database used WAT, CAT, SAT, and EAT
    +# for +0:00 through +3:00, respectively,
    +# but Mark R V Murray reports that
    +# `SAST' is the official abbreviation for +2:00 in the country of South Africa,
    +# `CAT' is commonly used for +2:00 in countries north of South Africa, and
    +# `WAT' is probably the best name for +1:00, as the common phrase for
    +# the area that includes Nigeria is ``West Africa''.
    +# He has heard of ``Western Sahara Time'' for +0:00 but can find no reference.
    +#
    +# To make things confusing, `WAT' seems to have been used for -1:00 long ago;
    +# I'd guess that this was because people needed _some_ name for -1:00,
    +# and at the time, far west Africa was the only major land area in -1:00.
    +# This usage is now obsolete, as the last use of -1:00 on the African
    +# mainland seems to have been 1976 in Western Sahara.
    +#
    +# To summarize, the following abbreviations seem to have some currency:
    +#	-1:00	WAT	West Africa Time (no longer used)
    +#	 0:00	GMT	Greenwich Mean Time
    +#	 2:00	CAT	Central Africa Time
    +#	 2:00	SAST	South Africa Standard Time
    +# and Murray suggests the following abbreviation:
    +#	 1:00	WAT	West Africa Time
    +# I realize that this leads to `WAT' being used for both -1:00 and 1:00
    +# for times before 1976, but this is the best I can think of
    +# until we get more information.
    +#
    +# I invented the following abbreviations; corrections are welcome!
    +#	 2:00	WAST	West Africa Summer Time
    +#	 2:30	BEAT	British East Africa Time (no longer used)
    +#	 2:45	BEAUT	British East Africa Unified Time (no longer used)
    +#	 3:00	CAST	Central Africa Summer Time (no longer used)
    +#	 3:00	SAST	South Africa Summer Time (no longer used)
    +#	 3:00	EAT	East Africa Time
    +#	 4:00	EAST	East Africa Summer Time (no longer used)
    +
    +# Algeria
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Algeria	1916	only	-	Jun	14	23:00s	1:00	S
    +Rule	Algeria	1916	1919	-	Oct	Sun>=1	23:00s	0	-
    +Rule	Algeria	1917	only	-	Mar	24	23:00s	1:00	S
    +Rule	Algeria	1918	only	-	Mar	 9	23:00s	1:00	S
    +Rule	Algeria	1919	only	-	Mar	 1	23:00s	1:00	S
    +Rule	Algeria	1920	only	-	Feb	14	23:00s	1:00	S
    +Rule	Algeria	1920	only	-	Oct	23	23:00s	0	-
    +Rule	Algeria	1921	only	-	Mar	14	23:00s	1:00	S
    +Rule	Algeria	1921	only	-	Jun	21	23:00s	0	-
    +Rule	Algeria	1939	only	-	Sep	11	23:00s	1:00	S
    +Rule	Algeria	1939	only	-	Nov	19	 1:00	0	-
    +Rule	Algeria	1944	1945	-	Apr	Mon>=1	 2:00	1:00	S
    +Rule	Algeria	1944	only	-	Oct	 8	 2:00	0	-
    +Rule	Algeria	1945	only	-	Sep	16	 1:00	0	-
    +Rule	Algeria	1971	only	-	Apr	25	23:00s	1:00	S
    +Rule	Algeria	1971	only	-	Sep	26	23:00s	0	-
    +Rule	Algeria	1977	only	-	May	 6	 0:00	1:00	S
    +Rule	Algeria	1977	only	-	Oct	21	 0:00	0	-
    +Rule	Algeria	1978	only	-	Mar	24	 1:00	1:00	S
    +Rule	Algeria	1978	only	-	Sep	22	 3:00	0	-
    +Rule	Algeria	1980	only	-	Apr	25	 0:00	1:00	S
    +Rule	Algeria	1980	only	-	Oct	31	 2:00	0	-
    +# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
    +# more precise 0:09:21.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Algiers	0:12:12 -	LMT	1891 Mar 15 0:01
    +			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
    +			0:00	Algeria	WE%sT	1940 Feb 25 2:00
    +			1:00	Algeria	CE%sT	1946 Oct  7
    +			0:00	-	WET	1956 Jan 29
    +			1:00	-	CET	1963 Apr 14
    +			0:00	Algeria	WE%sT	1977 Oct 21
    +			1:00	Algeria	CE%sT	1979 Oct 26
    +			0:00	Algeria	WE%sT	1981 May
    +			1:00	-	CET
    +
    +# Angola
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Luanda	0:52:56	-	LMT	1892
    +			0:52:04	-	AOT	1911 May 26 # Angola Time
    +			1:00	-	WAT
    +
    +# Benin
    +# Whitman says they switched to 1:00 in 1946, not 1934;
    +# go with Shanks & Pottenger.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Africa/Porto-Novo	0:10:28	-	LMT	1912
    +			0:00	-	GMT	1934 Feb 26
    +			1:00	-	WAT
    +
    +# Botswana
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Gaborone	1:43:40 -	LMT	1885
    +			2:00	-	CAT	1943 Sep 19 2:00
    +			2:00	1:00	CAST	1944 Mar 19 2:00
    +			2:00	-	CAT
    +
    +# Burkina Faso
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Africa/Ouagadougou	-0:06:04 -	LMT	1912
    +			 0:00	-	GMT
    +
    +# Burundi
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Africa/Bujumbura	1:57:28	-	LMT	1890
    +			2:00	-	CAT
    +
    +# Cameroon
    +# Whitman says they switched to 1:00 in 1920; go with Shanks & Pottenger.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Douala	0:38:48	-	LMT	1912
    +			1:00	-	WAT
    +
    +# Cape Verde
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Atlantic/Cape_Verde -1:34:04 -	LMT	1907			# Praia
    +			-2:00	-	CVT	1942 Sep
    +			-2:00	1:00	CVST	1945 Oct 15
    +			-2:00	-	CVT	1975 Nov 25 2:00
    +			-1:00	-	CVT
    +
    +# Central African Republic
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Bangui	1:14:20	-	LMT	1912
    +			1:00	-	WAT
    +
    +# Chad
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Ndjamena	1:00:12 -	LMT	1912
    +			1:00	-	WAT	1979 Oct 14
    +			1:00	1:00	WAST	1980 Mar  8
    +			1:00	-	WAT
    +
    +# Comoros
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Indian/Comoro	2:53:04 -	LMT	1911 Jul   # Moroni, Gran Comoro
    +			3:00	-	EAT
    +
    +# Democratic Republic of Congo
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Africa/Kinshasa	1:01:12 -	LMT	1897 Nov 9
    +			1:00	-	WAT
    +Zone Africa/Lubumbashi	1:49:52 -	LMT	1897 Nov 9
    +			2:00	-	CAT
    +
    +# Republic of the Congo
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Africa/Brazzaville	1:01:08 -	LMT	1912
    +			1:00	-	WAT
    +
    +# Cote D'Ivoire
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Abidjan	-0:16:08 -	LMT	1912
    +			 0:00	-	GMT
    +
    +# Djibouti
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Djibouti	2:52:36 -	LMT	1911 Jul
    +			3:00	-	EAT
    +
    +###############################################################################
    +
    +# Egypt
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Egypt	1940	only	-	Jul	15	0:00	1:00	S
    +Rule	Egypt	1940	only	-	Oct	 1	0:00	0	-
    +Rule	Egypt	1941	only	-	Apr	15	0:00	1:00	S
    +Rule	Egypt	1941	only	-	Sep	16	0:00	0	-
    +Rule	Egypt	1942	1944	-	Apr	 1	0:00	1:00	S
    +Rule	Egypt	1942	only	-	Oct	27	0:00	0	-
    +Rule	Egypt	1943	1945	-	Nov	 1	0:00	0	-
    +Rule	Egypt	1945	only	-	Apr	16	0:00	1:00	S
    +Rule	Egypt	1957	only	-	May	10	0:00	1:00	S
    +Rule	Egypt	1957	1958	-	Oct	 1	0:00	0	-
    +Rule	Egypt	1958	only	-	May	 1	0:00	1:00	S
    +Rule	Egypt	1959	1981	-	May	 1	1:00	1:00	S
    +Rule	Egypt	1959	1965	-	Sep	30	3:00	0	-
    +Rule	Egypt	1966	1994	-	Oct	 1	3:00	0	-
    +Rule	Egypt	1982	only	-	Jul	25	1:00	1:00	S
    +Rule	Egypt	1983	only	-	Jul	12	1:00	1:00	S
    +Rule	Egypt	1984	1988	-	May	 1	1:00	1:00	S
    +Rule	Egypt	1989	only	-	May	 6	1:00	1:00	S
    +Rule	Egypt	1990	1994	-	May	 1	1:00	1:00	S
    +# IATA (after 1990) says transitions are at 0:00.
    +# Go with IATA starting in 1995, except correct 1995 entry from 09-30 to 09-29.
    +
    +# From Alexander Krivenyshev (2011-04-20):
    +# "...Egypt's interim cabinet decided on Wednesday to cancel daylight
    +# saving time after a poll posted on its website showed the majority of
    +# Egyptians would approve the cancellation."
    +#
    +# Egypt to cancel daylight saving time
    +# 
    +# http://www.almasryalyoum.com/en/node/407168
    +# 
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_egypt04.html
    +# 
    +Rule	Egypt	1995	2010	-	Apr	lastFri	 0:00s	1:00	S
    +Rule	Egypt	1995	2005	-	Sep	lastThu	23:00s	0	-
    +# From Steffen Thorsen (2006-09-19):
    +# The Egyptian Gazette, issue 41,090 (2006-09-18), page 1, reports:
    +# Egypt will turn back clocks by one hour at the midnight of Thursday
    +# after observing the daylight saving time since May.
    +# http://news.gom.com.eg/gazette/pdf/2006/09/18/01.pdf
    +Rule	Egypt	2006	only	-	Sep	21	23:00s	0	-
    +# From Dirk Losch (2007-08-14):
    +# I received a mail from an airline which says that the daylight
    +# saving time in Egypt will end in the night of 2007-09-06 to 2007-09-07.
    +# From Jesper Norgaard Welen (2007-08-15): [The following agree:]
    +# http://www.nentjes.info/Bill/bill5.htm
    +# http://www.timeanddate.com/worldclock/city.html?n=53
    +# From Steffen Thorsen (2007-09-04): The official information...:
    +# http://www.sis.gov.eg/En/EgyptOnline/Miscellaneous/000002/0207000000000000001580.htm
    +Rule	Egypt	2007	only	-	Sep	Thu>=1	23:00s	0	-
    +# From Abdelrahman Hassan (2007-09-06):
    +# Due to the Hijri (lunar Islamic calendar) year being 11 days shorter
    +# than the year of the Gregorian calendar, Ramadan shifts earlier each
    +# year. This year it will be observed September 13 (September is quite
    +# hot in Egypt), and the idea is to make fasting easier for workers by
    +# shifting business hours one hour out of daytime heat. Consequently,
    +# unless discontinued, next DST may end Thursday 28 August 2008.
    +# From Paul Eggert (2007-08-17):
    +# For lack of better info, assume the new rule is last Thursday in August.
    +
    +# From Petr Machata (2009-04-06):
    +# The following appeared in Red Hat bugzilla[1] (edited):
    +#
    +# > $ zdump -v /usr/share/zoneinfo/Africa/Cairo | grep 2009
    +# > /usr/share/zoneinfo/Africa/Cairo  Thu Apr 23 21:59:59 2009 UTC = Thu =
    +# Apr 23
    +# > 23:59:59 2009 EET isdst=0 gmtoff=7200
    +# > /usr/share/zoneinfo/Africa/Cairo  Thu Apr 23 22:00:00 2009 UTC = Fri =
    +# Apr 24
    +# > 01:00:00 2009 EEST isdst=1 gmtoff=10800
    +# > /usr/share/zoneinfo/Africa/Cairo  Thu Aug 27 20:59:59 2009 UTC = Thu =
    +# Aug 27
    +# > 23:59:59 2009 EEST isdst=1 gmtoff=10800
    +# > /usr/share/zoneinfo/Africa/Cairo  Thu Aug 27 21:00:00 2009 UTC = Thu =
    +# Aug 27
    +# > 23:00:00 2009 EET isdst=0 gmtoff=7200
    +#
    +# > end date should be Thu Sep 24 2009 (Last Thursday in September at 23:59=
    +# :59)
    +# > http://support.microsoft.com/kb/958729/
    +#
    +# timeanddate[2] and another site I've found[3] also support that.
    +#
    +# [1] 
    +# https://bugzilla.redhat.com/show_bug.cgi?id=492263
    +# 
    +# [2] 
    +# http://www.timeanddate.com/worldclock/clockchange.html?n=53
    +# 
    +# [3] 
    +# http://wwp.greenwichmeantime.com/time-zone/africa/egypt/
    +# 
    +
    +# From Arthur David Olson (2009-04-20):
    +# In 2009 (and for the next several years), Ramadan ends before the fourth
    +# Thursday in September; Egypt is expected to revert to the last Thursday
    +# in September.
    +
    +# From Steffen Thorsen (2009-08-11):
    +# We have been able to confirm the August change with the Egyptian Cabinet
    +# Information and Decision Support Center:
    +# 
    +# http://www.timeanddate.com/news/time/egypt-dst-ends-2009.html
    +# 
    +#
    +# The Middle East News Agency
    +# 
    +# http://www.mena.org.eg/index.aspx
    +# 
    +# also reports "Egypt starts winter time on August 21"
    +# today in article numbered "71, 11/08/2009 12:25 GMT."
    +# Only the title above is available without a subscription to their service,
    +# and can be found by searching for "winter" in their search engine
    +# (at least today).
    +
    +# From Alexander Krivenyshev (2010-07-20):
    +# According to News from Egypt -  Al-Masry Al-Youm Egypt's cabinet has
    +# decided that Daylight Saving Time will not be used in Egypt during
    +# Ramadan.
    +#
    +# Arabic translation:
    +# "Clocks to go back during Ramadan--and then forward again"
    +# 
    +# http://www.almasryalyoum.com/en/news/clocks-go-back-during-ramadan-and-then-forward-again
    +# 
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_egypt02.html
    +# 
    +
    +Rule	Egypt	2008	only	-	Aug	lastThu	23:00s	0	-
    +Rule	Egypt	2009	only	-	Aug	20	23:00s	0	-
    +Rule	Egypt	2010	only	-	Aug	11	0:00	0	-
    +Rule	Egypt	2010	only	-	Sep	10	0:00	1:00	S
    +Rule	Egypt	2010	only	-	Sep	lastThu	23:00s	0	-
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Cairo	2:05:00 -	LMT	1900 Oct
    +			2:00	Egypt	EE%sT
    +
    +# Equatorial Guinea
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Malabo	0:35:08 -	LMT	1912
    +			0:00	-	GMT	1963 Dec 15
    +			1:00	-	WAT
    +
    +# Eritrea
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Asmara	2:35:32 -	LMT	1870
    +			2:35:32	-	AMT	1890	      # Asmara Mean Time
    +			2:35:20	-	ADMT	1936 May 5    # Adis Dera MT
    +			3:00	-	EAT
    +
    +# Ethiopia
    +# From Paul Eggert (2006-03-22):
    +# Shanks & Pottenger write that Ethiopia had six narrowly-spaced time zones
    +# between 1870 and 1890, and that they merged to 38E50 (2:35:20) in 1890.
    +# We'll guess that 38E50 is for Adis Dera.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Africa/Addis_Ababa	2:34:48 -	LMT	1870
    +			2:35:20	-	ADMT	1936 May 5    # Adis Dera MT
    +			3:00	-	EAT
    +
    +# Gabon
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Africa/Libreville	0:37:48 -	LMT	1912
    +			1:00	-	WAT
    +
    +# Gambia
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Banjul	-1:06:36 -	LMT	1912
    +			-1:06:36 -	BMT	1935	# Banjul Mean Time
    +			-1:00	-	WAT	1964
    +			 0:00	-	GMT
    +
    +# Ghana
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +# Whitman says DST was observed from 1931 to ``the present'';
    +# go with Shanks & Pottenger.
    +Rule	Ghana	1936	1942	-	Sep	 1	0:00	0:20	GHST
    +Rule	Ghana	1936	1942	-	Dec	31	0:00	0	GMT
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Accra	-0:00:52 -	LMT	1918
    +			 0:00	Ghana	%s
    +
    +# Guinea
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Conakry	-0:54:52 -	LMT	1912
    +			 0:00	-	GMT	1934 Feb 26
    +			-1:00	-	WAT	1960
    +			 0:00	-	GMT
    +
    +# Guinea-Bissau
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Bissau	-1:02:20 -	LMT	1911 May 26
    +			-1:00	-	WAT	1975
    +			 0:00	-	GMT
    +
    +# Kenya
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Nairobi	2:27:16	-	LMT	1928 Jul
    +			3:00	-	EAT	1930
    +			2:30	-	BEAT	1940
    +			2:45	-	BEAUT	1960
    +			3:00	-	EAT
    +
    +# Lesotho
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Maseru	1:50:00 -	LMT	1903 Mar
    +			2:00	-	SAST	1943 Sep 19 2:00
    +			2:00	1:00	SAST	1944 Mar 19 2:00
    +			2:00	-	SAST
    +
    +# Liberia
    +# From Paul Eggert (2006-03-22):
    +# In 1972 Liberia was the last country to switch
    +# from a UTC offset that was not a multiple of 15 or 20 minutes.
    +# Howse reports that it was in honor of their president's birthday.
    +# Shank & Pottenger report the date as May 1, whereas Howse reports Jan;
    +# go with Shanks & Pottenger.
    +# For Liberia before 1972, Shanks & Pottenger report -0:44, whereas Howse and
    +# Whitman each report -0:44:30; go with the more precise figure.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Monrovia	-0:43:08 -	LMT	1882
    +			-0:43:08 -	MMT	1919 Mar # Monrovia Mean Time
    +			-0:44:30 -	LRT	1972 May # Liberia Time
    +			 0:00	-	GMT
    +
    +###############################################################################
    +
    +# Libya
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Libya	1951	only	-	Oct	14	2:00	1:00	S
    +Rule	Libya	1952	only	-	Jan	 1	0:00	0	-
    +Rule	Libya	1953	only	-	Oct	 9	2:00	1:00	S
    +Rule	Libya	1954	only	-	Jan	 1	0:00	0	-
    +Rule	Libya	1955	only	-	Sep	30	0:00	1:00	S
    +Rule	Libya	1956	only	-	Jan	 1	0:00	0	-
    +Rule	Libya	1982	1984	-	Apr	 1	0:00	1:00	S
    +Rule	Libya	1982	1985	-	Oct	 1	0:00	0	-
    +Rule	Libya	1985	only	-	Apr	 6	0:00	1:00	S
    +Rule	Libya	1986	only	-	Apr	 4	0:00	1:00	S
    +Rule	Libya	1986	only	-	Oct	 3	0:00	0	-
    +Rule	Libya	1987	1989	-	Apr	 1	0:00	1:00	S
    +Rule	Libya	1987	1989	-	Oct	 1	0:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Tripoli	0:52:44 -	LMT	1920
    +			1:00	Libya	CE%sT	1959
    +			2:00	-	EET	1982
    +			1:00	Libya	CE%sT	1990 May  4
    +# The following entries are from Shanks & Pottenger;
    +# the IATA SSIM data contain some obvious errors.
    +			2:00	-	EET	1996 Sep 30
    +			1:00	-	CET	1997 Apr  4
    +			1:00	1:00	CEST	1997 Oct  4
    +			2:00	-	EET
    +
    +# Madagascar
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Indian/Antananarivo 3:10:04 -	LMT	1911 Jul
    +			3:00	-	EAT	1954 Feb 27 23:00s
    +			3:00	1:00	EAST	1954 May 29 23:00s
    +			3:00	-	EAT
    +
    +# Malawi
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Blantyre	2:20:00 -	LMT	1903 Mar
    +			2:00	-	CAT
    +
    +# Mali
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Bamako	-0:32:00 -	LMT	1912
    +			 0:00	-	GMT	1934 Feb 26
    +			-1:00	-	WAT	1960 Jun 20
    +			 0:00	-	GMT
    +
    +# Mauritania
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Africa/Nouakchott	-1:03:48 -	LMT	1912
    +			 0:00	-	GMT	1934 Feb 26
    +			-1:00	-	WAT	1960 Nov 28
    +			 0:00	-	GMT
    +
    +# Mauritius
    +
    +# From Steffen Thorsen (2008-06-25):
    +# Mauritius plans to observe DST from 2008-11-01 to 2009-03-31 on a trial
    +# basis....
    +# It seems that Mauritius observed daylight saving time from 1982-10-10 to
    +# 1983-03-20 as well, but that was not successful....
    +# http://www.timeanddate.com/news/time/mauritius-daylight-saving-time.html
    +
    +# From Alex Krivenyshev (2008-06-25):
    +# http://economicdevelopment.gov.mu/portal/site/Mainhomepage/menuitem.a42b24128104d9845dabddd154508a0c/?content_id=0a7cee8b5d69a110VgnVCM1000000a04a8c0RCRD
    +
    +# From Arthur David Olson (2008-06-30):
    +# The www.timeanddate.com article cited by Steffen Thorsen notes that "A
    +# final decision has yet to be made on the times that daylight saving
    +# would begin and end on these dates." As a place holder, use midnight.
    +
    +# From Paul Eggert (2008-06-30):
    +# Follow Thorsen on DST in 1982/1983, instead of Shanks & Pottenger.
    +
    +# From Steffen Thorsen (2008-07-10):
    +# According to
    +# 
    +# http://www.lexpress.mu/display_article.php?news_id=111216
    +# 
    +# (in French), Mauritius will start and end their DST a few days earlier
    +# than previously announced (2008-11-01 to 2009-03-31).  The new start
    +# date is 2008-10-26 at 02:00 and the new end date is 2009-03-27 (no time
    +# given, but it is probably at either 2 or 3 wall clock time).
    +#
    +# A little strange though, since the article says that they moved the date
    +# to align itself with Europe and USA which also change time on that date,
    +# but that means they have not paid attention to what happened in
    +# USA/Canada last year (DST ends first Sunday in November). I also wonder
    +# why that they end on a Friday, instead of aligning with Europe which
    +# changes two days later.
    +
    +# From Alex Krivenyshev (2008-07-11):
    +# Seems that English language article "The revival of daylight saving
    +# time:  Energy conservation?"-# No. 16578 (07/11/2008) was originally
    +# published on Monday, June 30, 2008...
    +#
    +# I guess that article in French "Le gouvernement avance l'introduction
    +# de l'heure d'ete" stating that DST in Mauritius starting on October 26
    +# and ending on March 27, 2009 is the most recent one.
    +# ...
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_mauritius02.html
    +# 
    +
    +# From Riad M. Hossen Ally (2008-08-03):
    +# The Government of Mauritius weblink
    +# 
    +# http://www.gov.mu/portal/site/pmosite/menuitem.4ca0efdee47462e7440a600248a521ca/?content_id=4728ca68b2a5b110VgnVCM1000000a04a8c0RCRD
    +# 
    +# Cabinet Decision of July 18th, 2008 states as follows:
    +#
    +# 4. ...Cabinet has agreed to the introduction into the National Assembly
    +# of the Time Bill which provides for the introduction of summer time in
    +# Mauritius. The summer time period which will be of one hour ahead of
    +# the standard time, will be aligned with that in Europe and the United
    +# States of America. It will start at two o'clock in the morning on the
    +# last Sunday of October and will end at two o'clock in the morning on
    +# the last Sunday of March the following year. The summer time for the
    +# year 2008 - 2009 will, therefore, be effective as from 26 October 2008
    +# and end on 29 March 2009.
    +
    +# From Ed Maste (2008-10-07):
    +# THE TIME BILL (No. XXVII of 2008) Explanatory Memorandum states the
    +# beginning / ending of summer time is 2 o'clock standard time in the
    +# morning of the last Sunday of October / last Sunday of March.
    +# 
    +# http://www.gov.mu/portal/goc/assemblysite/file/bill2708.pdf
    +# 
    +
    +# From Steffen Thorsen (2009-06-05):
    +# According to several sources, Mauritius will not continue to observe
    +# DST the coming summer...
    +#
    +# Some sources, in French:
    +# 
    +# http://www.defimedia.info/news/946/Rashid-Beebeejaun-:-%C2%AB-L%E2%80%99heure-d%E2%80%99%C3%A9t%C3%A9-ne-sera-pas-appliqu%C3%A9e-cette-ann%C3%A9e-%C2%BB
    +# 
    +# 
    +# http://lexpress.mu/Story/3398~Beebeejaun---Les-objectifs-d-%C3%A9conomie-d-%C3%A9nergie-de-l-heure-d-%C3%A9t%C3%A9-ont-%C3%A9t%C3%A9-atteints-
    +# 
    +#
    +# Our wrap-up:
    +# 
    +# http://www.timeanddate.com/news/time/mauritius-dst-will-not-repeat.html
    +# 
    +
    +# From Arthur David Olson (2009-07-11):
    +# The "mauritius-dst-will-not-repeat" wrapup includes this:
    +# "The trial ended on March 29, 2009, when the clocks moved back by one hour
    +# at 2am (or 02:00) local time..."
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule Mauritius	1982	only	-	Oct	10	0:00	1:00	S
    +Rule Mauritius	1983	only	-	Mar	21	0:00	0	-
    +Rule Mauritius	2008	only	-	Oct	lastSun	2:00	1:00	S
    +Rule Mauritius	2009	only	-	Mar	lastSun	2:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Indian/Mauritius	3:50:00 -	LMT	1907		# Port Louis
    +			4:00 Mauritius	MU%sT	# Mauritius Time
    +# Agalega Is, Rodriguez
    +# no information; probably like Indian/Mauritius
    +
    +# Mayotte
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Indian/Mayotte	3:00:56 -	LMT	1911 Jul	# Mamoutzou
    +			3:00	-	EAT
    +
    +# Morocco
    +# See the `europe' file for Spanish Morocco (Africa/Ceuta).
    +
    +# From Alex Krivenyshev (2008-05-09):
    +# Here is an article that Morocco plan to introduce Daylight Saving Time between
    +# 1 June, 2008 and 27 September, 2008.
    +#
    +# "... Morocco is to save energy by adjusting its clock during summer so it will
    +# be one hour ahead of GMT between 1 June and 27 September, according to
    +# Communication Minister and Gov ernment Spokesman, Khalid Naciri...."
    +#
    +# 
    +# http://www.worldtimezone.net/dst_news/dst_news_morocco01.html
    +# 
    +# OR
    +# 
    +# http://en.afrik.com/news11892.html
    +# 
    +
    +# From Alex Krivenyshev (2008-05-09):
    +# The Morocco time change can be confirmed on Morocco web site Maghreb Arabe Presse:
    +# 
    +# http://www.map.ma/eng/sections/box3/morocco_shifts_to_da/view
    +# 
    +#
    +# Morocco shifts to daylight time on June 1st through September 27, Govt.
    +# spokesman.
    +
    +# From Patrice Scattolin (2008-05-09):
    +# According to this article:
    +# 
    +# http://www.avmaroc.com/actualite/heure-dete-comment-a127896.html
    +# 
    +# (and republished here:
    +# 
    +# http://www.actu.ma/heure-dete-comment_i127896_0.html
    +# 
    +# )
    +# the changes occurs at midnight:
    +#
    +# saturday night may 31st at midnight (which in french is to be
    +# intrepreted as the night between saturday and sunday)
    +# sunday night the 28th  at midnight
    +#
    +# Seeing that the 28th is monday, I am guessing that she intends to say
    +# the midnight of the 28th which is the midnight between sunday and
    +# monday, which jives with other sources that say that it's inclusive
    +# june1st to sept 27th.
    +#
    +# The decision was taken by decree *2-08-224 *but I can't find the decree
    +# published on the web.
    +#
    +# It's also confirmed here:
    +# 
    +# http://www.maroc.ma/NR/exeres/FACF141F-D910-44B0-B7FA-6E03733425D1.htm
    +# 
    +# on a government portal as being  between june 1st and sept 27th (not yet
    +# posted in english).
    +#
    +# The following google query will generate many relevant hits:
    +# 
    +# http://www.google.com/search?hl=en&q=Conseil+de+gouvernement+maroc+heure+avance&btnG=Search
    +# 
    +
    +# From Alex Krivenyshev (2008-05-09):
    +# Is Western Sahara (part which administrated by Morocco) going to follow
    +# Morocco DST changes?  Any information?  What about other part of
    +# Western Sahara - under administration of POLISARIO Front (also named
    +# SADR Saharawi Arab Democratic Republic)?
    +
    +# From Arthur David Olson (2008-05-09):
    +# XXX--guess that it is only Morocco for now; guess only 2008 for now.
    +
    +# From Steffen Thorsen (2008-08-27):
    +# Morocco will change the clocks back on the midnight between August 31
    +# and September 1. They originally planned to observe DST to near the end
    +# of September:
    +#
    +# One article about it (in French):
    +# 
    +# http://www.menara.ma/fr/Actualites/Maroc/Societe/ci.retour_a_l_heure_gmt_a_partir_du_dimanche_31_aout_a_minuit_officiel_.default
    +# 
    +#
    +# We have some further details posted here:
    +# 
    +# http://www.timeanddate.com/news/time/morocco-ends-dst-early-2008.html
    +# 
    +
    +# From Steffen Thorsen (2009-03-17):
    +# Morocco will observe DST from 2009-06-01 00:00 to 2009-08-21 00:00 according
    +# to many sources, such as
    +# 
    +# http://news.marweb.com/morocco/entertainment/morocco-daylight-saving.html
    +# 
    +# 
    +# http://www.medi1sat.ma/fr/depeche.aspx?idp=2312
    +# 
    +# (French)
    +#
    +# Our summary:
    +# 
    +# http://www.timeanddate.com/news/time/morocco-starts-dst-2009.html
    +# 
    +
    +# From Alexander Krivenyshev (2009-03-17):
    +# Here is a link to official document from Royaume du Maroc Premier Ministre,
    +# Ministere de la Modernisation des Secteurs Publics
    +#
    +# Under Article 1 of Royal Decree No. 455-67 of Act 23 safar 1387 (2 june 1967)
    +# concerning the amendment of the legal time, the Ministry of Modernization of
    +# Public Sectors announced that the official time in the Kingdom will be
    +# advanced 60 minutes from Sunday 31 May 2009 at midnight.
    +#
    +# 
    +# http://www.mmsp.gov.ma/francais/Actualites_fr/PDF_Actualites_Fr/HeureEte_FR.pdf
    +# 
    +#
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_morocco03.html
    +# 
    +
    +# From Steffen Thorsen (2010-04-13):
    +# Several news media in Morocco report that the Ministry of Modernization
    +# of Public Sectors has announced that Morocco will have DST from
    +# 2010-05-02 to 2010-08-08.
    +#
    +# Example:
    +# 
    +# http://www.lavieeco.com/actualites/4099-le-maroc-passera-a-l-heure-d-ete-gmt1-le-2-mai.html
    +# 
    +# (French)
    +# Our page:
    +# 
    +# http://www.timeanddate.com/news/time/morocco-starts-dst-2010.html
    +# 
    +
    +# From Dan Abitol (2011-03-30):
    +# ...Rules for Africa/Casablanca are the following (24h format)
    +# The 3rd april 2011 at 00:00:00, [it] will be 3rd april 1:00:00
    +# The 31th july 2011 at 00:59:59,  [it] will be 31th July 00:00:00
    +# ...Official links of change in morocco
    +# The change was broadcast on the FM Radio
    +# I ve called ANRT (telecom regulations in Morocco) at
    +# +212.537.71.84.00
    +# 
    +# http://www.anrt.net.ma/fr/
    +# 
    +# They said that
    +# 
    +# http://www.map.ma/fr/sections/accueil/l_heure_legale_au_ma/view
    +# 
    +# is the official publication to look at.
    +# They said that the decision was already taken.
    +#
    +# More articles in the press
    +# 
    +# http://www.yabiladi.com/articles/details/5058/secret-l-heure-d-ete-maroc-lev
    +# 
    +# e.html
    +# 
    +# http://www.lematin.ma/Actualite/Express/Article.asp?id=148923
    +# 
    +# 
    +# http://www.lavieeco.com/actualite/Le-Maroc-passe-sur-GMT%2B1-a-partir-de-dim
    +# anche-prochain-5538.html
    +# 
    +
    +# From Petr Machata (2011-03-30):
    +# They have it written in English here:
    +# 
    +# http://www.map.ma/eng/sections/home/morocco_to_spring_fo/view
    +# 
    +#
    +# It says there that "Morocco will resume its standard time on July 31,
    +# 2011 at midnight." Now they don't say whether they mean midnight of
    +# wall clock time (i.e. 11pm UTC), but that's what I would assume. It has
    +# also been like that in the past.
    +
    +# From Alexander Krivenyshev (2012-03-09):
    +# According to Infomédiaire web site from Morocco (infomediaire.ma),
    +# on March 9, 2012, (in French) Heure légale:
    +# Le Maroc adopte officiellement l'heure d'été
    +# 
    +# http://www.infomediaire.ma/news/maroc/heure-l%C3%A9gale-le-maroc-adopte-officiellement-lheure-d%C3%A9t%C3%A9
    +# 
    +# Governing Council adopted draft decree, that Morocco DST starts on
    +# the last Sunday of March (March 25, 2012) and ends on
    +# last Sunday of September (September 30, 2012)
    +# except the month of Ramadan.
    +# or (brief)
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_morocco06.html
    +# 
    +
    +# From Arthur David Olson (2012-03-10):
    +# The infomediaire.ma source indicates that the system is to be in
    +# effect every year. It gives 03H00 as the "fall back" time of day;
    +# it lacks a "spring forward" time of day; assume 2:00 XXX.
    +# Wait on specifying the Ramadan exception for details about
    +# start date, start time of day, end date, and end time of day XXX.
    +
    +# From Christophe Tropamer (2012-03-16):
    +# Seen Morocco change again:
    +# 
    +# http://www.le2uminutes.com/actualite.php
    +# 
    +# "...à partir du dernier dimance d'avril et non fins mars,
    +# comme annoncé précédemment."
    +
    +# From Milamber Space Network (2012-07-17):
    +# The official return to GMT is announced by the Moroccan government:
    +# 
    +# http://www.mmsp.gov.ma/fr/actualites.aspx?id=288 [in French]
    +# 
    +#
    +# Google translation, lightly edited:
    +# Back to the standard time of the Kingdom (GMT)
    +# Pursuant to Decree No. 2-12-126 issued on 26 Jumada (I) 1433 (April 18,
    +# 2012) and in accordance with the order of Mr. President of the
    +# Government No. 3-47-12 issued on 24 Sha'ban (11 July 2012), the Ministry
    +# of Public Service and Administration Modernization announces the return
    +# of the legal time of the Kingdom (GMT) from Friday, July 20, 2012 until
    +# Monday, August 20, 2012.  So the time will be delayed by 60 minutes from
    +# 3:00 am Friday, July 20, 2012 and will again be advanced by 60 minutes
    +# August 20, 2012 from 2:00 am.
    +
    +# RULE	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +
    +Rule	Morocco	1939	only	-	Sep	12	 0:00	1:00	S
    +Rule	Morocco	1939	only	-	Nov	19	 0:00	0	-
    +Rule	Morocco	1940	only	-	Feb	25	 0:00	1:00	S
    +Rule	Morocco	1945	only	-	Nov	18	 0:00	0	-
    +Rule	Morocco	1950	only	-	Jun	11	 0:00	1:00	S
    +Rule	Morocco	1950	only	-	Oct	29	 0:00	0	-
    +Rule	Morocco	1967	only	-	Jun	 3	12:00	1:00	S
    +Rule	Morocco	1967	only	-	Oct	 1	 0:00	0	-
    +Rule	Morocco	1974	only	-	Jun	24	 0:00	1:00	S
    +Rule	Morocco	1974	only	-	Sep	 1	 0:00	0	-
    +Rule	Morocco	1976	1977	-	May	 1	 0:00	1:00	S
    +Rule	Morocco	1976	only	-	Aug	 1	 0:00	0	-
    +Rule	Morocco	1977	only	-	Sep	28	 0:00	0	-
    +Rule	Morocco	1978	only	-	Jun	 1	 0:00	1:00	S
    +Rule	Morocco	1978	only	-	Aug	 4	 0:00	0	-
    +Rule	Morocco	2008	only	-	Jun	 1	 0:00	1:00	S
    +Rule	Morocco	2008	only	-	Sep	 1	 0:00	0	-
    +Rule	Morocco	2009	only	-	Jun	 1	 0:00	1:00	S
    +Rule	Morocco	2009	only	-	Aug	 21	 0:00	0	-
    +Rule	Morocco	2010	only	-	May	 2	 0:00	1:00	S
    +Rule	Morocco	2010	only	-	Aug	 8	 0:00	0	-
    +Rule	Morocco	2011	only	-	Apr	 3	 0:00	1:00	S
    +Rule	Morocco	2011	only	-	Jul	 31	 0	0	-
    +Rule	Morocco	2012	max	-	Apr	 lastSun 2:00	1:00	S
    +Rule	Morocco	2012	max	-	Sep	 lastSun 3:00	0	-
    +Rule	Morocco	2012	only	-	Jul	 20	 3:00	0	-
    +Rule	Morocco	2012	only	-	Aug	 20	 2:00	1:00	S
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Africa/Casablanca	-0:30:20 -	LMT	1913 Oct 26
    +			 0:00	Morocco	WE%sT	1984 Mar 16
    +			 1:00	-	CET	1986
    +			 0:00	Morocco	WE%sT
    +# Western Sahara
    +Zone Africa/El_Aaiun	-0:52:48 -	LMT	1934 Jan
    +			-1:00	-	WAT	1976 Apr 14
    +			 0:00	-	WET
    +
    +# Mozambique
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Maputo	2:10:20 -	LMT	1903 Mar
    +			2:00	-	CAT
    +
    +# Namibia
    +# The 1994-04-03 transition is from Shanks & Pottenger.
    +# Shanks & Pottenger report no DST after 1998-04; go with IATA.
    +
    +# From Petronella Sibeene (2007-03-30) in
    +# :
    +# While the entire country changes its time, Katima Mulilo and other
    +# settlements in Caprivi unofficially will not because the sun there
    +# rises and sets earlier compared to other regions.  Chief of
    +# Forecasting Riaan van Zyl explained that the far eastern parts of
    +# the country are close to 40 minutes earlier in sunrise than the rest
    +# of the country.
    +#
    +# From Paul Eggert (2007-03-31):
    +# Apparently the Caprivi Strip informally observes Botswana time, but
    +# we have no details.  In the meantime people there can use Africa/Gaborone.
    +
    +# RULE	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Namibia	1994	max	-	Sep	Sun>=1	2:00	1:00	S
    +Rule	Namibia	1995	max	-	Apr	Sun>=1	2:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Windhoek	1:08:24 -	LMT	1892 Feb 8
    +			1:30	-	SWAT	1903 Mar	# SW Africa Time
    +			2:00	-	SAST	1942 Sep 20 2:00
    +			2:00	1:00	SAST	1943 Mar 21 2:00
    +			2:00	-	SAST	1990 Mar 21 # independence
    +			2:00	-	CAT	1994 Apr  3
    +			1:00	Namibia	WA%sT
    +
    +# Niger
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Niamey	 0:08:28 -	LMT	1912
    +			-1:00	-	WAT	1934 Feb 26
    +			 0:00	-	GMT	1960
    +			 1:00	-	WAT
    +
    +# Nigeria
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Lagos	0:13:36 -	LMT	1919 Sep
    +			1:00	-	WAT
    +
    +# Reunion
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Indian/Reunion	3:41:52 -	LMT	1911 Jun	# Saint-Denis
    +			4:00	-	RET	# Reunion Time
    +#
    +# Scattered Islands (Iles Eparses) administered from Reunion are as follows.
    +# The following information about them is taken from
    +# Iles Eparses (www.outre-mer.gouv.fr/domtom/ile.htm, 1997-07-22, in French;
    +# no longer available as of 1999-08-17).
    +# We have no info about their time zone histories.
    +#
    +# Bassas da India - uninhabited
    +# Europa Island - inhabited from 1905 to 1910 by two families
    +# Glorioso Is - inhabited until at least 1958
    +# Juan de Nova - uninhabited
    +# Tromelin - inhabited until at least 1958
    +
    +# Rwanda
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Kigali	2:00:16 -	LMT	1935 Jun
    +			2:00	-	CAT
    +
    +# St Helena
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Atlantic/St_Helena	-0:22:48 -	LMT	1890		# Jamestown
    +			-0:22:48 -	JMT	1951	# Jamestown Mean Time
    +			 0:00	-	GMT
    +# The other parts of the St Helena territory are similar:
    +#	Tristan da Cunha: on GMT, say Whitman and the CIA
    +#	Ascension: on GMT, says usno1995 and the CIA
    +#	Gough (scientific station since 1955; sealers wintered previously):
    +#		on GMT, says the CIA
    +#	Inaccessible, Nightingale: no information, but probably GMT
    +
    +# Sao Tome and Principe
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Sao_Tome	 0:26:56 -	LMT	1884
    +			-0:36:32 -	LMT	1912	# Lisbon Mean Time
    +			 0:00	-	GMT
    +
    +# Senegal
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Dakar	-1:09:44 -	LMT	1912
    +			-1:00	-	WAT	1941 Jun
    +			 0:00	-	GMT
    +
    +# Seychelles
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Indian/Mahe	3:41:48 -	LMT	1906 Jun	# Victoria
    +			4:00	-	SCT	# Seychelles Time
    +# From Paul Eggert (2001-05-30):
    +# Aldabra, Farquhar, and Desroches, originally dependencies of the
    +# Seychelles, were transferred to the British Indian Ocean Territory
    +# in 1965 and returned to Seychelles control in 1976.  We don't know
    +# whether this affected their time zone, so omit this for now.
    +# Possibly the islands were uninhabited.
    +
    +# Sierra Leone
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +# Whitman gives Mar 31 - Aug 31 for 1931 on; go with Shanks & Pottenger.
    +Rule	SL	1935	1942	-	Jun	 1	0:00	0:40	SLST
    +Rule	SL	1935	1942	-	Oct	 1	0:00	0	WAT
    +Rule	SL	1957	1962	-	Jun	 1	0:00	1:00	SLST
    +Rule	SL	1957	1962	-	Sep	 1	0:00	0	GMT
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Freetown	-0:53:00 -	LMT	1882
    +			-0:53:00 -	FMT	1913 Jun # Freetown Mean Time
    +			-1:00	SL	%s	1957
    +			 0:00	SL	%s
    +
    +# Somalia
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Africa/Mogadishu	3:01:28 -	LMT	1893 Nov
    +			3:00	-	EAT	1931
    +			2:30	-	BEAT	1957
    +			3:00	-	EAT
    +
    +# South Africa
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	SA	1942	1943	-	Sep	Sun>=15	2:00	1:00	-
    +Rule	SA	1943	1944	-	Mar	Sun>=15	2:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Africa/Johannesburg 1:52:00 -	LMT	1892 Feb 8
    +			1:30	-	SAST	1903 Mar
    +			2:00	SA	SAST
    +# Marion and Prince Edward Is
    +# scientific station since 1947
    +# no information
    +
    +# Sudan
    +#
    +# From 
    +# Sudan News Agency (2000-01-13)
    +# , also reported by Michael De Beukelaer-Dossche via Steffen Thorsen:
    +# Clocks will be moved ahead for 60 minutes all over the Sudan as of noon
    +# Saturday....  This was announced Thursday by Caretaker State Minister for
    +# Manpower Abdul-Rahman Nur-Eddin.
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Sudan	1970	only	-	May	 1	0:00	1:00	S
    +Rule	Sudan	1970	1985	-	Oct	15	0:00	0	-
    +Rule	Sudan	1971	only	-	Apr	30	0:00	1:00	S
    +Rule	Sudan	1972	1985	-	Apr	lastSun	0:00	1:00	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Khartoum	2:10:08 -	LMT	1931
    +			2:00	Sudan	CA%sT	2000 Jan 15 12:00
    +			3:00	-	EAT
    +
    +# South Sudan
    +Zone	Africa/Juba	2:06:24 -	LMT	1931
    +			2:00	Sudan	CA%sT	2000 Jan 15 12:00
    +			3:00	-	EAT
    +
    +# Swaziland
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Mbabane	2:04:24 -	LMT	1903 Mar
    +			2:00	-	SAST
    +
    +# Tanzania
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Africa/Dar_es_Salaam 2:37:08 -	LMT	1931
    +			3:00	-	EAT	1948
    +			2:45	-	BEAUT	1961
    +			3:00	-	EAT
    +
    +# Togo
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Lome	0:04:52 -	LMT	1893
    +			0:00	-	GMT
    +
    +# Tunisia
    +
    +# From Gwillim Law (2005-04-30):
    +# My correspondent, Risto Nykanen, has alerted me to another adoption of DST,
    +# this time in Tunisia.  According to Yahoo France News
    +# , in a story attributed to AP
    +# and dated 2005-04-26, "Tunisia has decided to advance its official time by
    +# one hour, starting on Sunday, May 1.  Henceforth, Tunisian time will be
    +# UTC+2 instead of UTC+1.  The change will take place at 23:00 UTC next
    +# Saturday."  (My translation)
    +#
    +# From Oscar van Vlijmen (2005-05-02):
    +# LaPresse, the first national daily newspaper ...
    +# 
    +# ... DST for 2005: on: Sun May 1 0h standard time, off: Fri Sept. 30,
    +# 1h standard time.
    +#
    +# From Atef Loukil (2006-03-28):
    +# The daylight saving time will be the same each year:
    +# Beginning      : the last Sunday of March at 02:00
    +# Ending         : the last Sunday of October at 03:00 ...
    +# http://www.tap.info.tn/en/index.php?option=com_content&task=view&id=1188&Itemid=50
    +
    +# From Steffen Thorsen (2009-03-16):
    +# According to several news sources, Tunisia will not observe DST this year.
    +# (Arabic)
    +# 
    +# http://www.elbashayer.com/?page=viewn&nid=42546
    +# 
    +# 
    +# http://www.babnet.net/kiwidetail-15295.asp
    +# 
    +#
    +# We have also confirmed this with the US embassy in Tunisia.
    +# We have a wrap-up about this on the following page:
    +# 
    +# http://www.timeanddate.com/news/time/tunisia-cancels-dst-2009.html
    +# 
    +
    +# From Alexander Krivenyshev (2009-03-17):
    +# Here is a link to Tunis Afrique Presse News Agency
    +#
    +# Standard time to be kept the whole year long (tap.info.tn):
    +#
    +# (in English)
    +# 
    +# http://www.tap.info.tn/en/index.php?option=com_content&task=view&id=26813&Itemid=157
    +# 
    +#
    +# (in Arabic)
    +# 
    +# http://www.tap.info.tn/ar/index.php?option=com_content&task=view&id=61240&Itemid=1
    +# 
    +
    +# From Arthur David Olson (2009--3-18):
    +# The Tunis Afrique Presse News Agency notice contains this: "This measure is due to the fact
    +# that the fasting month of ramadan coincides with the period concerned by summer time.
    +# Therefore, the standard time will be kept unchanged the whole year long."
    +# So foregoing DST seems to be an exception (albeit one that may be repeated in the  future).
    +
    +# From Alexander Krivenyshev (2010-03-27):
    +# According to some news reports Tunis confirmed not to use DST in 2010
    +#
    +# (translation):
    +# "The Tunisian government has decided to abandon DST, which was scheduled on
    +# Sunday...
    +# Tunisian authorities had suspended the DST for the first time last year also
    +# coincided with the month of Ramadan..."
    +#
    +# (in Arabic)
    +# 
    +# http://www.moheet.com/show_news.aspx?nid=358861&pg=1
    +# 
    +# http://www.almadenahnews.com/newss/news.php?c=118&id=38036
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_tunis02.html
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Tunisia	1939	only	-	Apr	15	23:00s	1:00	S
    +Rule	Tunisia	1939	only	-	Nov	18	23:00s	0	-
    +Rule	Tunisia	1940	only	-	Feb	25	23:00s	1:00	S
    +Rule	Tunisia	1941	only	-	Oct	 6	 0:00	0	-
    +Rule	Tunisia	1942	only	-	Mar	 9	 0:00	1:00	S
    +Rule	Tunisia	1942	only	-	Nov	 2	 3:00	0	-
    +Rule	Tunisia	1943	only	-	Mar	29	 2:00	1:00	S
    +Rule	Tunisia	1943	only	-	Apr	17	 2:00	0	-
    +Rule	Tunisia	1943	only	-	Apr	25	 2:00	1:00	S
    +Rule	Tunisia	1943	only	-	Oct	 4	 2:00	0	-
    +Rule	Tunisia	1944	1945	-	Apr	Mon>=1	 2:00	1:00	S
    +Rule	Tunisia	1944	only	-	Oct	 8	 0:00	0	-
    +Rule	Tunisia	1945	only	-	Sep	16	 0:00	0	-
    +Rule	Tunisia	1977	only	-	Apr	30	 0:00s	1:00	S
    +Rule	Tunisia	1977	only	-	Sep	24	 0:00s	0	-
    +Rule	Tunisia	1978	only	-	May	 1	 0:00s	1:00	S
    +Rule	Tunisia	1978	only	-	Oct	 1	 0:00s	0	-
    +Rule	Tunisia	1988	only	-	Jun	 1	 0:00s	1:00	S
    +Rule	Tunisia	1988	1990	-	Sep	lastSun	 0:00s	0	-
    +Rule	Tunisia	1989	only	-	Mar	26	 0:00s	1:00	S
    +Rule	Tunisia	1990	only	-	May	 1	 0:00s	1:00	S
    +Rule	Tunisia	2005	only	-	May	 1	 0:00s	1:00	S
    +Rule	Tunisia	2005	only	-	Sep	30	 1:00s	0	-
    +Rule	Tunisia	2006	2008	-	Mar	lastSun	 2:00s	1:00	S
    +Rule	Tunisia	2006	2008	-	Oct	lastSun	 2:00s	0	-
    +
    +# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
    +# more precise 0:09:21.
    +# Shanks & Pottenger say the 1911 switch was on Mar 9; go with Howse's Mar 11.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Tunis	0:40:44 -	LMT	1881 May 12
    +			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
    +			1:00	Tunisia	CE%sT
    +
    +# Uganda
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Kampala	2:09:40 -	LMT	1928 Jul
    +			3:00	-	EAT	1930
    +			2:30	-	BEAT	1948
    +			2:45	-	BEAUT	1957
    +			3:00	-	EAT
    +
    +# Zambia
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Lusaka	1:53:08 -	LMT	1903 Mar
    +			2:00	-	CAT
    +
    +# Zimbabwe
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Africa/Harare	2:04:12 -	LMT	1903 Mar
    +			2:00	-	CAT
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/antarctica b/jdk/test/sun/util/calendar/zi/tzdata/antarctica
    new file mode 100644
    index 00000000000..64b71d5c052
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/antarctica
    @@ -0,0 +1,436 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# From Paul Eggert (1999-11-15):
    +# To keep things manageable, we list only locations occupied year-round; see
    +# 
    +# COMNAP - Stations and Bases
    +# 
    +# and
    +# 
    +# Summary of the Peri-Antarctic Islands (1998-07-23)
    +# 
    +# for information.
    +# Unless otherwise specified, we have no time zone information.
    +#
    +# Except for the French entries,
    +# I made up all time zone abbreviations mentioned here; corrections welcome!
    +# FORMAT is `zzz' and GMTOFF is 0 for locations while uninhabited.
    +
    +# These rules are stolen from the `southamerica' file.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	ArgAQ	1964	1966	-	Mar	 1	0:00	0	-
    +Rule	ArgAQ	1964	1966	-	Oct	15	0:00	1:00	S
    +Rule	ArgAQ	1967	only	-	Apr	 2	0:00	0	-
    +Rule	ArgAQ	1967	1968	-	Oct	Sun>=1	0:00	1:00	S
    +Rule	ArgAQ	1968	1969	-	Apr	Sun>=1	0:00	0	-
    +Rule	ArgAQ	1974	only	-	Jan	23	0:00	1:00	S
    +Rule	ArgAQ	1974	only	-	May	 1	0:00	0	-
    +Rule	ChileAQ	1972	1986	-	Mar	Sun>=9	3:00u	0	-
    +Rule	ChileAQ	1974	1987	-	Oct	Sun>=9	4:00u	1:00	S
    +Rule	ChileAQ	1987	only	-	Apr	12	3:00u	0	-
    +Rule	ChileAQ	1988	1989	-	Mar	Sun>=9	3:00u	0	-
    +Rule	ChileAQ	1988	only	-	Oct	Sun>=1	4:00u	1:00	S
    +Rule	ChileAQ	1989	only	-	Oct	Sun>=9	4:00u	1:00	S
    +Rule	ChileAQ	1990	only	-	Mar	18	3:00u	0	-
    +Rule	ChileAQ	1990	only	-	Sep	16	4:00u	1:00	S
    +Rule	ChileAQ	1991	1996	-	Mar	Sun>=9	3:00u	0	-
    +Rule	ChileAQ	1991	1997	-	Oct	Sun>=9	4:00u	1:00	S
    +Rule	ChileAQ	1997	only	-	Mar	30	3:00u	0	-
    +Rule	ChileAQ	1998	only	-	Mar	Sun>=9	3:00u	0	-
    +Rule	ChileAQ	1998	only	-	Sep	27	4:00u	1:00	S
    +Rule	ChileAQ	1999	only	-	Apr	 4	3:00u	0	-
    +Rule	ChileAQ	1999	2010	-	Oct	Sun>=9	4:00u	1:00	S
    +Rule	ChileAQ	2000	2007	-	Mar	Sun>=9	3:00u	0	-
    +# N.B.: the end of March 29 in Chile is March 30 in Universal time,
    +# which is used below in specifying the transition.
    +Rule	ChileAQ	2008	only	-	Mar	30	3:00u	0	-
    +Rule	ChileAQ	2009	only	-	Mar	Sun>=9	3:00u	0	-
    +Rule	ChileAQ	2010	only	-	Apr	Sun>=1	3:00u	0	-
    +Rule	ChileAQ	2011	only	-	May	Sun>=2	3:00u	0	-
    +Rule	ChileAQ	2011	only	-	Aug	Sun>=16	4:00u	1:00	S
    +Rule	ChileAQ	2012	only	-	Apr	Sun>=23	3:00u	0	-
    +Rule	ChileAQ	2012	only	-	Sep	Sun>=2	4:00u	1:00	S
    +Rule	ChileAQ	2013	max	-	Mar	Sun>=9	3:00u	0	-
    +Rule	ChileAQ	2013	max	-	Oct	Sun>=9	4:00u	1:00	S
    +
    +# These rules are stolen from the `australasia' file.
    +Rule	AusAQ	1917	only	-	Jan	 1	0:01	1:00	-
    +Rule	AusAQ	1917	only	-	Mar	25	2:00	0	-
    +Rule	AusAQ	1942	only	-	Jan	 1	2:00	1:00	-
    +Rule	AusAQ	1942	only	-	Mar	29	2:00	0	-
    +Rule	AusAQ	1942	only	-	Sep	27	2:00	1:00	-
    +Rule	AusAQ	1943	1944	-	Mar	lastSun	2:00	0	-
    +Rule	AusAQ	1943	only	-	Oct	 3	2:00	1:00	-
    +Rule	ATAQ	1967	only	-	Oct	Sun>=1	2:00s	1:00	-
    +Rule	ATAQ	1968	only	-	Mar	lastSun	2:00s	0	-
    +Rule	ATAQ	1968	1985	-	Oct	lastSun	2:00s	1:00	-
    +Rule	ATAQ	1969	1971	-	Mar	Sun>=8	2:00s	0	-
    +Rule	ATAQ	1972	only	-	Feb	lastSun	2:00s	0	-
    +Rule	ATAQ	1973	1981	-	Mar	Sun>=1	2:00s	0	-
    +Rule	ATAQ	1982	1983	-	Mar	lastSun	2:00s	0	-
    +Rule	ATAQ	1984	1986	-	Mar	Sun>=1	2:00s	0	-
    +Rule	ATAQ	1986	only	-	Oct	Sun>=15	2:00s	1:00	-
    +Rule	ATAQ	1987	1990	-	Mar	Sun>=15	2:00s	0	-
    +Rule	ATAQ	1987	only	-	Oct	Sun>=22	2:00s	1:00	-
    +Rule	ATAQ	1988	1990	-	Oct	lastSun	2:00s	1:00	-
    +Rule	ATAQ	1991	1999	-	Oct	Sun>=1	2:00s	1:00	-
    +Rule	ATAQ	1991	2005	-	Mar	lastSun	2:00s	0	-
    +Rule	ATAQ	2000	only	-	Aug	lastSun	2:00s	1:00	-
    +Rule	ATAQ	2001	max	-	Oct	Sun>=1	2:00s	1:00	-
    +Rule	ATAQ	2006	only	-	Apr	Sun>=1	2:00s	0	-
    +Rule	ATAQ	2007	only	-	Mar	lastSun	2:00s	0	-
    +Rule	ATAQ	2008	max	-	Apr	Sun>=1	2:00s	0	-
    +
    +# Argentina - year-round bases
    +# Belgrano II, Confin Coast, -770227-0343737, since 1972-02-05
    +# Esperanza, San Martin Land, -6323-05659, since 1952-12-17
    +# Jubany, Potter Peninsula, King George Island, -6414-0602320, since 1982-01
    +# Marambio, Seymour I, -6414-05637, since 1969-10-29
    +# Orcadas, Laurie I, -6016-04444, since 1904-02-22
    +# San Martin, Debenham I, -6807-06708, since 1951-03-21
    +#	(except 1960-03 / 1976-03-21)
    +
    +# Australia - territories
    +# Heard Island, McDonald Islands (uninhabited)
    +#	previously sealers and scientific personnel wintered
    +#	
    +#	Margaret Turner reports
    +#	 (1999-09-30) that they're UTC+5, with no DST;
    +#	presumably this is when they have visitors.
    +#
    +# year-round bases
    +# Casey, Bailey Peninsula, -6617+11032, since 1969
    +# Davis, Vestfold Hills, -6835+07759, since 1957-01-13
    +#	(except 1964-11 - 1969-02)
    +# Mawson, Holme Bay, -6736+06253, since 1954-02-13
    +
    +# From Steffen Thorsen (2009-03-11):
    +# Three Australian stations in Antarctica have changed their time zone:
    +# Casey moved from UTC+8 to UTC+11
    +# Davis moved from UTC+7 to UTC+5
    +# Mawson moved from UTC+6 to UTC+5
    +# The changes occurred on 2009-10-18 at 02:00 (local times).
    +#
    +# Government source: (Australian Antarctic Division)
    +# 
    +# http://www.aad.gov.au/default.asp?casid=37079
    +# 
    +#
    +# We have more background information here:
    +# 
    +# http://www.timeanddate.com/news/time/antarctica-new-times.html
    +# 
    +
    +# From Steffen Thorsen (2010-03-10):
    +# We got these changes from the Australian Antarctic Division:
    +# - Macquarie Island will stay on UTC+11 for winter and therefore not
    +# switch back from daylight savings time when other parts of Australia do
    +# on 4 April.
    +#
    +# - Casey station reverted to its normal time of UTC+8 on 5 March 2010.
    +# The change to UTC+11 is being considered as a regular summer thing but
    +# has not been decided yet.
    +#
    +# - Davis station will revert to its normal time of UTC+7 at 10 March 2010
    +# 20:00 UTC.
    +#
    +# - Mawson station stays on UTC+5.
    +#
    +# In addition to the Rule changes for Casey/Davis, it means that Macquarie
    +# will no longer be like Hobart and will have to have its own Zone created.
    +#
    +# Background:
    +# 
    +# http://www.timeanddate.com/news/time/antartica-time-changes-2010.html
    +# 
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Antarctica/Casey	0	-	zzz	1969
    +			8:00	-	WST	2009 Oct 18 2:00
    +						# Western (Aus) Standard Time
    +			11:00	-	CAST	2010 Mar 5 2:00
    +						# Casey Time
    +			8:00	-	WST	2011 Oct 28 2:00
    +			11:00	-	CAST	2012 Feb 21 17:00u
    +			8:00	-	WST
    +Zone Antarctica/Davis	0	-	zzz	1957 Jan 13
    +			7:00	-	DAVT	1964 Nov # Davis Time
    +			0	-	zzz	1969 Feb
    +			7:00	-	DAVT	2009 Oct 18 2:00
    +			5:00	-	DAVT	2010 Mar 10 20:00u
    +			7:00	-	DAVT	2011 Oct 28 2:00
    +			5:00	-	DAVT	2012 Feb 21 20:00u
    +			7:00	-	DAVT
    +Zone Antarctica/Mawson	0	-	zzz	1954 Feb 13
    +			6:00	-	MAWT	2009 Oct 18 2:00
    +						# Mawson Time
    +			5:00	-	MAWT
    +Zone Antarctica/Macquarie 0	-	zzz	1911
    +			10:00	-	EST	1916 Oct 1 2:00
    +			10:00	1:00	EST	1917 Feb
    +			10:00	AusAQ	EST	1967
    +			10:00	ATAQ	EST	2010 Apr 4 3:00
    +			11:00	-	MIST	# Macquarie Island Time
    +# References:
    +# 
    +# Casey Weather (1998-02-26)
    +# 
    +# 
    +# Davis Station, Antarctica (1998-02-26)
    +# 
    +# 
    +# Mawson Station, Antarctica (1998-02-25)
    +# 
    +
    +# Brazil - year-round base
    +# Comandante Ferraz, King George Island, -6205+05824, since 1983/4
    +
    +# Chile - year-round bases and towns
    +# Escudero, South Shetland Is, -621157-0585735, since 1994
    +# Presidente Eduadro Frei, King George Island, -6214-05848, since 1969-03-07
    +# General Bernardo O'Higgins, Antarctic Peninsula, -6319-05704, since 1948-02
    +# Capitan Arturo Prat, -6230-05941
    +# Villa Las Estrellas (a town), around the Frei base, since 1984-04-09
    +# These locations have always used Santiago time; use TZ='America/Santiago'.
    +
    +# China - year-round bases
    +# Great Wall, King George Island, -6213-05858, since 1985-02-20
    +# Zhongshan, Larsemann Hills, Prydz Bay, -6922+07623, since 1989-02-26
    +
    +# France - year-round bases
    +#
    +# From Antoine Leca (1997-01-20):
    +# Time data are from Nicole Pailleau at the IFRTP
    +# (French Institute for Polar Research and Technology).
    +# She confirms that French Southern Territories and Terre Adelie bases
    +# don't observe daylight saving time, even if Terre Adelie supplies came
    +# from Tasmania.
    +#
    +# French Southern Territories with year-round inhabitants
    +#
    +# Martin-de-Vivies Base, Amsterdam Island, -374105+0773155, since 1950
    +# Alfred-Faure Base, Crozet Islands, -462551+0515152, since 1964
    +# Port-aux-Francais, Kerguelen Islands, -492110+0701303, since 1951;
    +#	whaling & sealing station operated 1908/1914, 1920/1929, and 1951/1956
    +#
    +# St Paul Island - near Amsterdam, uninhabited
    +#	fishing stations operated variously 1819/1931
    +#
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Indian/Kerguelen	0	-	zzz	1950	# Port-aux-Francais
    +			5:00	-	TFT	# ISO code TF Time
    +#
    +# year-round base in the main continent
    +# Dumont-d'Urville, Ile des Petrels, -6640+14001, since 1956-11
    +#
    +# Another base at Port-Martin, 50km east, began operation in 1947.
    +# It was destroyed by fire on 1952-01-14.
    +#
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Antarctica/DumontDUrville 0 -	zzz	1947
    +			10:00	-	PMT	1952 Jan 14 # Port-Martin Time
    +			0	-	zzz	1956 Nov
    +			10:00	-	DDUT	# Dumont-d'Urville Time
    +# Reference:
    +# 
    +# Dumont d'Urville Station (2005-12-05)
    +# 
    +
    +# Germany - year-round base
    +# Georg von Neumayer, -7039-00815
    +
    +# India - year-round base
    +# Dakshin Gangotri, -7005+01200
    +
    +# Japan - year-round bases
    +# Dome Fuji, -7719+03942
    +# Syowa, -690022+0393524
    +#
    +# From Hideyuki Suzuki (1999-02-06):
    +# In all Japanese stations, +0300 is used as the standard time.
    +#
    +# Syowa station, which is the first antarctic station of Japan,
    +# was established on 1957-01-29.  Since Syowa station is still the main
    +# station of Japan, it's appropriate for the principal location.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Antarctica/Syowa	0	-	zzz	1957 Jan 29
    +			3:00	-	SYOT	# Syowa Time
    +# See:
    +# 
    +# NIPR Antarctic Research Activities (1999-08-17)
    +# 
    +
    +# S Korea - year-round base
    +# King Sejong, King George Island, -6213-05847, since 1988
    +
    +# New Zealand - claims
    +# Balleny Islands (never inhabited)
    +# Scott Island (never inhabited)
    +#
    +# year-round base
    +# Scott, Ross Island, since 1957-01, is like Antarctica/McMurdo.
    +#
    +# These rules for New Zealand are stolen from the `australasia' file.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	NZAQ	1974	only	-	Nov	 3	2:00s	1:00	D
    +Rule	NZAQ	1975	1988	-	Oct	lastSun	2:00s	1:00	D
    +Rule	NZAQ	1989	only	-	Oct	 8	2:00s	1:00	D
    +Rule	NZAQ	1990	2006	-	Oct	Sun>=1	2:00s	1:00	D
    +Rule	NZAQ	1975	only	-	Feb	23	2:00s	0	S
    +Rule	NZAQ	1976	1989	-	Mar	Sun>=1	2:00s	0	S
    +Rule	NZAQ	1990	2007	-	Mar	Sun>=15	2:00s	0	S
    +Rule	NZAQ	2007	max	-	Sep	lastSun	2:00s	1:00	D
    +Rule	NZAQ	2008	max	-	Apr	Sun>=1	2:00s	0	S
    +
    +# Norway - territories
    +# Bouvet (never inhabited)
    +#
    +# claims
    +# Peter I Island (never inhabited)
    +
    +# Poland - year-round base
    +# Arctowski, King George Island, -620945-0582745, since 1977
    +
    +# Russia - year-round bases
    +# Bellingshausen, King George Island, -621159-0585337, since 1968-02-22
    +# Mirny, Davis coast, -6633+09301, since 1956-02
    +# Molodezhnaya, Alasheyev Bay, -6740+04551,
    +#	year-round from 1962-02 to 1999-07-01
    +# Novolazarevskaya, Queen Maud Land, -7046+01150,
    +#	year-round from 1960/61 to 1992
    +
    +# Vostok, since 1957-12-16, temporarily closed 1994-02/1994-11
    +# 
    +# From Craig Mundell (1994-12-15):
    +# Vostok, which is one of the Russian stations, is set on the same
    +# time as Moscow, Russia.
    +#
    +# From Lee Hotz (2001-03-08):
    +# I queried the folks at Columbia who spent the summer at Vostok and this is
    +# what they had to say about time there:
    +# ``in the US Camp (East Camp) we have been on New Zealand (McMurdo)
    +# time, which is 12 hours ahead of GMT. The Russian Station Vostok was
    +# 6 hours behind that (although only 2 miles away, i.e. 6 hours ahead
    +# of GMT). This is a time zone I think two hours east of Moscow. The
    +# natural time zone is in between the two: 8 hours ahead of GMT.''
    +#
    +# From Paul Eggert (2001-05-04):
    +# This seems to be hopelessly confusing, so I asked Lee Hotz about it
    +# in person.  He said that some Antartic locations set their local
    +# time so that noon is the warmest part of the day, and that this
    +# changes during the year and does not necessarily correspond to mean
    +# solar noon.  So the Vostok time might have been whatever the clocks
    +# happened to be during their visit.  So we still don't really know what time
    +# it is at Vostok.  But we'll guess UTC+6.
    +#
    +Zone Antarctica/Vostok	0	-	zzz	1957 Dec 16
    +			6:00	-	VOST	# Vostok time
    +
    +# S Africa - year-round bases
    +# Marion Island, -4653+03752
    +# Sanae, -7141-00250
    +
    +# UK
    +#
    +# British Antarctic Territories (BAT) claims
    +# South Orkney Islands
    +#	scientific station from 1903
    +#	whaling station at Signy I 1920/1926
    +# South Shetland Islands
    +#
    +# year-round bases
    +# Bird Island, South Georgia, -5400-03803, since 1983
    +# Deception Island, -6259-06034, whaling station 1912/1931,
    +#	scientific station 1943/1967,
    +#	previously sealers and a scientific expedition wintered by accident,
    +#	and a garrison was deployed briefly
    +# Halley, Coates Land, -7535-02604, since 1956-01-06
    +#	Halley is on a moving ice shelf and is periodically relocated
    +#	so that it is never more than 10km from its nominal location.
    +# Rothera, Adelaide Island, -6734-6808, since 1976-12-01
    +#
    +# From Paul Eggert (2002-10-22)
    +#  says Rothera is -03 all year.
    +#
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Antarctica/Rothera	0	-	zzz	1976 Dec  1
    +			-3:00	-	ROTT	# Rothera time
    +
    +# Uruguay - year round base
    +# Artigas, King George Island, -621104-0585107
    +
    +# USA - year-round bases
    +#
    +# Palmer, Anvers Island, since 1965 (moved 2 miles in 1968)
    +#
    +# From Ethan Dicks (1996-10-06):
    +# It keeps the same time as Punta Arenas, Chile, because, just like us
    +# and the South Pole, that's the other end of their supply line....
    +# I verified with someone who was there that since 1980,
    +# Palmer has followed Chile.  Prior to that, before the Falklands War,
    +# Palmer used to be supplied from Argentina.
    +#
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Antarctica/Palmer	0	-	zzz	1965
    +			-4:00	ArgAQ	AR%sT	1969 Oct 5
    +			-3:00	ArgAQ	AR%sT	1982 May
    +			-4:00	ChileAQ	CL%sT
    +#
    +#
    +# McMurdo, Ross Island, since 1955-12
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Antarctica/McMurdo	0	-	zzz	1956
    +			12:00	NZAQ	NZ%sT
    +#
    +# Amundsen-Scott, South Pole, continuously occupied since 1956-11-20
    +#
    +# From Paul Eggert (1996-09-03):
    +# Normally it wouldn't have a separate entry, since it's like the
    +# larger Antarctica/McMurdo since 1970, but it's too famous to omit.
    +#
    +# From Chris Carrier (1996-06-27):
    +# Siple, the first commander of the South Pole station,
    +# stated that he would have liked to have kept GMT at the station,
    +# but that he found it more convenient to keep GMT+12
    +# as supplies for the station were coming from McMurdo Sound,
    +# which was on GMT+12 because New Zealand was on GMT+12 all year
    +# at that time (1957).  (Source: Siple's book 90 degrees SOUTH.)
    +#
    +# From Susan Smith
    +# http://www.cybertours.com/whs/pole10.html
    +# (1995-11-13 16:24:56 +1300, no longer available):
    +# We use the same time as McMurdo does.
    +# And they use the same time as Christchurch, NZ does....
    +# One last quirk about South Pole time.
    +# All the electric clocks are usually wrong.
    +# Something about the generators running at 60.1hertz or something
    +# makes all of the clocks run fast.  So every couple of days,
    +# we have to go around and set them back 5 minutes or so.
    +# Maybe if we let them run fast all of the time, we'd get to leave here sooner!!
    +#
    +Link	Antarctica/McMurdo	Antarctica/South_Pole
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/asia b/jdk/test/sun/util/calendar/zi/tzdata/asia
    new file mode 100644
    index 00000000000..9ef3ef8df54
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/asia
    @@ -0,0 +1,2738 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# This data is by no means authoritative; if you think you know better,
    +# go ahead and edit the file (and please send any changes to
    +# tz@elsie.nci.nih.gov for general use in the future).
    +
    +# From Paul Eggert (2006-03-22):
    +#
    +# A good source for time zone historical data outside the U.S. is
    +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
    +# San Diego: ACS Publications, Inc. (2003).
    +#
    +# Gwillim Law writes that a good source
    +# for recent time zone data is the International Air Transport
    +# Association's Standard Schedules Information Manual (IATA SSIM),
    +# published semiannually.  Law sent in several helpful summaries
    +# of the IATA's data after 1990.
    +#
    +# Except where otherwise noted, Shanks & Pottenger is the source for
    +# entries through 1990, and IATA SSIM is the source for entries afterwards.
    +#
    +# Another source occasionally used is Edward W. Whitman, World Time Differences,
    +# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
    +# I found in the UCLA library.
    +#
    +# A reliable and entertaining source about time zones is
    +# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
    +#
    +# I invented the abbreviations marked `*' in the following table;
    +# the rest are from earlier versions of this file, or from other sources.
    +# Corrections are welcome!
    +#	     std  dst
    +#	     LMT	Local Mean Time
    +#	2:00 EET  EEST	Eastern European Time
    +#	2:00 IST  IDT	Israel
    +#	3:00 AST  ADT	Arabia*
    +#	3:30 IRST IRDT	Iran
    +#	4:00 GST	Gulf*
    +#	5:30 IST	India
    +#	7:00 ICT	Indochina*
    +#	7:00 WIT	west Indonesia
    +#	8:00 CIT	central Indonesia
    +#	8:00 CST	China
    +#	9:00 CJT	Central Japanese Time (1896/1937)*
    +#	9:00 EIT	east Indonesia
    +#	9:00 JST  JDT	Japan
    +#	9:00 KST  KDT	Korea
    +#	9:30 CST	(Australian) Central Standard Time
    +#
    +# See the `europe' file for Russia and Turkey in Asia.
    +
    +# From Guy Harris:
    +# Incorporates data for Singapore from Robert Elz' asia 1.1, as well as
    +# additional information from Tom Yap, Sun Microsystems Intercontinental
    +# Technical Support (including a page from the Official Airline Guide -
    +# Worldwide Edition).  The names for time zones are guesses.
    +
    +###############################################################################
    +
    +# These rules are stolen from the `europe' file.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	EUAsia	1981	max	-	Mar	lastSun	 1:00u	1:00	S
    +Rule	EUAsia	1979	1995	-	Sep	lastSun	 1:00u	0	-
    +Rule	EUAsia	1996	max	-	Oct	lastSun	 1:00u	0	-
    +Rule E-EurAsia	1981	max	-	Mar	lastSun	 0:00	1:00	S
    +Rule E-EurAsia	1979	1995	-	Sep	lastSun	 0:00	0	-
    +Rule E-EurAsia	1996	max	-	Oct	lastSun	 0:00	0	-
    +Rule RussiaAsia	1981	1984	-	Apr	1	 0:00	1:00	S
    +Rule RussiaAsia	1981	1983	-	Oct	1	 0:00	0	-
    +Rule RussiaAsia	1984	1991	-	Sep	lastSun	 2:00s	0	-
    +Rule RussiaAsia	1985	1991	-	Mar	lastSun	 2:00s	1:00	S
    +Rule RussiaAsia	1992	only	-	Mar	lastSat	23:00	1:00	S
    +Rule RussiaAsia	1992	only	-	Sep	lastSat	23:00	0	-
    +Rule RussiaAsia	1993	max	-	Mar	lastSun	 2:00s	1:00	S
    +Rule RussiaAsia	1993	1995	-	Sep	lastSun	 2:00s	0	-
    +Rule RussiaAsia	1996	max	-	Oct	lastSun	 2:00s	0	-
    +
    +# Afghanistan
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Kabul	4:36:48 -	LMT	1890
    +			4:00	-	AFT	1945
    +			4:30	-	AFT
    +
    +# Armenia
    +# From Paul Eggert (2006-03-22):
    +# Shanks & Pottenger have Yerevan switching to 3:00 (with Russian DST)
    +# in spring 1991, then to 4:00 with no DST in fall 1995, then
    +# readopting Russian DST in 1997.  Go with Shanks & Pottenger, even
    +# when they disagree with others.  Edgar Der-Danieliantz
    +# reported (1996-05-04) that Yerevan probably wouldn't use DST
    +# in 1996, though it did use DST in 1995.  IATA SSIM (1991/1998) reports that
    +# Armenia switched from 3:00 to 4:00 in 1998 and observed DST after 1991,
    +# but started switching at 3:00s in 1998.
    +
    +# From Arthur David Olson (2011-06-15):
    +# While Russia abandoned DST in 2011, Armenia may choose to
    +# follow Russia's "old" rules.
    +
    +# From Alexander Krivenyshev (2012-02-10):
    +# According to News Armenia, on Feb 9, 2012,
    +# http://newsarmenia.ru/society/20120209/42609695.html
    +#
    +# The Armenia National Assembly adopted final reading of Amendments to the
    +# Law "On procedure of calculation time on the territory of the Republic of
    +# Armenia" according to which Armenia [is] abolishing Daylight Saving Time.
    +# or
    +# (brief)
    +# http://www.worldtimezone.com/dst_news/dst_news_armenia03.html
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Yerevan	2:58:00 -	LMT	1924 May  2
    +			3:00	-	YERT	1957 Mar    # Yerevan Time
    +			4:00 RussiaAsia YER%sT	1991 Mar 31 2:00s
    +			3:00	1:00	YERST	1991 Sep 23 # independence
    +			3:00 RussiaAsia	AM%sT	1995 Sep 24 2:00s
    +			4:00	-	AMT	1997
    +			4:00 RussiaAsia	AM%sT	2012 Mar 25 2:00s
    +			4:00	-	AMT
    +
    +# Azerbaijan
    +# From Rustam Aliyev of the Azerbaijan Internet Forum (2005-10-23):
    +# According to the resolution of Cabinet of Ministers, 1997
    +# Resolution available at: http://aif.az/docs/daylight_res.pdf
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Azer	1997	max	-	Mar	lastSun	 4:00	1:00	S
    +Rule	Azer	1997	max	-	Oct	lastSun	 5:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Baku	3:19:24 -	LMT	1924 May  2
    +			3:00	-	BAKT	1957 Mar    # Baku Time
    +			4:00 RussiaAsia BAK%sT	1991 Mar 31 2:00s
    +			3:00	1:00	BAKST	1991 Aug 30 # independence
    +			3:00 RussiaAsia	AZ%sT	1992 Sep lastSat 23:00
    +			4:00	-	AZT	1996 # Azerbaijan time
    +			4:00	EUAsia	AZ%sT	1997
    +			4:00	Azer	AZ%sT
    +
    +# Bahrain
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Bahrain	3:22:20 -	LMT	1920		# Al Manamah
    +			4:00	-	GST	1972 Jun
    +			3:00	-	AST
    +
    +# Bangladesh
    +# From Alexander Krivenyshev (2009-05-13):
    +# According to newspaper Asian Tribune (May 6, 2009) Bangladesh may introduce
    +# Daylight Saving Time from June 16 to Sept 30
    +#
    +# Bangladesh to introduce daylight saving time likely from June 16
    +# 
    +# http://www.asiantribune.com/?q=node/17288
    +# 
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_bangladesh02.html
    +# 
    +#
    +# "... Bangladesh government has decided to switch daylight saving time from
    +# June
    +# 16 till September 30 in a bid to ensure maximum use of daylight to cope with
    +# crippling power crisis. "
    +#
    +# The switch will remain in effect from June 16 to Sept 30 (2009) but if
    +# implemented the next year, it will come in force from April 1, 2010
    +
    +# From Steffen Thorsen (2009-06-02):
    +# They have finally decided now, but changed the start date to midnight between
    +# the 19th and 20th, and they have not set the end date yet.
    +#
    +# Some sources:
    +# 
    +# http://in.reuters.com/article/southAsiaNews/idINIndia-40017620090601
    +# 
    +# 
    +# http://bdnews24.com/details.php?id=85889&cid=2
    +# 
    +#
    +# Our wrap-up:
    +# 
    +# http://www.timeanddate.com/news/time/bangladesh-daylight-saving-2009.html
    +# 
    +
    +# From A. N. M. Kamrus Saadat (2009-06-15):
    +# Finally we've got the official mail regarding DST start time where DST start
    +# time is mentioned as Jun 19 2009, 23:00 from BTRC (Bangladesh
    +# Telecommunication Regulatory Commission).
    +#
    +# No DST end date has been announced yet.
    +
    +# From Alexander Krivenyshev (2009-09-25):
    +# Bangladesh won't go back to Standard Time from October 1, 2009,
    +# instead it will continue DST measure till the cabinet makes a fresh decision.
    +#
    +# Following report by same newspaper-"The Daily Star Friday":
    +# "DST change awaits cabinet decision-Clock won't go back by 1-hr from Oct 1"
    +# 
    +# http://www.thedailystar.net/newDesign/news-details.php?nid=107021
    +# 
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_bangladesh04.html
    +# 
    +
    +# From Steffen Thorsen (2009-10-13):
    +# IANS (Indo-Asian News Service) now reports:
    +# Bangladesh has decided that the clock advanced by an hour to make
    +# maximum use of daylight hours as an energy saving measure would
    +# "continue for an indefinite period."
    +#
    +# One of many places where it is published:
    +# 
    +# http://www.thaindian.com/newsportal/business/bangladesh-to-continue-indefinitely-with-advanced-time_100259987.html
    +# 
    +
    +# From Alexander Krivenyshev (2009-12-24):
    +# According to Bangladesh newspaper "The Daily Star,"
    +# Bangladesh will change its clock back to Standard Time on Dec 31, 2009.
    +#
    +# Clock goes back 1-hr on Dec 31 night.
    +# 
    +# http://www.thedailystar.net/newDesign/news-details.php?nid=119228
    +# 
    +# and
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_bangladesh05.html
    +# 
    +#
    +# "...The government yesterday decided to put the clock back by one hour
    +# on December 31 midnight and the new time will continue until March 31,
    +# 2010 midnight. The decision came at a cabinet meeting at the Prime
    +# Minister's Office last night..."
    +
    +# From Alexander Krivenyshev (2010-03-22):
    +# According to Bangladesh newspaper "The Daily Star,"
    +# Cabinet cancels Daylight Saving Time
    +# 
    +# http://www.thedailystar.net/newDesign/latest_news.php?nid=22817
    +# 
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_bangladesh06.html
    +# 
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Dhaka	2009	only	-	Jun	19	23:00	1:00	S
    +Rule	Dhaka	2009	only	-	Dec	31	23:59	0	-
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Dhaka	6:01:40 -	LMT	1890
    +			5:53:20	-	HMT	1941 Oct    # Howrah Mean Time?
    +			6:30	-	BURT	1942 May 15 # Burma Time
    +			5:30	-	IST	1942 Sep
    +			6:30	-	BURT	1951 Sep 30
    +			6:00	-	DACT	1971 Mar 26 # Dacca Time
    +			6:00	-	BDT	2009
    +			6:00	Dhaka	BD%sT
    +
    +# Bhutan
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Thimphu	5:58:36 -	LMT	1947 Aug 15 # or Thimbu
    +			5:30	-	IST	1987 Oct
    +			6:00	-	BTT	# Bhutan Time
    +
    +# British Indian Ocean Territory
    +# Whitman and the 1995 CIA time zone map say 5:00, but the
    +# 1997 and later maps say 6:00.  Assume the switch occurred in 1996.
    +# We have no information as to when standard time was introduced;
    +# assume it occurred in 1907, the same year as Mauritius (which
    +# then contained the Chagos Archipelago).
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Indian/Chagos	4:49:40	-	LMT	1907
    +			5:00	-	IOT	1996 # BIOT Time
    +			6:00	-	IOT
    +
    +# Brunei
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Brunei	7:39:40 -	LMT	1926 Mar   # Bandar Seri Begawan
    +			7:30	-	BNT	1933
    +			8:00	-	BNT
    +
    +# Burma / Myanmar
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Rangoon	6:24:40 -	LMT	1880		# or Yangon
    +			6:24:36	-	RMT	1920	   # Rangoon Mean Time?
    +			6:30	-	BURT	1942 May   # Burma Time
    +			9:00	-	JST	1945 May 3
    +			6:30	-	MMT		   # Myanmar Time
    +
    +# Cambodia
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Phnom_Penh	6:59:40 -	LMT	1906 Jun  9
    +			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
    +			7:00	-	ICT	1912 May
    +			8:00	-	ICT	1931 May
    +			7:00	-	ICT
    +
    +# China
    +
    +# From Guy Harris:
    +# People's Republic of China.  Yes, they really have only one time zone.
    +
    +# From Bob Devine (1988-01-28):
    +# No they don't.  See TIME mag, 1986-02-17 p.52.  Even though
    +# China is across 4 physical time zones, before Feb 1, 1986 only the
    +# Peking (Bejing) time zone was recognized.  Since that date, China
    +# has two of 'em -- Peking's and Urumqi (named after the capital of
    +# the Xinjiang Uyghur Autonomous Region).  I don't know about DST for it.
    +#
    +# . . .I just deleted the DST table and this editor makes it too
    +# painful to suck in another copy..  So, here is what I have for
    +# DST start/end dates for Peking's time zone (info from AP):
    +#
    +#     1986 May 4 - Sept 14
    +#     1987 mid-April - ??
    +
    +# From U. S. Naval Observatory (1989-01-19):
    +# CHINA               8 H  AHEAD OF UTC  ALL OF CHINA, INCL TAIWAN
    +# CHINA               9 H  AHEAD OF UTC  APR 17 - SEP 10
    +
    +# From Paul Eggert (2006-03-22):
    +# Shanks & Pottenger write that China (except for Hong Kong and Macau)
    +# has had a single time zone since 1980 May 1, observing summer DST
    +# from 1986 through 1991; this contradicts Devine's
    +# note about Time magazine, though apparently _something_ happened in 1986.
    +# Go with Shanks & Pottenger for now.  I made up names for the other
    +# pre-1980 time zones.
    +
    +# From Shanks & Pottenger:
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Shang	1940	only	-	Jun	 3	0:00	1:00	D
    +Rule	Shang	1940	1941	-	Oct	 1	0:00	0	S
    +Rule	Shang	1941	only	-	Mar	16	0:00	1:00	D
    +Rule	PRC	1986	only	-	May	 4	0:00	1:00	D
    +Rule	PRC	1986	1991	-	Sep	Sun>=11	0:00	0	S
    +Rule	PRC	1987	1991	-	Apr	Sun>=10	0:00	1:00	D
    +
    +# From Anthony Fok (2001-12-20):
    +# BTW, I did some research on-line and found some info regarding these five
    +# historic timezones from some Taiwan websites.  And yes, there are official
    +# Chinese names for these locales (before 1949).
    +#
    +# From Jesper Norgaard Welen (2006-07-14):
    +# I have investigated the timezones around 1970 on the
    +# http://www.astro.com/atlas site [with provinces and county
    +# boundaries summarized below]....  A few other exceptions were two
    +# counties on the Sichuan side of the Xizang-Sichuan border,
    +# counties Dege and Baiyu which lies on the Sichuan side and are
    +# therefore supposed to be GMT+7, Xizang region being GMT+6, but Dege
    +# county is GMT+8 according to astro.com while Baiyu county is GMT+6
    +# (could be true), for the moment I am assuming that those two
    +# counties are mistakes in the astro.com data.
    +
    +# From Paul Eggert (2008-02-11):
    +# I just now checked Google News for western news sources that talk
    +# about China's single time zone, and couldn't find anything before 1986
    +# talking about China being in one time zone.  (That article was: Jim
    +# Mann, "A clumsy embrace for another western custom: China on daylight
    +# time--sort of", Los Angeles Times, 1986-05-05.  By the way, this
    +# article confirms the tz database's data claiming that China began
    +# observing daylight saving time in 1986.
    +#
    +# From Thomas S. Mullaney (2008-02-11):
    +# I think you're combining two subjects that need to treated
    +# separately: daylight savings (which, you're correct, wasn't
    +# implemented until the 1980s) and the unified time zone centered near
    +# Beijing (which was implemented in 1949). Briefly, there was also a
    +# "Lhasa Time" in Tibet and "Urumqi Time" in Xinjiang. The first was
    +# ceased, and the second eventually recognized (again, in the 1980s).
    +#
    +# From Paul Eggert (2008-06-30):
    +# There seems to be a good chance China switched to a single time zone in 1949
    +# rather than in 1980 as Shanks & Pottenger have it, but we don't have a
    +# reliable documentary source saying so yet, so for now we still go with
    +# Shanks & Pottenger.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +# Changbai Time ("Long-white Time", Long-white = Heilongjiang area)
    +# Heilongjiang (except Mohe county), Jilin
    +Zone	Asia/Harbin	8:26:44	-	LMT	1928 # or Haerbin
    +			8:30	-	CHAT	1932 Mar # Changbai Time
    +			8:00	-	CST	1940
    +			9:00	-	CHAT	1966 May
    +			8:30	-	CHAT	1980 May
    +			8:00	PRC	C%sT
    +# Zhongyuan Time ("Central plain Time")
    +# most of China
    +Zone	Asia/Shanghai	8:05:52	-	LMT	1928
    +			8:00	Shang	C%sT	1949
    +			8:00	PRC	C%sT
    +# Long-shu Time (probably due to Long and Shu being two names of that area)
    +# Guangxi, Guizhou, Hainan, Ningxia, Sichuan, Shaanxi, and Yunnan;
    +# most of Gansu; west Inner Mongolia; west Qinghai; and the Guangdong
    +# counties Deqing, Enping, Kaiping, Luoding, Taishan, Xinxing,
    +# Yangchun, Yangjiang, Yu'nan, and Yunfu.
    +Zone	Asia/Chongqing	7:06:20	-	LMT	1928 # or Chungking
    +			7:00	-	LONT	1980 May # Long-shu Time
    +			8:00	PRC	C%sT
    +# Xin-zang Time ("Xinjiang-Tibet Time")
    +# The Gansu counties Aksay, Anxi, Dunhuang, Subei; west Qinghai;
    +# the Guangdong counties  Xuwen, Haikang, Suixi, Lianjiang,
    +# Zhanjiang, Wuchuan, Huazhou, Gaozhou, Maoming, Dianbai, and Xinyi;
    +# east Tibet, including Lhasa, Chamdo, Shigaise, Jimsar, Shawan and Hutubi;
    +# east Xinjiang, including Urumqi, Turpan, Karamay, Korla, Minfeng, Jinghe,
    +# Wusu, Qiemo, Xinyan, Wulanwusu, Jinghe, Yumin, Tacheng, Tuoli, Emin,
    +# Shihezi, Changji, Yanqi, Heshuo, Tuokexun, Tulufan, Shanshan, Hami,
    +# Fukang, Kuitun, Kumukuli, Miquan, Qitai, and Turfan.
    +Zone	Asia/Urumqi	5:50:20	-	LMT	1928 # or Urumchi
    +			6:00	-	URUT	1980 May # Urumqi Time
    +			8:00	PRC	C%sT
    +# Kunlun Time
    +# West Tibet, including Pulan, Aheqi, Shufu, Shule;
    +# West Xinjiang, including Aksu, Atushi, Yining, Hetian, Cele, Luopu, Nileke,
    +# Zhaosu, Tekesi, Gongliu, Chabuchaer, Huocheng, Bole, Pishan, Suiding,
    +# and Yarkand.
    +
    +# From Luther Ma (2009-10-17):
    +# Almost all (>99.9%) ethnic Chinese (properly ethnic Han) living in
    +# Xinjiang use Chinese Standard Time. Some are aware of Xinjiang time,
    +# but have no need of it. All planes, trains, and schools function on
    +# what is called "Beijing time." When Han make an appointment in Chinese
    +# they implicitly use Beijing time.
    +#
    +# On the other hand, ethnic Uyghurs, who make up about half the
    +# population of Xinjiang, typically use "Xinjiang time" which is two
    +# hours behind Beijing time, or UTC +0600. The government of the Xinjiang
    +# Uyghur Autonomous Region, (XAUR, or just Xinjiang for short) as well as
    +# local governments such as the Urumqi city government use both times in
    +# publications, referring to what is popularly called Xinjiang time as
    +# "Urumqi time." When Uyghurs make an appointment in the Uyghur language
    +# they almost invariably use Xinjiang time.
    +#
    +# (Their ethnic Han compatriots would typically have no clue of its
    +# widespread use, however, because so extremely few of them are fluent in
    +# Uyghur, comparable to the number of Anglo-Americans fluent in Navajo.)
    +#
    +# (...As with the rest of China there was a brief interval ending in 1990
    +# or 1991 when summer time was in use.  The confusion was severe, with
    +# the province not having dual times but four times in use at the same
    +# time. Some areas remained on standard Xinjiang time or Beijing time and
    +# others moving their clocks ahead.)
    +#
    +# ...an example of an official website using of Urumqi time.
    +#
    +# The first few lines of the Google translation of
    +# 
    +# http://www.fjysgl.gov.cn/show.aspx?id=2379&cid=39
    +# 
    +# (retrieved 2009-10-13)
    +# > Urumqi fire seven people are missing the alleged losses of at least
    +# > 500 million yuan
    +# >
    +# > (Reporter Dong Liu) the day before 20:20 or so (Urumqi Time 18:20),
    +# > Urumqi City Department of International Plaza Luther Qiantang River
    +# > burst fire. As of yesterday, 18:30, Urumqi City Fire officers and men
    +# > have worked continuously for 22 hours...
    +
    +# From Luther Ma (2009-11-19):
    +# With the risk of being redundant to previous answers these are the most common
    +# English "transliterations" (w/o using non-English symbols):
    +#
    +# 1. Wulumuqi...
    +# 2. Kashi...
    +# 3. Urumqi...
    +# 4. Kashgar...
    +# ...
    +# 5. It seems that Uyghurs in Urumqi has been using Xinjiang since at least the
    +# 1960's. I know of one Han, now over 50, who grew up in the surrounding
    +# countryside and used Xinjiang time as a child.
    +#
    +# 6. Likewise for Kashgar and the rest of south Xinjiang I don't know of any
    +# start date for Xinjiang time.
    +#
    +# Without having access to local historical records, nor the ability to legally
    +# publish them, I would go with October 1, 1949, when Xinjiang became the Uyghur
    +# Autonomous Region under the PRC. (Before that Uyghurs, of course, would also
    +# not be using Beijing time, but some local time.)
    +
    +Zone	Asia/Kashgar	5:03:56	-	LMT	1928 # or Kashi or Kaxgar
    +			5:30	-	KAST	1940	 # Kashgar Time
    +			5:00	-	KAST	1980 May
    +			8:00	PRC	C%sT
    +
    +
    +# From Lee Yiu Chung (2009-10-24):
    +# I found there are some mistakes for the...DST rule for Hong
    +# Kong. [According] to the DST record from Hong Kong Observatory (actually,
    +# it is not [an] observatory, but the official meteorological agency of HK,
    +# and also serves as the official timing agency), there are some missing
    +# and incorrect rules. Although the exact switch over time is missing, I
    +# think 3:30 is correct. The official DST record for Hong Kong can be
    +# obtained from
    +# 
    +# http://www.hko.gov.hk/gts/time/Summertime.htm
    +# .
    +
    +# From Arthur David Olson (2009-10-28):
    +# Here are the dates given at
    +# 
    +# http://www.hko.gov.hk/gts/time/Summertime.htm
    +# 
    +# as of 2009-10-28:
    +# Year        Period
    +# 1941        1 Apr to 30 Sep
    +# 1942        Whole year
    +# 1943        Whole year
    +# 1944        Whole year
    +# 1945        Whole year
    +# 1946        20 Apr to 1 Dec
    +# 1947        13 Apr to 30 Dec
    +# 1948        2 May to 31 Oct
    +# 1949        3 Apr to 30 Oct
    +# 1950        2 Apr to 29 Oct
    +# 1951        1 Apr to 28 Oct
    +# 1952        6 Apr to 25 Oct
    +# 1953        5 Apr to 1 Nov
    +# 1954        21 Mar to 31 Oct
    +# 1955        20 Mar to 6 Nov
    +# 1956        18 Mar to 4 Nov
    +# 1957        24 Mar to 3 Nov
    +# 1958        23 Mar to 2 Nov
    +# 1959        22 Mar to 1 Nov
    +# 1960        20 Mar to 6 Nov
    +# 1961        19 Mar to 5 Nov
    +# 1962        18 Mar to 4 Nov
    +# 1963        24 Mar to 3 Nov
    +# 1964        22 Mar to 1 Nov
    +# 1965        18 Apr to 17 Oct
    +# 1966        17 Apr to 16 Oct
    +# 1967        16 Apr to 22 Oct
    +# 1968        21 Apr to 20 Oct
    +# 1969        20 Apr to 19 Oct
    +# 1970        19 Apr to 18 Oct
    +# 1971        18 Apr to 17 Oct
    +# 1972        16 Apr to 22 Oct
    +# 1973        22 Apr to 21 Oct
    +# 1973/74     30 Dec 73 to 20 Oct 74
    +# 1975        20 Apr to 19 Oct
    +# 1976        18 Apr to 17 Oct
    +# 1977        Nil
    +# 1978        Nil
    +# 1979        13 May to 21 Oct
    +# 1980 to Now Nil
    +# The page does not give start or end times of day.
    +# The page does not give a start date for 1942.
    +# The page does not givw an end date for 1945.
    +# The Japanese occupation of Hong Kong began on 1941-12-25.
    +# The Japanese surrender of Hong Kong was signed 1945-09-15.
    +# For lack of anything better, use start of those days as the transition times.
    +
    +# Hong Kong (Xianggang)
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	HK	1941	only	-	Apr	1	3:30	1:00	S
    +Rule	HK	1941	only	-	Sep	30	3:30	0	-
    +Rule	HK	1946	only	-	Apr	20	3:30	1:00	S
    +Rule	HK	1946	only	-	Dec	1	3:30	0	-
    +Rule	HK	1947	only	-	Apr	13	3:30	1:00	S
    +Rule	HK	1947	only	-	Dec	30	3:30	0	-
    +Rule	HK	1948	only	-	May	2	3:30	1:00	S
    +Rule	HK	1948	1951	-	Oct	lastSun	3:30	0	-
    +Rule	HK	1952	only	-	Oct	25	3:30	0	-
    +Rule	HK	1949	1953	-	Apr	Sun>=1	3:30	1:00	S
    +Rule	HK	1953	only	-	Nov	1	3:30	0	-
    +Rule	HK	1954	1964	-	Mar	Sun>=18	3:30	1:00	S
    +Rule	HK	1954	only	-	Oct	31	3:30	0	-
    +Rule	HK	1955	1964	-	Nov	Sun>=1	3:30	0	-
    +Rule	HK	1965	1976	-	Apr	Sun>=16	3:30	1:00	S
    +Rule	HK	1965	1976	-	Oct	Sun>=16	3:30	0	-
    +Rule	HK	1973	only	-	Dec	30	3:30	1:00	S
    +Rule	HK	1979	only	-	May	Sun>=8	3:30	1:00	S
    +Rule	HK	1979	only	-	Oct	Sun>=16	3:30	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Hong_Kong	7:36:36 -	LMT	1904 Oct 30
    +			8:00	HK	HK%sT	1941 Dec 25
    +			9:00	-	JST	1945 Sep 15
    +			8:00	HK	HK%sT
    +
    +###############################################################################
    +
    +# Taiwan
    +
    +# Shanks & Pottenger write that Taiwan observed DST during 1945, when it
    +# was still controlled by Japan.  This is hard to believe, but we don't
    +# have any other information.
    +
    +# From smallufo (2010-04-03):
    +# According to Taiwan's CWB,
    +# 
    +# http://www.cwb.gov.tw/V6/astronomy/cdata/summert.htm
    +# 
    +# Taipei has DST in 1979 between July 1st and Sep 30.
    +
    +# From Arthur David Olson (2010-04-07):
    +# Here's Google's translation of the table at the bottom of the "summert.htm" page:
    +# Decade 	                                                    Name                      Start and end date
    +# Republic of China 34 years to 40 years (AD 1945-1951 years) Summer Time               May 1 to September 30
    +# 41 years of the Republic of China (AD 1952)                 Daylight Saving Time      March 1 to October 31
    +# Republic of China 42 years to 43 years (AD 1953-1954 years) Daylight Saving Time      April 1 to October 31
    +# In the 44 years to 45 years (AD 1955-1956 years)            Daylight Saving Time      April 1 to September 30
    +# Republic of China 46 years to 48 years (AD 1957-1959)       Summer Time               April 1 to September 30
    +# Republic of China 49 years to 50 years (AD 1960-1961)       Summer Time               June 1 to September 30
    +# Republic of China 51 years to 62 years (AD 1962-1973 years) Stop Summer Time
    +# Republic of China 63 years to 64 years (1974-1975 AD)       Daylight Saving Time      April 1 to September 30
    +# Republic of China 65 years to 67 years (1976-1978 AD)       Stop Daylight Saving Time
    +# Republic of China 68 years (AD 1979)                        Daylight Saving Time      July 1 to September 30
    +# Republic of China since 69 years (AD 1980)                  Stop Daylight Saving Time
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Taiwan	1945	1951	-	May	1	0:00	1:00	D
    +Rule	Taiwan	1945	1951	-	Oct	1	0:00	0	S
    +Rule	Taiwan	1952	only	-	Mar	1	0:00	1:00	D
    +Rule	Taiwan	1952	1954	-	Nov	1	0:00	0	S
    +Rule	Taiwan	1953	1959	-	Apr	1	0:00	1:00	D
    +Rule	Taiwan	1955	1961	-	Oct	1	0:00	0	S
    +Rule	Taiwan	1960	1961	-	Jun	1	0:00	1:00	D
    +Rule	Taiwan	1974	1975	-	Apr	1	0:00	1:00	D
    +Rule	Taiwan	1974	1975	-	Oct	1	0:00	0	S
    +Rule	Taiwan	1979	only	-	Jun	30	0:00	1:00	D
    +Rule	Taiwan	1979	only	-	Sep	30	0:00	0	S
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Taipei	8:06:00 -	LMT	1896 # or Taibei or T'ai-pei
    +			8:00	Taiwan	C%sT
    +
    +# Macau (Macao, Aomen)
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Macau	1961	1962	-	Mar	Sun>=16	3:30	1:00	S
    +Rule	Macau	1961	1964	-	Nov	Sun>=1	3:30	0	-
    +Rule	Macau	1963	only	-	Mar	Sun>=16	0:00	1:00	S
    +Rule	Macau	1964	only	-	Mar	Sun>=16	3:30	1:00	S
    +Rule	Macau	1965	only	-	Mar	Sun>=16	0:00	1:00	S
    +Rule	Macau	1965	only	-	Oct	31	0:00	0	-
    +Rule	Macau	1966	1971	-	Apr	Sun>=16	3:30	1:00	S
    +Rule	Macau	1966	1971	-	Oct	Sun>=16	3:30	0	-
    +Rule	Macau	1972	1974	-	Apr	Sun>=15	0:00	1:00	S
    +Rule	Macau	1972	1973	-	Oct	Sun>=15	0:00	0	-
    +Rule	Macau	1974	1977	-	Oct	Sun>=15	3:30	0	-
    +Rule	Macau	1975	1977	-	Apr	Sun>=15	3:30	1:00	S
    +Rule	Macau	1978	1980	-	Apr	Sun>=15	0:00	1:00	S
    +Rule	Macau	1978	1980	-	Oct	Sun>=15	0:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Macau	7:34:20 -	LMT	1912
    +			8:00	Macau	MO%sT	1999 Dec 20 # return to China
    +			8:00	PRC	C%sT
    +
    +
    +###############################################################################
    +
    +# Cyprus
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Cyprus	1975	only	-	Apr	13	0:00	1:00	S
    +Rule	Cyprus	1975	only	-	Oct	12	0:00	0	-
    +Rule	Cyprus	1976	only	-	May	15	0:00	1:00	S
    +Rule	Cyprus	1976	only	-	Oct	11	0:00	0	-
    +Rule	Cyprus	1977	1980	-	Apr	Sun>=1	0:00	1:00	S
    +Rule	Cyprus	1977	only	-	Sep	25	0:00	0	-
    +Rule	Cyprus	1978	only	-	Oct	2	0:00	0	-
    +Rule	Cyprus	1979	1997	-	Sep	lastSun	0:00	0	-
    +Rule	Cyprus	1981	1998	-	Mar	lastSun	0:00	1:00	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Nicosia	2:13:28 -	LMT	1921 Nov 14
    +			2:00	Cyprus	EE%sT	1998 Sep
    +			2:00	EUAsia	EE%sT
    +# IATA SSIM (1998-09) has Cyprus using EU rules for the first time.
    +
    +# Classically, Cyprus belongs to Asia; e.g. see Herodotus, Histories, I.72.
    +# However, for various reasons many users expect to find it under Europe.
    +Link	Asia/Nicosia	Europe/Nicosia
    +
    +# Georgia
    +# From Paul Eggert (1994-11-19):
    +# Today's _Economist_ (p 60) reports that Georgia moved its clocks forward
    +# an hour recently, due to a law proposed by Zurab Murvanidze,
    +# an MP who went on a hunger strike for 11 days to force discussion about it!
    +# We have no details, but we'll guess they didn't move the clocks back in fall.
    +#
    +# From Mathew Englander, quoting AP (1996-10-23 13:05-04):
    +# Instead of putting back clocks at the end of October, Georgia
    +# will stay on daylight savings time this winter to save energy,
    +# President Eduard Shevardnadze decreed Wednesday.
    +#
    +# From the BBC via Joseph S. Myers (2004-06-27):
    +#
    +# Georgia moved closer to Western Europe on Sunday...  The former Soviet
    +# republic has changed its time zone back to that of Moscow.  As a result it
    +# is now just four hours ahead of Greenwich Mean Time, rather than five hours
    +# ahead.  The switch was decreed by the pro-Western president of Georgia,
    +# Mikhail Saakashvili, who said the change was partly prompted by the process
    +# of integration into Europe.
    +
    +# From Teimuraz Abashidze (2005-11-07):
    +# Government of Georgia ... decided to NOT CHANGE daylight savings time on
    +# [Oct.] 30, as it was done before during last more than 10 years.
    +# Currently, we are in fact GMT +4:00, as before 30 October it was GMT
    +# +3:00.... The problem is, there is NO FORMAL LAW or governmental document
    +# about it.  As far as I can find, I was told, that there is no document,
    +# because we just DIDN'T ISSUE document about switching to winter time....
    +# I don't know what can be done, especially knowing that some years ago our
    +# DST rules where changed THREE TIMES during one month.
    +
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Tbilisi	2:59:16 -	LMT	1880
    +			2:59:16	-	TBMT	1924 May  2 # Tbilisi Mean Time
    +			3:00	-	TBIT	1957 Mar    # Tbilisi Time
    +			4:00 RussiaAsia TBI%sT	1991 Mar 31 2:00s
    +			3:00	1:00	TBIST	1991 Apr  9 # independence
    +			3:00 RussiaAsia GE%sT	1992 # Georgia Time
    +			3:00 E-EurAsia	GE%sT	1994 Sep lastSun
    +			4:00 E-EurAsia	GE%sT	1996 Oct lastSun
    +			4:00	1:00	GEST	1997 Mar lastSun
    +			4:00 E-EurAsia	GE%sT	2004 Jun 27
    +			3:00 RussiaAsia	GE%sT	2005 Mar lastSun 2:00
    +			4:00	-	GET
    +
    +# East Timor
    +
    +# See Indonesia for the 1945 transition.
    +
    +# From Joao Carrascalao, brother of the former governor of East Timor, in
    +# 
    +# East Timor may be late for its millennium
    +#  (1999-12-26/31):
    +# Portugal tried to change the time forward in 1974 because the sun
    +# rises too early but the suggestion raised a lot of problems with the
    +# Timorese and I still don't think it would work today because it
    +# conflicts with their way of life.
    +
    +# From Paul Eggert (2000-12-04):
    +# We don't have any record of the above attempt.
    +# Most likely our records are incomplete, but we have no better data.
    +
    +# 
    +# From Manoel de Almeida e Silva, Deputy Spokesman for the UN Secretary-General
    +# (2000-08-16):
    +# The Cabinet of the East Timor Transition Administration decided
    +# today to advance East Timor's time by one hour.  The time change,
    +# which will be permanent, with no seasonal adjustment, will happen at
    +# midnight on Saturday, September 16.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Dili	8:22:20 -	LMT	1912
    +			8:00	-	TLT	1942 Feb 21 23:00 # E Timor Time
    +			9:00	-	JST	1945 Sep 23
    +			9:00	-	TLT	1976 May  3
    +			8:00	-	CIT	2000 Sep 17 00:00
    +			9:00	-	TLT
    +
    +# India
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Kolkata	5:53:28 -	LMT	1880	# Kolkata
    +			5:53:20	-	HMT	1941 Oct    # Howrah Mean Time?
    +			6:30	-	BURT	1942 May 15 # Burma Time
    +			5:30	-	IST	1942 Sep
    +			5:30	1:00	IST	1945 Oct 15
    +			5:30	-	IST
    +# The following are like Asia/Kolkata:
    +#	Andaman Is
    +#	Lakshadweep (Laccadive, Minicoy and Amindivi Is)
    +#	Nicobar Is
    +
    +# Indonesia
    +#
    +# From Gwillim Law (2001-05-28), overriding Shanks & Pottenger:
    +# 
    +# says that Indonesia's time zones changed on 1988-01-01.  Looking at some
    +# time zone maps, I think that must refer to Western Borneo (Kalimantan Barat
    +# and Kalimantan Tengah) switching from UTC+8 to UTC+7.
    +#
    +# From Paul Eggert (2007-03-10):
    +# Here is another correction to Shanks & Pottenger.
    +# JohnTWB writes that Japanese forces did not surrender control in
    +# Indonesia until 1945-09-01 00:00 at the earliest (in Jakarta) and
    +# other formal surrender ceremonies were September 9, 11, and 13, plus
    +# September 12 for the regional surrender to Mountbatten in Singapore.
    +# These would be the earliest possible times for a change.
    +# Regimes horaires pour le monde entier, by Henri Le Corre, (Editions
    +# Traditionnelles, 1987, Paris) says that Java and Madura switched
    +# from JST to UTC+07:30 on 1945-09-23, and gives 1944-09-01 for Jayapura
    +# (Hollandia).  For now, assume all Indonesian locations other than Jayapura
    +# switched on 1945-09-23.
    +#
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Asia/Jakarta	7:07:12 -	LMT	1867 Aug 10
    +# Shanks & Pottenger say the next transition was at 1924 Jan 1 0:13,
    +# but this must be a typo.
    +			7:07:12	-	JMT	1923 Dec 31 23:47:12 # Jakarta
    +			7:20	-	JAVT	1932 Nov	 # Java Time
    +			7:30	-	WIT	1942 Mar 23
    +			9:00	-	JST	1945 Sep 23
    +			7:30	-	WIT	1948 May
    +			8:00	-	WIT	1950 May
    +			7:30	-	WIT	1964
    +			7:00	-	WIT
    +Zone Asia/Pontianak	7:17:20	-	LMT	1908 May
    +			7:17:20	-	PMT	1932 Nov    # Pontianak MT
    +			7:30	-	WIT	1942 Jan 29
    +			9:00	-	JST	1945 Sep 23
    +			7:30	-	WIT	1948 May
    +			8:00	-	WIT	1950 May
    +			7:30	-	WIT	1964
    +			8:00	-	CIT	1988 Jan  1
    +			7:00	-	WIT
    +Zone Asia/Makassar	7:57:36 -	LMT	1920
    +			7:57:36	-	MMT	1932 Nov    # Macassar MT
    +			8:00	-	CIT	1942 Feb  9
    +			9:00	-	JST	1945 Sep 23
    +			8:00	-	CIT
    +Zone Asia/Jayapura	9:22:48 -	LMT	1932 Nov
    +			9:00	-	EIT	1944 Sep  1
    +			9:30	-	CST	1964
    +			9:00	-	EIT
    +
    +# Iran
    +
    +# From Roozbeh Pournader (2003-03-15):
    +# This is an English translation of what I just found (originally in Persian).
    +# The Gregorian dates in brackets are mine:
    +#
    +#	Official Newspaper No. 13548-1370/6/25 [1991-09-16]
    +#	No. 16760/T233 H				1370/6/10 [1991-09-01]
    +#
    +#	The Rule About Change of the Official Time of the Country
    +#
    +#	The Board of Ministers, in the meeting dated 1370/5/23 [1991-08-14],
    +#	based on the suggestion number 2221/D dated 1370/4/22 [1991-07-13]
    +#	of the Country's Organization for Official and Employment Affairs,
    +#	and referring to the law for equating the working hours of workers
    +#	and officers in the whole country dated 1359/4/23 [1980-07-14], and
    +#	for synchronizing the official times of the country, agreed that:
    +#
    +#	The official time of the country will should move forward one hour
    +#	at the 24[:00] hours of the first day of Farvardin and should return
    +#	to its previous state at the 24[:00] hours of the 30th day of
    +#	Shahrivar.
    +#
    +#	First Deputy to the President - Hassan Habibi
    +#
    +# From personal experience, that agrees with what has been followed
    +# for at least the last 5 years.  Before that, for a few years, the
    +# date used was the first Thursday night of Farvardin and the last
    +# Thursday night of Shahrivar, but I can't give exact dates....
    +# I have also changed the abbreviations to what is considered correct
    +# here in Iran, IRST for regular time and IRDT for daylight saving time.
    +#
    +# From Roozbeh Pournader (2005-04-05):
    +# The text of the Iranian law, in effect since 1925, clearly mentions
    +# that the true solar year is the measure, and there is no arithmetic
    +# leap year calculation involved.  There has never been any serious
    +# plan to change that law....
    +#
    +# From Paul Eggert (2006-03-22):
    +# Go with Shanks & Pottenger before Sept. 1991, and with Pournader thereafter.
    +# I used Ed Reingold's cal-persia in GNU Emacs 21.2 to check Persian dates,
    +# stopping after 2037 when 32-bit time_t's overflow.
    +# That cal-persia used Birashk's approximation, which disagrees with the solar
    +# calendar predictions for the year 2025, so I corrected those dates by hand.
    +#
    +# From Oscar van Vlijmen (2005-03-30), writing about future
    +# discrepancies between cal-persia and the Iranian calendar:
    +# For 2091 solar-longitude-after yields 2091-03-20 08:40:07.7 UT for
    +# the vernal equinox and that gets so close to 12:00 some local
    +# Iranian time that the definition of the correct location needs to be
    +# known exactly, amongst other factors.  2157 is even closer:
    +# 2157-03-20 08:37:15.5 UT.  But the Gregorian year 2025 should give
    +# no interpretation problem whatsoever.  By the way, another instant
    +# in the near future where there will be a discrepancy between
    +# arithmetical and astronomical Iranian calendars will be in 2058:
    +# vernal equinox on 2058-03-20 09:03:05.9 UT.  The Java version of
    +# Reingold's/Dershowitz' calculator gives correctly the Gregorian date
    +# 2058-03-21 for 1 Farvardin 1437 (astronomical).
    +#
    +# From Steffen Thorsen (2006-03-22):
    +# Several of my users have reported that Iran will not observe DST anymore:
    +# http://www.irna.ir/en/news/view/line-17/0603193812164948.htm
    +#
    +# From Reuters (2007-09-16), with a heads-up from Jesper Norgaard Welen:
    +# ... the Guardian Council ... approved a law on Sunday to re-introduce
    +# daylight saving time ...
    +# http://uk.reuters.com/article/oilRpt/idUKBLA65048420070916
    +#
    +# From Roozbeh Pournader (2007-11-05):
    +# This is quoted from Official Gazette of the Islamic Republic of
    +# Iran, Volume 63, Number 18242, dated Tuesday 1386/6/24
    +# [2007-10-16]. I am doing the best translation I can:...
    +# The official time of the country will be moved forward for one hour
    +# on the 24 hours of the first day of the month of Farvardin and will
    +# be changed back to its previous state on the 24 hours of the
    +# thirtieth day of Shahrivar.
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Iran	1978	1980	-	Mar	21	0:00	1:00	D
    +Rule	Iran	1978	only	-	Oct	21	0:00	0	S
    +Rule	Iran	1979	only	-	Sep	19	0:00	0	S
    +Rule	Iran	1980	only	-	Sep	23	0:00	0	S
    +Rule	Iran	1991	only	-	May	 3	0:00	1:00	D
    +Rule	Iran	1992	1995	-	Mar	22	0:00	1:00	D
    +Rule	Iran	1991	1995	-	Sep	22	0:00	0	S
    +Rule	Iran	1996	only	-	Mar	21	0:00	1:00	D
    +Rule	Iran	1996	only	-	Sep	21	0:00	0	S
    +Rule	Iran	1997	1999	-	Mar	22	0:00	1:00	D
    +Rule	Iran	1997	1999	-	Sep	22	0:00	0	S
    +Rule	Iran	2000	only	-	Mar	21	0:00	1:00	D
    +Rule	Iran	2000	only	-	Sep	21	0:00	0	S
    +Rule	Iran	2001	2003	-	Mar	22	0:00	1:00	D
    +Rule	Iran	2001	2003	-	Sep	22	0:00	0	S
    +Rule	Iran	2004	only	-	Mar	21	0:00	1:00	D
    +Rule	Iran	2004	only	-	Sep	21	0:00	0	S
    +Rule	Iran	2005	only	-	Mar	22	0:00	1:00	D
    +Rule	Iran	2005	only	-	Sep	22	0:00	0	S
    +Rule	Iran	2008	only	-	Mar	21	0:00	1:00	D
    +Rule	Iran	2008	only	-	Sep	21	0:00	0	S
    +Rule	Iran	2009	2011	-	Mar	22	0:00	1:00	D
    +Rule	Iran	2009	2011	-	Sep	22	0:00	0	S
    +Rule	Iran	2012	only	-	Mar	21	0:00	1:00	D
    +Rule	Iran	2012	only	-	Sep	21	0:00	0	S
    +Rule	Iran	2013	2015	-	Mar	22	0:00	1:00	D
    +Rule	Iran	2013	2015	-	Sep	22	0:00	0	S
    +Rule	Iran	2016	only	-	Mar	21	0:00	1:00	D
    +Rule	Iran	2016	only	-	Sep	21	0:00	0	S
    +Rule	Iran	2017	2019	-	Mar	22	0:00	1:00	D
    +Rule	Iran	2017	2019	-	Sep	22	0:00	0	S
    +Rule	Iran	2020	only	-	Mar	21	0:00	1:00	D
    +Rule	Iran	2020	only	-	Sep	21	0:00	0	S
    +Rule	Iran	2021	2023	-	Mar	22	0:00	1:00	D
    +Rule	Iran	2021	2023	-	Sep	22	0:00	0	S
    +Rule	Iran	2024	only	-	Mar	21	0:00	1:00	D
    +Rule	Iran	2024	only	-	Sep	21	0:00	0	S
    +Rule	Iran	2025	2027	-	Mar	22	0:00	1:00	D
    +Rule	Iran	2025	2027	-	Sep	22	0:00	0	S
    +Rule	Iran	2028	2029	-	Mar	21	0:00	1:00	D
    +Rule	Iran	2028	2029	-	Sep	21	0:00	0	S
    +Rule	Iran	2030	2031	-	Mar	22	0:00	1:00	D
    +Rule	Iran	2030	2031	-	Sep	22	0:00	0	S
    +Rule	Iran	2032	2033	-	Mar	21	0:00	1:00	D
    +Rule	Iran	2032	2033	-	Sep	21	0:00	0	S
    +Rule	Iran	2034	2035	-	Mar	22	0:00	1:00	D
    +Rule	Iran	2034	2035	-	Sep	22	0:00	0	S
    +Rule	Iran	2036	2037	-	Mar	21	0:00	1:00	D
    +Rule	Iran	2036	2037	-	Sep	21	0:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Tehran	3:25:44	-	LMT	1916
    +			3:25:44	-	TMT	1946	# Tehran Mean Time
    +			3:30	-	IRST	1977 Nov
    +			4:00	Iran	IR%sT	1979
    +			3:30	Iran	IR%sT
    +
    +
    +# Iraq
    +#
    +# From Jonathan Lennox (2000-06-12):
    +# An article in this week's Economist ("Inside the Saddam-free zone", p. 50 in
    +# the U.S. edition) on the Iraqi Kurds contains a paragraph:
    +# "The three northern provinces ... switched their clocks this spring and
    +# are an hour ahead of Baghdad."
    +#
    +# But Rives McDow (2000-06-18) quotes a contact in Iraqi-Kurdistan as follows:
    +# In the past, some Kurdish nationalists, as a protest to the Iraqi
    +# Government, did not adhere to daylight saving time.  They referred
    +# to daylight saving as Saddam time.  But, as of today, the time zone
    +# in Iraqi-Kurdistan is on standard time with Baghdad, Iraq.
    +#
    +# So we'll ignore the Economist's claim.
    +
    +# From Steffen Thorsen (2008-03-10):
    +# The cabinet in Iraq abolished DST last week, according to the following
    +# news sources (in Arabic):
    +# 
    +# http://www.aljeeran.net/wesima_articles/news-20080305-98602.html
    +# 
    +# 
    +# http://www.aswataliraq.info/look/article.tpl?id=2047&IdLanguage=17&IdPublication=4&NrArticle=71743&NrIssue=1&NrSection=10
    +# 
    +#
    +# We have published a short article in English about the change:
    +# 
    +# http://www.timeanddate.com/news/time/iraq-dumps-daylight-saving.html
    +# 
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Iraq	1982	only	-	May	1	0:00	1:00	D
    +Rule	Iraq	1982	1984	-	Oct	1	0:00	0	S
    +Rule	Iraq	1983	only	-	Mar	31	0:00	1:00	D
    +Rule	Iraq	1984	1985	-	Apr	1	0:00	1:00	D
    +Rule	Iraq	1985	1990	-	Sep	lastSun	1:00s	0	S
    +Rule	Iraq	1986	1990	-	Mar	lastSun	1:00s	1:00	D
    +# IATA SSIM (1991/1996) says Apr 1 12:01am UTC; guess the `:01' is a typo.
    +# Shanks & Pottenger say Iraq did not observe DST 1992/1997; ignore this.
    +#
    +Rule	Iraq	1991	2007	-	Apr	 1	3:00s	1:00	D
    +Rule	Iraq	1991	2007	-	Oct	 1	3:00s	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Baghdad	2:57:40	-	LMT	1890
    +			2:57:36	-	BMT	1918	    # Baghdad Mean Time?
    +			3:00	-	AST	1982 May
    +			3:00	Iraq	A%sT
    +
    +
    +###############################################################################
    +
    +# Israel
    +
    +# From Ephraim Silverberg (2001-01-11):
    +#
    +# I coined "IST/IDT" circa 1988.  Until then there were three
    +# different abbreviations in use:
    +#
    +# JST  Jerusalem Standard Time [Danny Braniss, Hebrew University]
    +# IZT  Israel Zonal (sic) Time [Prof. Haim Papo, Technion]
    +# EEST Eastern Europe Standard Time [used by almost everyone else]
    +#
    +# Since timezones should be called by country and not capital cities,
    +# I ruled out JST.  As Israel is in Asia Minor and not Eastern Europe,
    +# EEST was equally unacceptable.  Since "zonal" was not compatible with
    +# any other timezone abbreviation, I felt that 'IST' was the way to go
    +# and, indeed, it has received almost universal acceptance in timezone
    +# settings in Israeli computers.
    +#
    +# In any case, I am happy to share timezone abbreviations with India,
    +# high on my favorite-country list (and not only because my wife's
    +# family is from India).
    +
    +# From Shanks & Pottenger:
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Zion	1940	only	-	Jun	 1	0:00	1:00	D
    +Rule	Zion	1942	1944	-	Nov	 1	0:00	0	S
    +Rule	Zion	1943	only	-	Apr	 1	2:00	1:00	D
    +Rule	Zion	1944	only	-	Apr	 1	0:00	1:00	D
    +Rule	Zion	1945	only	-	Apr	16	0:00	1:00	D
    +Rule	Zion	1945	only	-	Nov	 1	2:00	0	S
    +Rule	Zion	1946	only	-	Apr	16	2:00	1:00	D
    +Rule	Zion	1946	only	-	Nov	 1	0:00	0	S
    +Rule	Zion	1948	only	-	May	23	0:00	2:00	DD
    +Rule	Zion	1948	only	-	Sep	 1	0:00	1:00	D
    +Rule	Zion	1948	1949	-	Nov	 1	2:00	0	S
    +Rule	Zion	1949	only	-	May	 1	0:00	1:00	D
    +Rule	Zion	1950	only	-	Apr	16	0:00	1:00	D
    +Rule	Zion	1950	only	-	Sep	15	3:00	0	S
    +Rule	Zion	1951	only	-	Apr	 1	0:00	1:00	D
    +Rule	Zion	1951	only	-	Nov	11	3:00	0	S
    +Rule	Zion	1952	only	-	Apr	20	2:00	1:00	D
    +Rule	Zion	1952	only	-	Oct	19	3:00	0	S
    +Rule	Zion	1953	only	-	Apr	12	2:00	1:00	D
    +Rule	Zion	1953	only	-	Sep	13	3:00	0	S
    +Rule	Zion	1954	only	-	Jun	13	0:00	1:00	D
    +Rule	Zion	1954	only	-	Sep	12	0:00	0	S
    +Rule	Zion	1955	only	-	Jun	11	2:00	1:00	D
    +Rule	Zion	1955	only	-	Sep	11	0:00	0	S
    +Rule	Zion	1956	only	-	Jun	 3	0:00	1:00	D
    +Rule	Zion	1956	only	-	Sep	30	3:00	0	S
    +Rule	Zion	1957	only	-	Apr	29	2:00	1:00	D
    +Rule	Zion	1957	only	-	Sep	22	0:00	0	S
    +Rule	Zion	1974	only	-	Jul	 7	0:00	1:00	D
    +Rule	Zion	1974	only	-	Oct	13	0:00	0	S
    +Rule	Zion	1975	only	-	Apr	20	0:00	1:00	D
    +Rule	Zion	1975	only	-	Aug	31	0:00	0	S
    +Rule	Zion	1985	only	-	Apr	14	0:00	1:00	D
    +Rule	Zion	1985	only	-	Sep	15	0:00	0	S
    +Rule	Zion	1986	only	-	May	18	0:00	1:00	D
    +Rule	Zion	1986	only	-	Sep	 7	0:00	0	S
    +Rule	Zion	1987	only	-	Apr	15	0:00	1:00	D
    +Rule	Zion	1987	only	-	Sep	13	0:00	0	S
    +Rule	Zion	1988	only	-	Apr	 9	0:00	1:00	D
    +Rule	Zion	1988	only	-	Sep	 3	0:00	0	S
    +
    +# From Ephraim Silverberg
    +# (1997-03-04, 1998-03-16, 1998-12-28, 2000-01-17, 2000-07-25, 2004-12-22,
    +# and 2005-02-17):
    +
    +# According to the Office of the Secretary General of the Ministry of
    +# Interior, there is NO set rule for Daylight-Savings/Standard time changes.
    +# One thing is entrenched in law, however: that there must be at least 150
    +# days of daylight savings time annually.  From 1993-1998, the change to
    +# daylight savings time was on a Friday morning from midnight IST to
    +# 1 a.m IDT; up until 1998, the change back to standard time was on a
    +# Saturday night from midnight daylight savings time to 11 p.m. standard
    +# time.  1996 is an exception to this rule where the change back to standard
    +# time took place on Sunday night instead of Saturday night to avoid
    +# conflicts with the Jewish New Year.  In 1999, the change to
    +# daylight savings time was still on a Friday morning but from
    +# 2 a.m. IST to 3 a.m. IDT; furthermore, the change back to standard time
    +# was also on a Friday morning from 2 a.m. IDT to 1 a.m. IST for
    +# 1999 only.  In the year 2000, the change to daylight savings time was
    +# similar to 1999, but although the change back will be on a Friday, it
    +# will take place from 1 a.m. IDT to midnight IST.  Starting in 2001, all
    +# changes to/from will take place at 1 a.m. old time, but now there is no
    +# rule as to what day of the week it will take place in as the start date
    +# (except in 2003) is the night after the Passover Seder (i.e. the eve
    +# of the 16th of Nisan in the lunar Hebrew calendar) and the end date
    +# (except in 2002) is three nights before Yom Kippur [Day of Atonement]
    +# (the eve of the 7th of Tishrei in the lunar Hebrew calendar).
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Zion	1989	only	-	Apr	30	0:00	1:00	D
    +Rule	Zion	1989	only	-	Sep	 3	0:00	0	S
    +Rule	Zion	1990	only	-	Mar	25	0:00	1:00	D
    +Rule	Zion	1990	only	-	Aug	26	0:00	0	S
    +Rule	Zion	1991	only	-	Mar	24	0:00	1:00	D
    +Rule	Zion	1991	only	-	Sep	 1	0:00	0	S
    +Rule	Zion	1992	only	-	Mar	29	0:00	1:00	D
    +Rule	Zion	1992	only	-	Sep	 6	0:00	0	S
    +Rule	Zion	1993	only	-	Apr	 2	0:00	1:00	D
    +Rule	Zion	1993	only	-	Sep	 5	0:00	0	S
    +
    +# The dates for 1994-1995 were obtained from Office of the Spokeswoman for the
    +# Ministry of Interior, Jerusalem, Israel.  The spokeswoman can be reached by
    +# calling the office directly at 972-2-6701447 or 972-2-6701448.
    +
    +# Rule	NAME    FROM    TO      TYPE    IN      ON      AT      SAVE    LETTER/S
    +Rule	Zion	1994	only	-	Apr	 1	0:00	1:00	D
    +Rule	Zion	1994	only	-	Aug	28	0:00	0	S
    +Rule	Zion	1995	only	-	Mar	31	0:00	1:00	D
    +Rule	Zion	1995	only	-	Sep	 3	0:00	0	S
    +
    +# The dates for 1996 were determined by the Minister of Interior of the
    +# time, Haim Ramon.  The official announcement regarding 1996-1998
    +# (with the dates for 1997-1998 no longer being relevant) can be viewed at:
    +#
    +#   ftp://ftp.cs.huji.ac.il/pub/tz/announcements/1996-1998.ramon.ps.gz
    +#
    +# The dates for 1997-1998 were altered by his successor, Rabbi Eli Suissa.
    +#
    +# The official announcements for the years 1997-1999 can be viewed at:
    +#
    +#   ftp://ftp.cs.huji.ac.il/pub/tz/announcements/YYYY.ps.gz
    +#
    +#       where YYYY is the relevant year.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Zion	1996	only	-	Mar	15	0:00	1:00	D
    +Rule	Zion	1996	only	-	Sep	16	0:00	0	S
    +Rule	Zion	1997	only	-	Mar	21	0:00	1:00	D
    +Rule	Zion	1997	only	-	Sep	14	0:00	0	S
    +Rule	Zion	1998	only	-	Mar	20	0:00	1:00	D
    +Rule	Zion	1998	only	-	Sep	 6	0:00	0	S
    +Rule	Zion	1999	only	-	Apr	 2	2:00	1:00	D
    +Rule	Zion	1999	only	-	Sep	 3	2:00	0	S
    +
    +# The Knesset Interior Committee has changed the dates for 2000 for
    +# the third time in just over a year and have set new dates for the
    +# years 2001-2004 as well.
    +#
    +# The official announcement for the start date of 2000 can be viewed at:
    +#
    +#	ftp://ftp.cs.huji.ac.il/pub/tz/announcements/2000-start.ps.gz
    +#
    +# The official announcement for the end date of 2000 and the dates
    +# for the years 2001-2004 can be viewed at:
    +#
    +#	ftp://ftp.cs.huji.ac.il/pub/tz/announcements/2000-2004.ps.gz
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Zion	2000	only	-	Apr	14	2:00	1:00	D
    +Rule	Zion	2000	only	-	Oct	 6	1:00	0	S
    +Rule	Zion	2001	only	-	Apr	 9	1:00	1:00	D
    +Rule	Zion	2001	only	-	Sep	24	1:00	0	S
    +Rule	Zion	2002	only	-	Mar	29	1:00	1:00	D
    +Rule	Zion	2002	only	-	Oct	 7	1:00	0	S
    +Rule	Zion	2003	only	-	Mar	28	1:00	1:00	D
    +Rule	Zion	2003	only	-	Oct	 3	1:00	0	S
    +Rule	Zion	2004	only	-	Apr	 7	1:00	1:00	D
    +Rule	Zion	2004	only	-	Sep	22	1:00	0	S
    +
    +# The proposed law agreed upon by the Knesset Interior Committee on
    +# 2005-02-14 is that, for 2005 and beyond, DST starts at 02:00 the
    +# last Friday before April 2nd (i.e. the last Friday in March or April
    +# 1st itself if it falls on a Friday) and ends at 02:00 on the Saturday
    +# night _before_ the fast of Yom Kippur.
    +#
    +# Those who can read Hebrew can view the announcement at:
    +#
    +#	ftp://ftp.cs.huji.ac.il/pub/tz/announcements/2005+beyond.ps
    +
    +# From Paul Eggert (2012-10-26):
    +# I used Ephraim Silverberg's dst-israel.el program
    +#  (2005-02-20)
    +# along with Ed Reingold's cal-hebrew in GNU Emacs 21.4,
    +# to generate the transitions from 2005 through 2012.
    +# (I replaced "lastFri" with "Fri>=26" by hand.)
    +# The spring transitions all correspond to the following Rule:
    +#
    +# Rule	Zion	2005	2012	-	Mar	Fri>=26	2:00	1:00	D
    +#
    +# but older zic implementations (e.g., Solaris 8) do not support
    +# "Fri>=26" to mean April 1 in years like 2005, so for now we list the
    +# springtime transitions explicitly.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Zion	2005	only	-	Apr	 1	2:00	1:00	D
    +Rule	Zion	2005	only	-	Oct	 9	2:00	0	S
    +Rule	Zion	2006	2010	-	Mar	Fri>=26	2:00	1:00	D
    +Rule	Zion	2006	only	-	Oct	 1	2:00	0	S
    +Rule	Zion	2007	only	-	Sep	16	2:00	0	S
    +Rule	Zion	2008	only	-	Oct	 5	2:00	0	S
    +Rule	Zion	2009	only	-	Sep	27	2:00	0	S
    +Rule	Zion	2010	only	-	Sep	12	2:00	0	S
    +Rule	Zion	2011	only	-	Apr	 1	2:00	1:00	D
    +Rule	Zion	2011	only	-	Oct	 2	2:00	0	S
    +Rule	Zion	2012	only	-	Mar	Fri>=26	2:00	1:00	D
    +Rule	Zion	2012	only	-	Sep	23	2:00	0	S
    +
    +# From Ephraim Silverberg (2012-10-18):
    +
    +# Yesterday, the Interior Ministry Committee, after more than a year
    +# past, approved sending the proposed June 2011 changes to the Time
    +# Decree Law back to the Knesset for second and third (final) votes
    +# before the upcoming elections on Jan. 22, 2013.  Hence, although the
    +# changes are not yet law, they are expected to be so before February 2013.
    +#
    +# As of 2013, DST starts at 02:00 on the Friday before the last Sunday in March.
    +# DST ends at 02:00 on the first Sunday after October 1, unless it occurs on the
    +# second day of the Jewish Rosh Hashana holiday, in which case DST ends a day
    +# later (i.e. at 02:00 the first Monday after October 2).
    +# [Rosh Hashana holidays are factored in until 2100.]
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Zion	2013	max	-	Mar	Fri>=23	2:00	1:00	D
    +Rule	Zion	2013	2026	-	Oct	Sun>=2	2:00	0	S
    +Rule	Zion	2027	only	-	Oct	Mon>=3	2:00	0	S
    +Rule	Zion	2028	max	-	Oct	Sun>=2	2:00	0	S
    +# The following rules are commented out for now, as they break older
    +# versions of zic that support only signed 32-bit timestamps, i.e.,
    +# through 2038-01-19 03:14:07 UTC.
    +#Rule	Zion	2028	2053	-	Oct	Sun>=2	2:00	0	S
    +#Rule	Zion	2054	only	-	Oct	Mon>=3	2:00	0	S
    +#Rule	Zion	2055	2080	-	Oct	Sun>=2	2:00	0	S
    +#Rule	Zion	2081	only	-	Oct	Mon>=3	2:00	0	S
    +#Rule	Zion	2082	max	-	Oct	Sun>=2	2:00	0	S
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Jerusalem	2:20:56 -	LMT	1880
    +			2:20:40	-	JMT	1918	# Jerusalem Mean Time?
    +			2:00	Zion	I%sT
    +
    +
    +
    +###############################################################################
    +
    +# Japan
    +
    +# `9:00' and `JST' is from Guy Harris.
    +
    +# From Paul Eggert (1995-03-06):
    +# Today's _Asahi Evening News_ (page 4) reports that Japan had
    +# daylight saving between 1948 and 1951, but ``the system was discontinued
    +# because the public believed it would lead to longer working hours.''
    +
    +# From Mayumi Negishi in the 2005-08-10 Japan Times
    +# :
    +# Occupation authorities imposed daylight-saving time on Japan on
    +# [1948-05-01]....  But lack of prior debate and the execution of
    +# daylight-saving time just three days after the bill was passed generated
    +# deep hatred of the concept....  The Diet unceremoniously passed a bill to
    +# dump the unpopular system in October 1951, less than a month after the San
    +# Francisco Peace Treaty was signed.  (A government poll in 1951 showed 53%
    +# of the Japanese wanted to scrap daylight-saving time, as opposed to 30% who
    +# wanted to keep it.)
    +
    +# From Paul Eggert (2006-03-22):
    +# Shanks & Pottenger write that DST in Japan during those years was as follows:
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Japan	1948	only	-	May	Sun>=1	2:00	1:00	D
    +Rule	Japan	1948	1951	-	Sep	Sat>=8	2:00	0	S
    +Rule	Japan	1949	only	-	Apr	Sun>=1	2:00	1:00	D
    +Rule	Japan	1950	1951	-	May	Sun>=1	2:00	1:00	D
    +# but the only locations using it (for birth certificates, presumably, since
    +# their audience is astrologers) were US military bases.  For now, assume
    +# that for most purposes daylight-saving time was observed; otherwise, what
    +# would have been the point of the 1951 poll?
    +
    +# From Hideyuki Suzuki (1998-11-09):
    +# 'Tokyo' usually stands for the former location of Tokyo Astronomical
    +# Observatory: E 139 44' 40".90 (9h 18m 58s.727), N 35 39' 16".0.
    +# This data is from 'Rika Nenpyou (Chronological Scientific Tables) 1996'
    +# edited by National Astronomical Observatory of Japan....
    +# JST (Japan Standard Time) has been used since 1888-01-01 00:00 (JST).
    +# The law is enacted on 1886-07-07.
    +
    +# From Hideyuki Suzuki (1998-11-16):
    +# The ordinance No. 51 (1886) established "standard time" in Japan,
    +# which stands for the time on E 135 degree.
    +# In the ordinance No. 167 (1895), "standard time" was renamed to "central
    +# standard time".  And the same ordinance also established "western standard
    +# time", which stands for the time on E 120 degree....  But "western standard
    +# time" was abolished in the ordinance No. 529 (1937).  In the ordinance No.
    +# 167, there is no mention regarding for what place western standard time is
    +# standard....
    +#
    +# I wrote "ordinance" above, but I don't know how to translate.
    +# In Japanese it's "chokurei", which means ordinance from emperor.
    +
    +# Shanks & Pottenger claim JST in use since 1896, and that a few
    +# places (e.g. Ishigaki) use +0800; go with Suzuki.  Guess that all
    +# ordinances took effect on Jan 1.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Tokyo	9:18:59	-	LMT	1887 Dec 31 15:00u
    +			9:00	-	JST	1896
    +			9:00	-	CJT	1938
    +			9:00	Japan	J%sT
    +# Since 1938, all Japanese possessions have been like Asia/Tokyo.
    +
    +# Jordan
    +#
    +# From 
    +# Jordan Week (1999-07-01)  via Steffen Thorsen (1999-09-09):
    +# Clocks in Jordan were forwarded one hour on Wednesday at midnight,
    +# in accordance with the government's decision to implement summer time
    +# all year round.
    +#
    +# From 
    +# Jordan Week (1999-09-30)  via Steffen Thorsen (1999-11-09):
    +# Winter time starts today Thursday, 30 September. Clocks will be turned back
    +# by one hour.  This is the latest government decision and it's final!
    +# The decision was taken because of the increase in working hours in
    +# government's departments from six to seven hours.
    +#
    +# From Paul Eggert (2005-11-22):
    +# Starting 2003 transitions are from Steffen Thorsen's web site timeanddate.com.
    +#
    +# From Steffen Thorsen (2005-11-23):
    +# For Jordan I have received multiple independent user reports every year
    +# about DST end dates, as the end-rule is different every year.
    +#
    +# From Steffen Thorsen (2006-10-01), after a heads-up from Hilal Malawi:
    +# http://www.petranews.gov.jo/nepras/2006/Sep/05/4000.htm
    +# "Jordan will switch to winter time on Friday, October 27".
    +#
    +
    +# From Phil Pizzey (2009-04-02):
    +# ...I think I may have spotted an error in the timezone data for
    +# Jordan.
    +# The current (2009d) asia file shows Jordan going to daylight
    +# saving
    +# time on the last Thursday in March.
    +#
    +# Rule  Jordan      2000  max	-  Mar   lastThu     0:00s 1:00  S
    +#
    +# However timeanddate.com, which I usually find reliable, shows Jordan
    +# going to daylight saving time on the last Friday in March since 2002.
    +# Please see
    +# 
    +# http://www.timeanddate.com/worldclock/timezone.html?n=11
    +# 
    +
    +# From Steffen Thorsen (2009-04-02):
    +# This single one might be good enough, (2009-03-24, Arabic):
    +# 
    +# http://petra.gov.jo/Artical.aspx?Lng=2&Section=8&Artical=95279
    +# 
    +#
    +# Google's translation:
    +#
    +# > The Council of Ministers decided in 2002 to adopt the principle of timely
    +# > submission of the summer at 60 minutes as of midnight on the last Thursday
    +# > of the month of March of each year.
    +#
    +# So - this means the midnight between Thursday and Friday since 2002.
    +
    +# From Arthur David Olson (2009-04-06):
    +# We still have Jordan switching to DST on Thursdays in 2000 and 2001.
    +
    +# From Steffen Thorsen (2012-10-25):
    +# Yesterday the government in Jordan announced that they will not
    +# switch back to standard time this winter, so the will stay on DST
    +# until about the same time next year (at least).
    +# http://www.petra.gov.jo/Public_News/Nws_NewsDetails.aspx?NewsID=88950
    +#
    +# From Paul Eggert (2012-10-25):
    +# For now, assume this is just a one-year measure.  If it becomes
    +# permanent, we should move Jordan from EET to AST effective tomorrow.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Jordan	1973	only	-	Jun	6	0:00	1:00	S
    +Rule	Jordan	1973	1975	-	Oct	1	0:00	0	-
    +Rule	Jordan	1974	1977	-	May	1	0:00	1:00	S
    +Rule	Jordan	1976	only	-	Nov	1	0:00	0	-
    +Rule	Jordan	1977	only	-	Oct	1	0:00	0	-
    +Rule	Jordan	1978	only	-	Apr	30	0:00	1:00	S
    +Rule	Jordan	1978	only	-	Sep	30	0:00	0	-
    +Rule	Jordan	1985	only	-	Apr	1	0:00	1:00	S
    +Rule	Jordan	1985	only	-	Oct	1	0:00	0	-
    +Rule	Jordan	1986	1988	-	Apr	Fri>=1	0:00	1:00	S
    +Rule	Jordan	1986	1990	-	Oct	Fri>=1	0:00	0	-
    +Rule	Jordan	1989	only	-	May	8	0:00	1:00	S
    +Rule	Jordan	1990	only	-	Apr	27	0:00	1:00	S
    +Rule	Jordan	1991	only	-	Apr	17	0:00	1:00	S
    +Rule	Jordan	1991	only	-	Sep	27	0:00	0	-
    +Rule	Jordan	1992	only	-	Apr	10	0:00	1:00	S
    +Rule	Jordan	1992	1993	-	Oct	Fri>=1	0:00	0	-
    +Rule	Jordan	1993	1998	-	Apr	Fri>=1	0:00	1:00	S
    +Rule	Jordan	1994	only	-	Sep	Fri>=15	0:00	0	-
    +Rule	Jordan	1995	1998	-	Sep	Fri>=15	0:00s	0	-
    +Rule	Jordan	1999	only	-	Jul	 1	0:00s	1:00	S
    +Rule	Jordan	1999	2002	-	Sep	lastFri	0:00s	0	-
    +Rule	Jordan	2000	2001	-	Mar	lastThu	0:00s	1:00	S
    +Rule	Jordan	2002	max	-	Mar	lastThu	24:00	1:00	S
    +Rule	Jordan	2003	only	-	Oct	24	0:00s	0	-
    +Rule	Jordan	2004	only	-	Oct	15	0:00s	0	-
    +Rule	Jordan	2005	only	-	Sep	lastFri	0:00s	0	-
    +Rule	Jordan	2006	2011	-	Oct	lastFri	0:00s	0	-
    +Rule	Jordan	2013	max	-	Oct	lastFri	0:00s	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Amman	2:23:44 -	LMT	1931
    +			2:00	Jordan	EE%sT
    +
    +
    +# Kazakhstan
    +
    +# From Paul Eggert (1996-11-22):
    +# Andrew Evtichov (1996-04-13) writes that Kazakhstan
    +# stayed in sync with Moscow after 1990, and that Aqtobe (formerly Aktyubinsk)
    +# and Aqtau (formerly Shevchenko) are the largest cities in their zones.
    +# Guess that Aqtau and Aqtobe diverged in 1995, since that's the first time
    +# IATA SSIM mentions a third time zone in Kazakhstan.
    +
    +# From Paul Eggert (2006-03-22):
    +# German Iofis, ELSI, Almaty (2001-10-09) reports that Kazakhstan uses
    +# RussiaAsia rules, instead of switching at 00:00 as the IATA has it.
    +# Go with Shanks & Pottenger, who have them always using RussiaAsia rules.
    +# Also go with the following claims of Shanks & Pottenger:
    +#
    +# - Kazakhstan did not observe DST in 1991.
    +# - Qyzylorda switched from +5:00 to +6:00 on 1992-01-19 02:00.
    +# - Oral switched from +5:00 to +4:00 in spring 1989.
    +
    +# 
    +# From Kazakhstan Embassy's News Bulletin #11 (2005-03-21):
    +# 
    +# The Government of Kazakhstan passed a resolution March 15 abolishing
    +# daylight saving time citing lack of economic benefits and health
    +# complications coupled with a decrease in productivity.
    +#
    +# From Branislav Kojic (in Astana) via Gwillim Law (2005-06-28):
    +# ... what happened was that the former Kazakhstan Eastern time zone
    +# was "blended" with the Central zone.  Therefore, Kazakhstan now has
    +# two time zones, and difference between them is one hour.  The zone
    +# closer to UTC is the former Western zone (probably still called the
    +# same), encompassing four provinces in the west: Aqtobe, Atyrau,
    +# Mangghystau, and West Kazakhstan.  The other zone encompasses
    +# everything else....  I guess that would make Kazakhstan time zones
    +# de jure UTC+5 and UTC+6 respectively.
    +
    +#
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +#
    +# Almaty (formerly Alma-Ata), representing most locations in Kazakhstan
    +Zone	Asia/Almaty	5:07:48 -	LMT	1924 May  2 # or Alma-Ata
    +			5:00	-	ALMT	1930 Jun 21 # Alma-Ata Time
    +			6:00 RussiaAsia ALM%sT	1991
    +			6:00	-	ALMT	1992
    +			6:00 RussiaAsia	ALM%sT	2005 Mar 15
    +			6:00	-	ALMT
    +# Qyzylorda (aka Kyzylorda, Kizilorda, Kzyl-Orda, etc.)
    +Zone	Asia/Qyzylorda	4:21:52 -	LMT	1924 May  2
    +			4:00	-	KIZT	1930 Jun 21 # Kizilorda Time
    +			5:00	-	KIZT	1981 Apr  1
    +			5:00	1:00	KIZST	1981 Oct  1
    +			6:00	-	KIZT	1982 Apr  1
    +			5:00 RussiaAsia	KIZ%sT	1991
    +			5:00	-	KIZT	1991 Dec 16 # independence
    +			5:00	-	QYZT	1992 Jan 19 2:00
    +			6:00 RussiaAsia	QYZ%sT	2005 Mar 15
    +			6:00	-	QYZT
    +# Aqtobe (aka Aktobe, formerly Akt'ubinsk)
    +Zone	Asia/Aqtobe	3:48:40	-	LMT	1924 May  2
    +			4:00	-	AKTT	1930 Jun 21 # Aktyubinsk Time
    +			5:00	-	AKTT	1981 Apr  1
    +			5:00	1:00	AKTST	1981 Oct  1
    +			6:00	-	AKTT	1982 Apr  1
    +			5:00 RussiaAsia	AKT%sT	1991
    +			5:00	-	AKTT	1991 Dec 16 # independence
    +			5:00 RussiaAsia	AQT%sT	2005 Mar 15 # Aqtobe Time
    +			5:00	-	AQTT
    +# Mangghystau
    +# Aqtau was not founded until 1963, but it represents an inhabited region,
    +# so include time stamps before 1963.
    +Zone	Asia/Aqtau	3:21:04	-	LMT	1924 May  2
    +			4:00	-	FORT	1930 Jun 21 # Fort Shevchenko T
    +			5:00	-	FORT	1963
    +			5:00	-	SHET	1981 Oct  1 # Shevchenko Time
    +			6:00	-	SHET	1982 Apr  1
    +			5:00 RussiaAsia	SHE%sT	1991
    +			5:00	-	SHET	1991 Dec 16 # independence
    +			5:00 RussiaAsia	AQT%sT	1995 Mar lastSun 2:00 # Aqtau Time
    +			4:00 RussiaAsia	AQT%sT	2005 Mar 15
    +			5:00	-	AQTT
    +# West Kazakhstan
    +Zone	Asia/Oral	3:25:24	-	LMT	1924 May  2 # or Ural'sk
    +			4:00	-	URAT	1930 Jun 21 # Ural'sk time
    +			5:00	-	URAT	1981 Apr  1
    +			5:00	1:00	URAST	1981 Oct  1
    +			6:00	-	URAT	1982 Apr  1
    +			5:00 RussiaAsia	URA%sT	1989 Mar 26 2:00
    +			4:00 RussiaAsia	URA%sT	1991
    +			4:00	-	URAT	1991 Dec 16 # independence
    +			4:00 RussiaAsia	ORA%sT	2005 Mar 15 # Oral Time
    +			5:00	-	ORAT
    +
    +# Kyrgyzstan (Kirgizstan)
    +# Transitions through 1991 are from Shanks & Pottenger.
    +
    +# From Paul Eggert (2005-08-15):
    +# According to an article dated today in the Kyrgyzstan Development Gateway
    +# 
    +# Kyrgyzstan is canceling the daylight saving time system.  I take the article
    +# to mean that they will leave their clocks at 6 hours ahead of UTC.
    +# From Malik Abdugaliev (2005-09-21):
    +# Our government cancels daylight saving time 6th of August 2005.
    +# From 2005-08-12 our GMT-offset is +6, w/o any daylight saving.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Kyrgyz	1992	1996	-	Apr	Sun>=7	0:00s	1:00	S
    +Rule	Kyrgyz	1992	1996	-	Sep	lastSun	0:00	0	-
    +Rule	Kyrgyz	1997	2005	-	Mar	lastSun	2:30	1:00	S
    +Rule	Kyrgyz	1997	2004	-	Oct	lastSun	2:30	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Bishkek	4:58:24 -	LMT	1924 May  2
    +			5:00	-	FRUT	1930 Jun 21 # Frunze Time
    +			6:00 RussiaAsia FRU%sT	1991 Mar 31 2:00s
    +			5:00	1:00	FRUST	1991 Aug 31 2:00 # independence
    +			5:00	Kyrgyz	KG%sT	2005 Aug 12    # Kyrgyzstan Time
    +			6:00	-	KGT
    +
    +###############################################################################
    +
    +# Korea (North and South)
    +
    +# From Annie I. Bang (2006-07-10) in
    +# :
    +# The Ministry of Commerce, Industry and Energy has already
    +# commissioned a research project [to reintroduce DST] and has said
    +# the system may begin as early as 2008....  Korea ran a daylight
    +# saving program from 1949-61 but stopped it during the 1950-53 Korean War.
    +
    +# From Shanks & Pottenger:
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	ROK	1960	only	-	May	15	0:00	1:00	D
    +Rule	ROK	1960	only	-	Sep	13	0:00	0	S
    +Rule	ROK	1987	1988	-	May	Sun>=8	0:00	1:00	D
    +Rule	ROK	1987	1988	-	Oct	Sun>=8	0:00	0	S
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Seoul	8:27:52	-	LMT	1890
    +			8:30	-	KST	1904 Dec
    +			9:00	-	KST	1928
    +			8:30	-	KST	1932
    +			9:00	-	KST	1954 Mar 21
    +			8:00	ROK	K%sT	1961 Aug 10
    +			8:30	-	KST	1968 Oct
    +			9:00	ROK	K%sT
    +Zone	Asia/Pyongyang	8:23:00 -	LMT	1890
    +			8:30	-	KST	1904 Dec
    +			9:00	-	KST	1928
    +			8:30	-	KST	1932
    +			9:00	-	KST	1954 Mar 21
    +			8:00	-	KST	1961 Aug 10
    +			9:00	-	KST
    +
    +###############################################################################
    +
    +# Kuwait
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +# From the Arab Times (2007-03-14):
    +# The Civil Service Commission (CSC) has approved a proposal forwarded
    +# by MP Ahmad Baqer on implementing the daylight saving time (DST) in
    +# Kuwait starting from April until the end of Sept this year, reports Al-Anba.
    +# .
    +# From Paul Eggert (2007-03-29):
    +# We don't know the details, or whether the approval means it'll happen,
    +# so for now we assume no DST.
    +Zone	Asia/Kuwait	3:11:56 -	LMT	1950
    +			3:00	-	AST
    +
    +# Laos
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Vientiane	6:50:24 -	LMT	1906 Jun  9 # or Viangchan
    +			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
    +			7:00	-	ICT	1912 May
    +			8:00	-	ICT	1931 May
    +			7:00	-	ICT
    +
    +# Lebanon
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Lebanon	1920	only	-	Mar	28	0:00	1:00	S
    +Rule	Lebanon	1920	only	-	Oct	25	0:00	0	-
    +Rule	Lebanon	1921	only	-	Apr	3	0:00	1:00	S
    +Rule	Lebanon	1921	only	-	Oct	3	0:00	0	-
    +Rule	Lebanon	1922	only	-	Mar	26	0:00	1:00	S
    +Rule	Lebanon	1922	only	-	Oct	8	0:00	0	-
    +Rule	Lebanon	1923	only	-	Apr	22	0:00	1:00	S
    +Rule	Lebanon	1923	only	-	Sep	16	0:00	0	-
    +Rule	Lebanon	1957	1961	-	May	1	0:00	1:00	S
    +Rule	Lebanon	1957	1961	-	Oct	1	0:00	0	-
    +Rule	Lebanon	1972	only	-	Jun	22	0:00	1:00	S
    +Rule	Lebanon	1972	1977	-	Oct	1	0:00	0	-
    +Rule	Lebanon	1973	1977	-	May	1	0:00	1:00	S
    +Rule	Lebanon	1978	only	-	Apr	30	0:00	1:00	S
    +Rule	Lebanon	1978	only	-	Sep	30	0:00	0	-
    +Rule	Lebanon	1984	1987	-	May	1	0:00	1:00	S
    +Rule	Lebanon	1984	1991	-	Oct	16	0:00	0	-
    +Rule	Lebanon	1988	only	-	Jun	1	0:00	1:00	S
    +Rule	Lebanon	1989	only	-	May	10	0:00	1:00	S
    +Rule	Lebanon	1990	1992	-	May	1	0:00	1:00	S
    +Rule	Lebanon	1992	only	-	Oct	4	0:00	0	-
    +Rule	Lebanon	1993	max	-	Mar	lastSun	0:00	1:00	S
    +Rule	Lebanon	1993	1998	-	Sep	lastSun	0:00	0	-
    +Rule	Lebanon	1999	max	-	Oct	lastSun	0:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Beirut	2:22:00 -	LMT	1880
    +			2:00	Lebanon	EE%sT
    +
    +# Malaysia
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	NBorneo	1935	1941	-	Sep	14	0:00	0:20	TS # one-Third Summer
    +Rule	NBorneo	1935	1941	-	Dec	14	0:00	0	-
    +#
    +# peninsular Malaysia
    +# The data here are taken from Mok Ly Yng (2003-10-30)
    +# .
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Asia/Kuala_Lumpur	6:46:46 -	LMT	1901 Jan  1
    +			6:55:25	-	SMT	1905 Jun  1 # Singapore M.T.
    +			7:00	-	MALT	1933 Jan  1 # Malaya Time
    +			7:00	0:20	MALST	1936 Jan  1
    +			7:20	-	MALT	1941 Sep  1
    +			7:30	-	MALT	1942 Feb 16
    +			9:00	-	JST	1945 Sep 12
    +			7:30	-	MALT	1982 Jan  1
    +			8:00	-	MYT	# Malaysia Time
    +# Sabah & Sarawak
    +# From Paul Eggert (2006-03-22):
    +# The data here are mostly from Shanks & Pottenger, but the 1942, 1945 and 1982
    +# transition dates are from Mok Ly Yng.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Asia/Kuching	7:21:20	-	LMT	1926 Mar
    +			7:30	-	BORT	1933	# Borneo Time
    +			8:00	NBorneo	BOR%sT	1942 Feb 16
    +			9:00	-	JST	1945 Sep 12
    +			8:00	-	BORT	1982 Jan  1
    +			8:00	-	MYT
    +
    +# Maldives
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Indian/Maldives	4:54:00 -	LMT	1880	# Male
    +			4:54:00	-	MMT	1960	# Male Mean Time
    +			5:00	-	MVT		# Maldives Time
    +
    +# Mongolia
    +
    +# Shanks & Pottenger say that Mongolia has three time zones, but
    +# usno1995 and the CIA map Standard Time Zones of the World (2005-03)
    +# both say that it has just one.
    +
    +# From Oscar van Vlijmen (1999-12-11):
    +# 
    +# General Information Mongolia
    +#  (1999-09)
    +# "Time: Mongolia has two time zones. Three westernmost provinces of
    +# Bayan-Ulgii, Uvs, and Hovd are one hour earlier than the capital city, and
    +# the rest of the country follows the Ulaanbaatar time, which is UTC/GMT plus
    +# eight hours."
    +
    +# From Rives McDow (1999-12-13):
    +# Mongolia discontinued the use of daylight savings time in 1999; 1998
    +# being the last year it was implemented.  The dates of implementation I am
    +# unsure of, but most probably it was similar to Russia, except for the time
    +# of implementation may have been different....
    +# Some maps in the past have indicated that there was an additional time
    +# zone in the eastern part of Mongolia, including the provinces of Dornod,
    +# Suhbaatar, and possibly Khentij.
    +
    +# From Paul Eggert (1999-12-15):
    +# Naming and spelling is tricky in Mongolia.
    +# We'll use Hovd (also spelled Chovd and Khovd) to represent the west zone;
    +# the capital of the Hovd province is sometimes called Hovd, sometimes Dund-Us,
    +# and sometimes Jirgalanta (with variant spellings), but the name Hovd
    +# is good enough for our purposes.
    +
    +# From Rives McDow (2001-05-13):
    +# In addition to Mongolia starting daylight savings as reported earlier
    +# (adopted DST on 2001-04-27 02:00 local time, ending 2001-09-28),
    +# there are three time zones.
    +#
    +# Provinces [at 7:00]: Bayan-ulgii, Uvs, Khovd, Zavkhan, Govi-Altai
    +# Provinces [at 8:00]: Khovsgol, Bulgan, Arkhangai, Khentii, Tov,
    +#	Bayankhongor, Ovorkhangai, Dundgovi, Dornogovi, Omnogovi
    +# Provinces [at 9:00]: Dornod, Sukhbaatar
    +#
    +# [The province of Selenge is omitted from the above lists.]
    +
    +# From Ganbold Ts., Ulaanbaatar (2004-04-17):
    +# Daylight saving occurs at 02:00 local time last Saturday of March.
    +# It will change back to normal at 02:00 local time last Saturday of
    +# September.... As I remember this rule was changed in 2001.
    +#
    +# From Paul Eggert (2004-04-17):
    +# For now, assume Rives McDow's informant got confused about Friday vs
    +# Saturday, and that his 2001 dates should have 1 added to them.
    +
    +# From Paul Eggert (2005-07-26):
    +# We have wildly conflicting information about Mongolia's time zones.
    +# Bill Bonnet (2005-05-19) reports that the US Embassy in Ulaanbaatar says
    +# there is only one time zone and that DST is observed, citing Microsoft
    +# Windows XP as the source.  Risto Nykanen (2005-05-16) reports that
    +# travelmongolia.org says there are two time zones (UTC+7, UTC+8) with no DST.
    +# Oscar van Vlijmen (2005-05-20) reports that the Mongolian Embassy in
    +# Washington, DC says there are two time zones, with DST observed.
    +# He also found
    +# 
    +# which also says that there is DST, and which has a comment by "Toddius"
    +# (2005-03-31 06:05 +0700) saying "Mongolia actually has 3.5 time zones.
    +# The West (OLGII) is +7 GMT, most of the country is ULAT is +8 GMT
    +# and some Eastern provinces are +9 GMT but Sukhbaatar Aimag is SUHK +8.5 GMT.
    +# The SUKH timezone is new this year, it is one of the few things the
    +# parliament passed during the tumultuous winter session."
    +# For now, let's ignore this information, until we have more confirmation.
    +
    +# From Ganbold Ts. (2007-02-26):
    +# Parliament of Mongolia has just changed the daylight-saving rule in February.
    +# They decided not to adopt daylight-saving time....
    +# http://www.mongolnews.mn/index.php?module=unuudur&sec=view&id=15742
    +
    +# From Deborah Goldsmith (2008-03-30):
    +# We received a bug report claiming that the tz database UTC offset for
    +# Asia/Choibalsan (GMT+09:00) is incorrect, and that it should be GMT
    +# +08:00 instead. Different sources appear to disagree with the tz
    +# database on this, e.g.:
    +#
    +# 
    +# http://www.timeanddate.com/worldclock/city.html?n=1026
    +# 
    +# 
    +# http://www.worldtimeserver.com/current_time_in_MN.aspx
    +# 
    +#
    +# both say GMT+08:00.
    +
    +# From Steffen Thorsen (2008-03-31):
    +# eznis airways, which operates several domestic flights, has a flight
    +# schedule here:
    +# 
    +# http://www.eznis.com/Container.jsp?id=112
    +# 
    +# (click the English flag for English)
    +#
    +# There it appears that flights between Choibalsan and Ulaanbatar arrive
    +# about 1:35 - 1:50 hours later in local clock time, no matter the
    +# direction, while Ulaanbaatar-Khvod takes 2 hours in the Eastern
    +# direction and 3:35 back, which indicates that Ulaanbatar and Khvod are
    +# in different time zones (like we know about), while Choibalsan and
    +# Ulaanbatar are in the same time zone (correction needed).
    +
    +# From Arthur David Olson (2008-05-19):
    +# Assume that Choibalsan is indeed offset by 8:00.
    +# XXX--in the absence of better information, assume that transition
    +# was at the start of 2008-03-31 (the day of Steffen Thorsen's report);
    +# this is almost surely wrong.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Mongol	1983	1984	-	Apr	1	0:00	1:00	S
    +Rule	Mongol	1983	only	-	Oct	1	0:00	0	-
    +# Shanks & Pottenger and IATA SSIM say 1990s switches occurred at 00:00,
    +# but McDow says the 2001 switches occurred at 02:00.  Also, IATA SSIM
    +# (1996-09) says 1996-10-25.  Go with Shanks & Pottenger through 1998.
    +#
    +# Shanks & Pottenger say that the Sept. 1984 through Sept. 1990 switches
    +# in Choibalsan (more precisely, in Dornod and Sukhbaatar) took place
    +# at 02:00 standard time, not at 00:00 local time as in the rest of
    +# the country.  That would be odd, and possibly is a result of their
    +# correction of 02:00 (in the previous edition) not being done correctly
    +# in the latest edition; so ignore it for now.
    +
    +Rule	Mongol	1985	1998	-	Mar	lastSun	0:00	1:00	S
    +Rule	Mongol	1984	1998	-	Sep	lastSun	0:00	0	-
    +# IATA SSIM (1999-09) says Mongolia no longer observes DST.
    +Rule	Mongol	2001	only	-	Apr	lastSat	2:00	1:00	S
    +Rule	Mongol	2001	2006	-	Sep	lastSat	2:00	0	-
    +Rule	Mongol	2002	2006	-	Mar	lastSat	2:00	1:00	S
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +# Hovd, a.k.a. Chovd, Dund-Us, Dzhargalant, Khovd, Jirgalanta
    +Zone	Asia/Hovd	6:06:36 -	LMT	1905 Aug
    +			6:00	-	HOVT	1978	# Hovd Time
    +			7:00	Mongol	HOV%sT
    +# Ulaanbaatar, a.k.a. Ulan Bataar, Ulan Bator, Urga
    +Zone	Asia/Ulaanbaatar 7:07:32 -	LMT	1905 Aug
    +			7:00	-	ULAT	1978	# Ulaanbaatar Time
    +			8:00	Mongol	ULA%sT
    +# Choibalsan, a.k.a. Bajan Tuemen, Bajan Tumen, Chojbalsan,
    +# Choybalsan, Sanbejse, Tchoibalsan
    +Zone	Asia/Choibalsan	7:38:00 -	LMT	1905 Aug
    +			7:00	-	ULAT	1978
    +			8:00	-	ULAT	1983 Apr
    +			9:00	Mongol	CHO%sT	2008 Mar 31 # Choibalsan Time
    +			8:00	Mongol	CHO%sT
    +
    +# Nepal
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Kathmandu	5:41:16 -	LMT	1920
    +			5:30	-	IST	1986
    +			5:45	-	NPT	# Nepal Time
    +
    +# Oman
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Muscat	3:54:20 -	LMT	1920
    +			4:00	-	GST
    +
    +# Pakistan
    +
    +# From Rives McDow (2002-03-13):
    +# I have been advised that Pakistan has decided to adopt dst on a
    +# TRIAL basis for one year, starting 00:01 local time on April 7, 2002
    +# and ending at 00:01 local time October 6, 2002.  This is what I was
    +# told, but I believe that the actual time of change may be 00:00; the
    +# 00:01 was to make it clear which day it was on.
    +
    +# From Paul Eggert (2002-03-15):
    +# Jesper Norgaard found this URL:
    +# http://www.pak.gov.pk/public/news/app/app06_dec.htm
    +# (dated 2001-12-06) which says that the Cabinet adopted a scheme "to
    +# advance the clocks by one hour on the night between the first
    +# Saturday and Sunday of April and revert to the original position on
    +# 15th October each year".  This agrees with McDow's 04-07 at 00:00,
    +# but disagrees about the October transition, and makes it sound like
    +# it's not on a trial basis.  Also, the "between the first Saturday
    +# and Sunday of April" phrase, if taken literally, means that the
    +# transition takes place at 00:00 on the first Sunday on or after 04-02.
    +
    +# From Paul Eggert (2003-02-09):
    +# DAWN  reported on 2002-10-05
    +# that 2002 DST ended that day at midnight.  Go with McDow for now.
    +
    +# From Steffen Thorsen (2003-03-14):
    +# According to http://www.dawn.com/2003/03/07/top15.htm
    +# there will be no DST in Pakistan this year:
    +#
    +# ISLAMABAD, March 6: Information and Media Development Minister Sheikh
    +# Rashid Ahmed on Thursday said the cabinet had reversed a previous
    +# decision to advance clocks by one hour in summer and put them back by
    +# one hour in winter with the aim of saving light hours and energy.
    +#
    +# The minister told a news conference that the experiment had rather
    +# shown 8 per cent higher consumption of electricity.
    +
    +# From Alex Krivenyshev (2008-05-15):
    +#
    +# Here is an article that Pakistan plan to introduce Daylight Saving Time
    +# on June 1, 2008 for 3 months.
    +#
    +# "... The federal cabinet on Wednesday announced a new conservation plan to help
    +# reduce load shedding by approving the closure of commercial centres at 9pm and
    +# moving clocks forward by one hour for the next three months.
    +# ...."
    +#
    +# 
    +# http://www.worldtimezone.net/dst_news/dst_news_pakistan01.html
    +# 
    +# OR
    +# 
    +# http://www.dailytimes.com.pk/default.asp?page=2008%5C05%5C15%5Cstory_15-5-2008_pg1_4
    +# 
    +
    +# From Arthur David Olson (2008-05-19):
    +# XXX--midnight transitions is a guess; 2008 only is a guess.
    +
    +# From Alexander Krivenyshev (2008-08-28):
    +# Pakistan government has decided to keep the watches one-hour advanced
    +# for another 2 months--plan to return to Standard Time on October 31
    +# instead of August 31.
    +#
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_pakistan02.html
    +# 
    +# OR
    +# 
    +# http://dailymailnews.com/200808/28/news/dmbrn03.html
    +# 
    +
    +# From Alexander Krivenyshev (2009-04-08):
    +# Based on previous media reports that "... proposed plan to
    +# advance clocks by one hour from May 1 will cause disturbance
    +# to the working schedules rather than bringing discipline in
    +# official working."
    +# 
    +# http://www.thenews.com.pk/daily_detail.asp?id=171280
    +# 
    +#
    +# recent news that instead of May 2009 - Pakistan plan to
    +# introduce DST from April 15, 2009
    +#
    +# FYI: Associated Press Of Pakistan
    +# April 08, 2009
    +# Cabinet okays proposal to advance clocks by one hour from April 15
    +# 
    +# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=73043&Itemid=1
    +# 
    +#
    +# or
    +#
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_pakistan05.html
    +# 
    +#
    +# ....
    +# The Federal Cabinet on Wednesday approved the proposal to
    +# advance clocks in the country by one hour from April 15 to
    +# conserve energy"
    +
    +# From Steffen Thorsen (2009-09-17):
    +# "The News International," Pakistan reports that: "The Federal
    +# Government has decided to restore the previous time by moving the
    +# clocks backward by one hour from October 1. A formal announcement to
    +# this effect will be made after the Prime Minister grants approval in
    +# this regard."
    +# 
    +# http://www.thenews.com.pk/updates.asp?id=87168
    +# 
    +
    +# From Alexander Krivenyshev (2009-09-28):
    +# According to Associated Press Of Pakistan, it is confirmed that
    +# Pakistan clocks across the country would be turned back by an hour from October
    +# 1, 2009.
    +#
    +# "Clocks to go back one hour from 1 Oct"
    +# 
    +# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=86715&Itemid=2
    +# 
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_pakistan07.htm
    +# 
    +
    +# From Steffen Thorsen (2009-09-29):
    +# Alexander Krivenyshev wrote:
    +# > According to Associated Press Of Pakistan, it is confirmed that
    +# > Pakistan clocks across the country would be turned back by an hour from October
    +# > 1, 2009.
    +#
    +# Now they seem to have changed their mind, November 1 is the new date:
    +# 
    +# http://www.thenews.com.pk/top_story_detail.asp?Id=24742
    +# 
    +# "The country's clocks will be reversed by one hour on November 1.
    +# Officials of Federal Ministry for Interior told this to Geo News on
    +# Monday."
    +#
    +# And more importantly, it seems that these dates will be kept every year:
    +# "It has now been decided that clocks will be wound forward by one hour
    +# on April 15 and reversed by an hour on November 1 every year without
    +# obtaining prior approval, the officials added."
    +#
    +# We have confirmed this year's end date with both with the Ministry of
    +# Water and Power and the Pakistan Electric Power Company:
    +# 
    +# http://www.timeanddate.com/news/time/pakistan-ends-dst09.html
    +# 
    +
    +# From Christoph Goehre (2009-10-01):
    +# [T]he German Consulate General in Karachi reported me today that Pakistan
    +# will go back to standard time on 1st of November.
    +
    +# From Steffen Thorsen (2010-03-26):
    +# Steffen Thorsen wrote:
    +# > On Thursday (2010-03-25) it was announced that DST would start in
    +# > Pakistan on 2010-04-01.
    +# >
    +# > Then today, the president said that they might have to revert the
    +# > decision if it is not supported by the parliament. So at the time
    +# > being, it seems unclear if DST will be actually observed or not - but
    +# > April 1 could be a more likely date than April 15.
    +# Now, it seems that the decision to not observe DST in final:
    +#
    +# "Govt Withdraws Plan To Advance Clocks"
    +# 
    +# http://www.apakistannews.com/govt-withdraws-plan-to-advance-clocks-172041
    +# 
    +#
    +# "People laud PM's announcement to end DST"
    +# 
    +# http://www.app.com.pk/en_/index.php?option=com_content&task=view&id=99374&Itemid=2
    +# 
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule Pakistan	2002	only	-	Apr	Sun>=2	0:01	1:00	S
    +Rule Pakistan	2002	only	-	Oct	Sun>=2	0:01	0	-
    +Rule Pakistan	2008	only	-	Jun	1	0:00	1:00	S
    +Rule Pakistan	2008	only	-	Nov	1	0:00	0	-
    +Rule Pakistan	2009	only	-	Apr	15	0:00	1:00	S
    +Rule Pakistan	2009	only	-	Nov	1	0:00	0	-
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Karachi	4:28:12 -	LMT	1907
    +			5:30	-	IST	1942 Sep
    +			5:30	1:00	IST	1945 Oct 15
    +			5:30	-	IST	1951 Sep 30
    +			5:00	-	KART	1971 Mar 26 # Karachi Time
    +			5:00 Pakistan	PK%sT	# Pakistan Time
    +
    +# Palestine
    +
    +# From Amos Shapir (1998-02-15):
    +#
    +# From 1917 until 1948-05-15, all of Palestine, including the parts now
    +# known as the Gaza Strip and the West Bank, was under British rule.
    +# Therefore the rules given for Israel for that period, apply there too...
    +#
    +# The Gaza Strip was under Egyptian rule between 1948-05-15 until 1967-06-05
    +# (except a short occupation by Israel from 1956-11 till 1957-03, but no
    +# time zone was affected then).  It was never formally annexed to Egypt,
    +# though.
    +#
    +# The rest of Palestine was under Jordanian rule at that time, formally
    +# annexed in 1950 as the West Bank (and the word "Trans" was dropped from
    +# the country's previous name of "the Hashemite Kingdom of the
    +# Trans-Jordan").  So the rules for Jordan for that time apply.  Major
    +# towns in that area are Nablus (Shchem), El-Halil (Hebron), Ramallah, and
    +# East Jerusalem.
    +#
    +# Both areas were occupied by Israel in June 1967, but not annexed (except
    +# for East Jerusalem).  They were on Israel time since then; there might
    +# have been a Military Governor's order about time zones, but I'm not aware
    +# of any (such orders may have been issued semi-annually whenever summer
    +# time was in effect, but maybe the legal aspect of time was just neglected).
    +#
    +# The Palestinian Authority was established in 1993, and got hold of most
    +# towns in the West Bank and Gaza by 1995.  I know that in order to
    +# demonstrate...independence, they have been switching to
    +# summer time and back on a different schedule than Israel's, but I don't
    +# know when this was started, or what algorithm is used (most likely the
    +# Jordanian one).
    +#
    +# To summarize, the table should probably look something like that:
    +#
    +# Area \ when | 1918-1947 | 1948-1967 | 1967-1995 | 1996-
    +# ------------+-----------+-----------+-----------+-----------
    +# Israel      | Zion      | Zion      | Zion      | Zion
    +# West bank   | Zion      | Jordan    | Zion      | Jordan
    +# Gaza        | Zion      | Egypt     | Zion      | Jordan
    +#
    +# I guess more info may be available from the PA's web page (if/when they
    +# have one).
    +
    +# From Paul Eggert (2006-03-22):
    +# Shanks & Pottenger write that Gaza did not observe DST until 1957, but go
    +# with Shapir and assume that it observed DST from 1940 through 1947,
    +# and that it used Jordanian rules starting in 1996.
    +# We don't yet need a separate entry for the West Bank, since
    +# the only differences between it and Gaza that we know about
    +# occurred before our cutoff date of 1970.
    +# However, as we get more information, we may need to add entries
    +# for parts of the West Bank as they transitioned from Israel's rules
    +# to Palestine's rules.  If you have more info about this, please
    +# send it to tz@elsie.nci.nih.gov for incorporation into future editions.
    +
    +# From IINS News Service - Israel - 1998-03-23 10:38:07 Israel time,
    +# forwarded by Ephraim Silverberg:
    +#
    +# Despite the fact that Israel changed over to daylight savings time
    +# last week, the PLO Authority (PA) has decided not to turn its clocks
    +# one-hour forward at this time.  As a sign of independence from Israeli rule,
    +# the PA has decided to implement DST in April.
    +
    +# From Paul Eggert (1999-09-20):
    +# Daoud Kuttab writes in
    +# 
    +# Holiday havoc
    +#  (Jerusalem Post, 1999-04-22) that
    +# the Palestinian National Authority changed to DST on 1999-04-15.
    +# I vaguely recall that they switch back in October (sorry, forgot the source).
    +# For now, let's assume that the spring switch was at 24:00,
    +# and that they switch at 0:00 on the 3rd Fridays of April and October.
    +
    +# From Paul Eggert (2005-11-22):
    +# Starting 2004 transitions are from Steffen Thorsen's web site timeanddate.com.
    +
    +# From Steffen Thorsen (2005-11-23):
    +# A user from Gaza reported that Gaza made the change early because of
    +# the Ramadan.  Next year Ramadan will be even earlier, so I think
    +# there is a good chance next year's end date will be around two weeks
    +# earlier--the same goes for Jordan.
    +
    +# From Steffen Thorsen (2006-08-17):
    +# I was informed by a user in Bethlehem that in Bethlehem it started the
    +# same day as Israel, and after checking with other users in the area, I
    +# was informed that they started DST one day after Israel.  I was not
    +# able to find any authoritative sources at the time, nor details if
    +# Gaza changed as well, but presumed Gaza to follow the same rules as
    +# the West Bank.
    +
    +# From Steffen Thorsen (2006-09-26):
    +# according to the Palestine News Network (2006-09-19):
    +# http://english.pnn.ps/index.php?option=com_content&task=view&id=596&Itemid=5
    +# > The Council of Ministers announced that this year its winter schedule
    +# > will begin early, as of midnight Thursday.  It is also time to turn
    +# > back the clocks for winter.  Friday will begin an hour late this week.
    +# I guess it is likely that next year's date will be moved as well,
    +# because of the Ramadan.
    +
    +# From Jesper Norgaard Welen (2007-09-18):
    +# According to Steffen Thorsen's web site the Gaza Strip and the rest of the
    +# Palestinian territories left DST early on 13.th. of September at 2:00.
    +
    +# From Paul Eggert (2007-09-20):
    +# My understanding is that Gaza and the West Bank disagree even over when
    +# the weekend is (Thursday+Friday versus Friday+Saturday), so I'd be a bit
    +# surprised if they agreed about DST.  But for now, assume they agree.
    +# For lack of better information, predict that future changes will be
    +# the 2nd Thursday of September at 02:00.
    +
    +# From Alexander Krivenyshev (2008-08-28):
    +# Here is an article, that Mideast running on different clocks at Ramadan.
    +#
    +# Gaza Strip (as Egypt) ended DST at midnight Thursday (Aug 28, 2008), while
    +# the West Bank will end Daylight Saving Time at midnight Sunday (Aug 31, 2008).
    +#
    +# 
    +# http://www.guardian.co.uk/world/feedarticle/7759001
    +# 
    +# 
    +# http://www.abcnews.go.com/International/wireStory?id=5676087
    +# 
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_gazastrip01.html
    +# 
    +
    +# From Alexander Krivenyshev (2009-03-26):
    +# According to the Palestine News Network (arabic.pnn.ps), Palestinian
    +# government decided to start Daylight Time on Thursday night March
    +# 26 and continue until the night of 27 September 2009.
    +#
    +# (in Arabic)
    +# 
    +# http://arabic.pnn.ps/index.php?option=com_content&task=view&id=50850
    +# 
    +#
    +# or
    +# (English translation)
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_westbank01.html
    +# 
    +
    +# From Steffen Thorsen (2009-08-31):
    +# Palestine's Council of Ministers announced that they will revert back to
    +# winter time on Friday, 2009-09-04.
    +#
    +# One news source:
    +# 
    +# http://www.safa.ps/ara/?action=showdetail&seid=4158
    +# 
    +# (Palestinian press agency, Arabic),
    +# Google translate: "Decided that the Palestinian government in Ramallah
    +# headed by Salam Fayyad, the start of work in time for the winter of
    +# 2009, starting on Friday approved the fourth delay Sept. clock sixty
    +# minutes per hour as of Friday morning."
    +#
    +# We are not sure if Gaza will do the same, last year they had a different
    +# end date, we will keep this page updated:
    +# 
    +# http://www.timeanddate.com/news/time/westbank-gaza-dst-2009.html
    +# 
    +
    +# From Alexander Krivenyshev (2009-09-02):
    +# Seems that Gaza Strip will go back to Winter Time same date as West Bank.
    +#
    +# According to Palestinian Ministry Of Interior, West Bank and Gaza Strip plan
    +# to change time back to Standard time on September 4, 2009.
    +#
    +# "Winter time unite the West Bank and Gaza"
    +# (from Palestinian National Authority):
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_gazastrip02.html
    +# 
    +
    +# From Alexander Krivenyshev (2010-03-19):
    +# According to Voice of Palestine DST will last for 191 days, from March
    +# 26, 2010 till "the last Sunday before the tenth day of Tishri
    +# (October), each year" (October 03, 2010?)
    +#
    +# 
    +# http://palvoice.org/forums/showthread.php?t=245697
    +# 
    +# (in Arabic)
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_westbank03.html
    +# 
    +
    +# From Steffen Thorsen (2010-03-24):
    +# ...Ma'an News Agency reports that Hamas cabinet has decided it will
    +# start one day later, at 12:01am. Not sure if they really mean 12:01am or
    +# noon though:
    +#
    +# 
    +# http://www.maannews.net/eng/ViewDetails.aspx?ID=271178
    +# 
    +# (Ma'an News Agency)
    +# "At 12:01am Friday, clocks in Israel and the West Bank will change to
    +# 1:01am, while Gaza clocks will change at 12:01am Saturday morning."
    +
    +# From Steffen Thorsen (2010-08-11):
    +# According to several sources, including
    +# 
    +# http://www.maannews.net/eng/ViewDetails.aspx?ID=306795
    +# 
    +# the clocks were set back one hour at 2010-08-11 00:00:00 local time in
    +# Gaza and the West Bank.
    +# Some more background info:
    +# 
    +# http://www.timeanddate.com/news/time/westbank-gaza-end-dst-2010.html
    +# 
    +
    +# From Steffen Thorsen (2011-08-26):
    +# Gaza and the West Bank did go back to standard time in the beginning of
    +# August, and will now enter daylight saving time again on 2011-08-30
    +# 00:00 (so two periods of DST in 2011). The pause was because of
    +# Ramadan.
    +#
    +# 
    +# http://www.maannews.net/eng/ViewDetails.aspx?ID=416217
    +# 
    +# Additional info:
    +# 
    +# http://www.timeanddate.com/news/time/palestine-dst-2011.html
    +# 
    +
    +# From Alexander Krivenyshev (2011-08-27):
    +# According to the article in The Jerusalem Post:
    +# "...Earlier this month, the Palestinian government in the West Bank decided to
    +# move to standard time for 30 days, during Ramadan. The Palestinians in the
    +# Gaza Strip accepted the change and also moved their clocks one hour back.
    +# The Hamas government said on Saturday that it won't observe summertime after
    +# the Muslim feast of Id al-Fitr, which begins on Tuesday..."
    +# ...
    +# 
    +# http://www.jpost.com/MiddleEast/Article.aspx?id=235650
    +# 
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_gazastrip05.html
    +# 
    +# The rules for Egypt are stolen from the `africa' file.
    +
    +# From Steffen Thorsen (2011-09-30):
    +# West Bank did end Daylight Saving Time this morning/midnight (2011-09-30
    +# 00:00).
    +# So West Bank and Gaza now have the same time again.
    +#
    +# Many sources, including:
    +# 
    +# http://www.maannews.net/eng/ViewDetails.aspx?ID=424808
    +# 
    +
    +# From Steffen Thorsen (2012-03-26):
    +# Palestinian news sources tell that both Gaza and West Bank will start DST
    +# on Friday (Thursday midnight, 2012-03-29 24:00).
    +# Some of many sources in Arabic:
    +# 
    +# http://www.samanews.com/index.php?act=Show&id=122638
    +# 
    +#
    +# 
    +# http://safa.ps/details/news/74352/%D8%A8%D8%AF%D8%A1-%D8%A7%D9%84%D8%AA%D9%88%D9%82%D9%8A%D8%AA-%D8%A7%D9%84%D8%B5%D9%8A%D9%81%D9%8A-%D8%A8%D8%A7%D9%84%D8%B6%D9%81%D8%A9-%D9%88%D8%BA%D8%B2%D8%A9-%D9%84%D9%8A%D9%84%D8%A9-%D8%A7%D9%84%D8%AC%D9%85%D8%B9%D8%A9.html
    +# 
    +#
    +# Our brief summary:
    +# 
    +# http://www.timeanddate.com/news/time/gaza-west-bank-dst-2012.html
    +# 
    +
    +# From Arthur David Olson (2012-03-27):
    +# The timeanddate article for 2012 says that "the end date has not yet been
    +# announced" and that "Last year, both...paused daylight saving time during...
    +# Ramadan. It is not yet known [for] 2012."
    +# For now, assume both switch back on the last Friday in September. XXX
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule EgyptAsia	1957	only	-	May	10	0:00	1:00	S
    +Rule EgyptAsia	1957	1958	-	Oct	 1	0:00	0	-
    +Rule EgyptAsia	1958	only	-	May	 1	0:00	1:00	S
    +Rule EgyptAsia	1959	1967	-	May	 1	1:00	1:00	S
    +Rule EgyptAsia	1959	1965	-	Sep	30	3:00	0	-
    +Rule EgyptAsia	1966	only	-	Oct	 1	3:00	0	-
    +
    +Rule Palestine	1999	2005	-	Apr	Fri>=15	0:00	1:00	S
    +Rule Palestine	1999	2003	-	Oct	Fri>=15	0:00	0	-
    +Rule Palestine	2004	only	-	Oct	 1	1:00	0	-
    +Rule Palestine	2005	only	-	Oct	 4	2:00	0	-
    +Rule Palestine	2006	2008	-	Apr	 1	0:00	1:00	S
    +Rule Palestine	2006	only	-	Sep	22	0:00	0	-
    +Rule Palestine	2007	only	-	Sep	Thu>=8	2:00	0	-
    +Rule Palestine	2008	only	-	Aug	lastFri	0:00	0	-
    +Rule Palestine	2009	only	-	Mar	lastFri	0:00	1:00	S
    +Rule Palestine	2009	only	-	Sep	Fri>=1	2:00	0	-
    +Rule Palestine	2010	only	-	Mar	lastSat	0:01	1:00	S
    +Rule Palestine	2010	only	-	Aug	11	0:00	0	-
    +
    +# From Arthur David Olson (2011-09-20):
    +# 2011 transitions per http://www.timeanddate.com as of 2011-09-20.
    +# From Paul Eggert (2012-10-12):
    +# 2012 transitions per http://www.timeanddate.com as of 2012-10-12.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Gaza	2:17:52	-	LMT	1900 Oct
    +			2:00	Zion	EET	1948 May 15
    +			2:00 EgyptAsia	EE%sT	1967 Jun  5
    +			2:00	Zion	I%sT	1996
    +			2:00	Jordan	EE%sT	1999
    +			2:00 Palestine	EE%sT	2011 Apr  2 12:01
    +			2:00	1:00	EEST	2011 Aug  1
    +			2:00	-	EET	2012 Mar 30
    +			2:00	1:00	EEST	2012 Sep 21 1:00
    +			2:00	-	EET
    +
    +Zone	Asia/Hebron	2:20:23	-	LMT	1900 Oct
    +			2:00	Zion	EET	1948 May 15
    +			2:00 EgyptAsia	EE%sT	1967 Jun  5
    +			2:00	Zion	I%sT	1996
    +			2:00	Jordan	EE%sT	1999
    +			2:00 Palestine	EE%sT	2008 Aug
    +			2:00 	1:00	EEST	2008 Sep
    +			2:00 Palestine	EE%sT	2011 Apr  1 12:01
    +			2:00	1:00	EEST	2011 Aug  1
    +			2:00	-	EET	2011 Aug 30
    +			2:00	1:00	EEST	2011 Sep 30 3:00
    +			2:00	-	EET	2012 Mar 30
    +			2:00	1:00	EEST	2012 Sep 21 1:00
    +			2:00	-	EET
    +
    +# Paracel Is
    +# no information
    +
    +# Philippines
    +# On 1844-08-16, Narciso Claveria, governor-general of the
    +# Philippines, issued a proclamation announcing that 1844-12-30 was to
    +# be immediately followed by 1845-01-01.  Robert H. van Gent has a
    +# transcript of the decree in .
    +# The rest of the data are from Shanks & Pottenger.
    +
    +# From Paul Eggert (2006-04-25):
    +# Tomorrow's Manila Standard reports that the Philippines Department of
    +# Trade and Industry is considering adopting DST this June when the
    +# rainy season begins.  See
    +# .
    +# For now, we'll ignore this, since it's not definite and we lack details.
    +#
    +# From Jesper Norgaard Welen (2006-04-26):
    +# ... claims that Philippines had DST last time in 1990:
    +# http://story.philippinetimes.com/p.x/ct/9/id/145be20cc6b121c0/cid/3e5bbccc730d258c/
    +# [a story dated 2006-04-25 by Cris Larano of Dow Jones Newswires,
    +# but no details]
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Phil	1936	only	-	Nov	1	0:00	1:00	S
    +Rule	Phil	1937	only	-	Feb	1	0:00	0	-
    +Rule	Phil	1954	only	-	Apr	12	0:00	1:00	S
    +Rule	Phil	1954	only	-	Jul	1	0:00	0	-
    +Rule	Phil	1978	only	-	Mar	22	0:00	1:00	S
    +Rule	Phil	1978	only	-	Sep	21	0:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Manila	-15:56:00 -	LMT	1844 Dec 31
    +			8:04:00 -	LMT	1899 May 11
    +			8:00	Phil	PH%sT	1942 May
    +			9:00	-	JST	1944 Nov
    +			8:00	Phil	PH%sT
    +
    +# Qatar
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Qatar	3:26:08 -	LMT	1920	# Al Dawhah / Doha
    +			4:00	-	GST	1972 Jun
    +			3:00	-	AST
    +
    +# Saudi Arabia
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Riyadh	3:06:52 -	LMT	1950
    +			3:00	-	AST
    +
    +# Singapore
    +# The data here are taken from Mok Ly Yng (2003-10-30)
    +# .
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Singapore	6:55:25 -	LMT	1901 Jan  1
    +			6:55:25	-	SMT	1905 Jun  1 # Singapore M.T.
    +			7:00	-	MALT	1933 Jan  1 # Malaya Time
    +			7:00	0:20	MALST	1936 Jan  1
    +			7:20	-	MALT	1941 Sep  1
    +			7:30	-	MALT	1942 Feb 16
    +			9:00	-	JST	1945 Sep 12
    +			7:30	-	MALT	1965 Aug  9 # independence
    +			7:30	-	SGT	1982 Jan  1 # Singapore Time
    +			8:00	-	SGT
    +
    +# Spratly Is
    +# no information
    +
    +# Sri Lanka
    +# From Paul Eggert (1996-09-03):
    +# "Sri Lanka advances clock by an hour to avoid blackout"
    +# (www.virtual-pc.com/lankaweb/news/items/240596-2.html, 1996-05-24,
    +# no longer available as of 1999-08-17)
    +# reported ``the country's standard time will be put forward by one hour at
    +# midnight Friday (1830 GMT) `in the light of the present power crisis'.''
    +#
    +# From Dharmasiri Senanayake, Sri Lanka Media Minister (1996-10-24), as quoted
    +# by Shamindra in
    +# 
    +# Daily News - Hot News Section (1996-10-26)
    +# :
    +# With effect from 12.30 a.m. on 26th October 1996
    +# Sri Lanka will be six (06) hours ahead of GMT.
    +
    +# From Jesper Norgaard Welen (2006-04-14), quoting Sri Lanka News Online
    +#  (2006-04-13):
    +# 0030 hrs on April 15, 2006 (midnight of April 14, 2006 +30 minutes)
    +# at present, become 2400 hours of April 14, 2006 (midnight of April 14, 2006).
    +
    +# From Peter Apps and Ranga Sirila of Reuters (2006-04-12) in:
    +# 
    +# [The Tamil Tigers] never accepted the original 1996 time change and simply
    +# kept their clocks set five and a half hours ahead of Greenwich Mean
    +# Time (GMT), in line with neighbor India.
    +# From Paul Eggert (2006-04-18):
    +# People who live in regions under Tamil control can use [TZ='Asia/Kolkata'],
    +# as that zone has agreed with the Tamil areas since our cutoff date of 1970.
    +
    +# From K Sethu (2006-04-25):
    +# I think the abbreviation LKT originated from the world of computers at
    +# the time of or subsequent to the time zone changes by SL Government
    +# twice in 1996 and probably SL Government or its standardization
    +# agencies never declared an abbreviation as a national standard.
    +#
    +# I recollect before the recent change the government annoucemments
    +# mentioning it as simply changing Sri Lanka Standard Time or Sri Lanka
    +# Time and no mention was made about the abbreviation.
    +#
    +# If we look at Sri Lanka Department of Government's "Official News
    +# Website of Sri Lanka" ... http://www.news.lk/ we can see that they
    +# use SLT as abbreviation in time stamp at the beginning of each news
    +# item....
    +#
    +# Within Sri Lanka I think LKT is well known among computer users and
    +# adminsitrators.  In my opinion SLT may not be a good choice because the
    +# nation's largest telcom / internet operator Sri Lanka Telcom is well
    +# known by that abbreviation - simply as SLT (there IP domains are
    +# slt.lk and sltnet.lk).
    +#
    +# But if indeed our government has adopted SLT as standard abbreviation
    +# (that we have not known so far) then  it is better that it be used for
    +# all computers.
    +
    +# From Paul Eggert (2006-04-25):
    +# One possibility is that we wait for a bit for the dust to settle down
    +# and then see what people actually say in practice.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Colombo	5:19:24 -	LMT	1880
    +			5:19:32	-	MMT	1906	# Moratuwa Mean Time
    +			5:30	-	IST	1942 Jan  5
    +			5:30	0:30	IHST	1942 Sep
    +			5:30	1:00	IST	1945 Oct 16 2:00
    +			5:30	-	IST	1996 May 25 0:00
    +			6:30	-	LKT	1996 Oct 26 0:30
    +			6:00	-	LKT	2006 Apr 15 0:30
    +			5:30	-	IST
    +
    +# Syria
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Syria	1920	1923	-	Apr	Sun>=15	2:00	1:00	S
    +Rule	Syria	1920	1923	-	Oct	Sun>=1	2:00	0	-
    +Rule	Syria	1962	only	-	Apr	29	2:00	1:00	S
    +Rule	Syria	1962	only	-	Oct	1	2:00	0	-
    +Rule	Syria	1963	1965	-	May	1	2:00	1:00	S
    +Rule	Syria	1963	only	-	Sep	30	2:00	0	-
    +Rule	Syria	1964	only	-	Oct	1	2:00	0	-
    +Rule	Syria	1965	only	-	Sep	30	2:00	0	-
    +Rule	Syria	1966	only	-	Apr	24	2:00	1:00	S
    +Rule	Syria	1966	1976	-	Oct	1	2:00	0	-
    +Rule	Syria	1967	1978	-	May	1	2:00	1:00	S
    +Rule	Syria	1977	1978	-	Sep	1	2:00	0	-
    +Rule	Syria	1983	1984	-	Apr	9	2:00	1:00	S
    +Rule	Syria	1983	1984	-	Oct	1	2:00	0	-
    +Rule	Syria	1986	only	-	Feb	16	2:00	1:00	S
    +Rule	Syria	1986	only	-	Oct	9	2:00	0	-
    +Rule	Syria	1987	only	-	Mar	1	2:00	1:00	S
    +Rule	Syria	1987	1988	-	Oct	31	2:00	0	-
    +Rule	Syria	1988	only	-	Mar	15	2:00	1:00	S
    +Rule	Syria	1989	only	-	Mar	31	2:00	1:00	S
    +Rule	Syria	1989	only	-	Oct	1	2:00	0	-
    +Rule	Syria	1990	only	-	Apr	1	2:00	1:00	S
    +Rule	Syria	1990	only	-	Sep	30	2:00	0	-
    +Rule	Syria	1991	only	-	Apr	 1	0:00	1:00	S
    +Rule	Syria	1991	1992	-	Oct	 1	0:00	0	-
    +Rule	Syria	1992	only	-	Apr	 8	0:00	1:00	S
    +Rule	Syria	1993	only	-	Mar	26	0:00	1:00	S
    +Rule	Syria	1993	only	-	Sep	25	0:00	0	-
    +# IATA SSIM (1998-02) says 1998-04-02;
    +# (1998-09) says 1999-03-29 and 1999-09-29; (1999-02) says 1999-04-02,
    +# 2000-04-02, and 2001-04-02; (1999-09) says 2000-03-31 and 2001-03-31;
    +# (2006) says 2006-03-31 and 2006-09-22;
    +# for now ignore all these claims and go with Shanks & Pottenger,
    +# except for the 2006-09-22 claim (which seems right for Ramadan).
    +Rule	Syria	1994	1996	-	Apr	 1	0:00	1:00	S
    +Rule	Syria	1994	2005	-	Oct	 1	0:00	0	-
    +Rule	Syria	1997	1998	-	Mar	lastMon	0:00	1:00	S
    +Rule	Syria	1999	2006	-	Apr	 1	0:00	1:00	S
    +# From Stephen Colebourne (2006-09-18):
    +# According to IATA data, Syria will change DST on 21st September [21:00 UTC]
    +# this year [only]....  This is probably related to Ramadan, like Egypt.
    +Rule	Syria	2006	only	-	Sep	22	0:00	0	-
    +# From Paul Eggert (2007-03-29):
    +# Today the AP reported "Syria will switch to summertime at midnight Thursday."
    +# http://www.iht.com/articles/ap/2007/03/29/africa/ME-GEN-Syria-Time-Change.php
    +Rule	Syria	2007	only	-	Mar	lastFri	0:00	1:00	S
    +# From Jesper Norgard (2007-10-27):
    +# The sister center ICARDA of my work CIMMYT is confirming that Syria DST will
    +# not take place 1.st November at 0:00 o'clock but 1.st November at 24:00 or
    +# rather Midnight between Thursday and Friday. This does make more sence than
    +# having it between Wednesday and Thursday (two workdays in Syria) since the
    +# weekend in Syria is not Saturday and Sunday, but Friday and Saturday. So now
    +# it is implemented at midnight of the last workday before weekend...
    +#
    +# From Steffen Thorsen (2007-10-27):
    +# Jesper Norgaard Welen wrote:
    +#
    +# > "Winter local time in Syria will be observed at midnight of Thursday 1
    +# > November 2007, and the clock will be put back 1 hour."
    +#
    +# I found confirmation on this in this gov.sy-article (Arabic):
    +# http://wehda.alwehda.gov.sy/_print_veiw.asp?FileName=12521710520070926111247
    +#
    +# which using Google's translate tools says:
    +# Council of Ministers also approved the commencement of work on
    +# identifying the winter time as of Friday, 2/11/2007 where the 60th
    +# minute delay at midnight Thursday 1/11/2007.
    +Rule	Syria	2007	only	-	Nov	 Fri>=1	0:00	0	-
    +
    +# From Stephen Colebourne (2008-03-17):
    +# For everyone's info, I saw an IATA time zone change for [Syria] for
    +# this month (March 2008) in the last day or so...This is the data IATA
    +# are now using:
    +# Country     Time Standard   --- DST Start ---   --- DST End ---  DST
    +# Name        Zone Variation   Time    Date        Time    Date
    +# Variation
    +# Syrian Arab
    +# Republic    SY    +0200      2200  03APR08       2100  30SEP08   +0300
    +#                              2200  02APR09       2100  30SEP09   +0300
    +#                              2200  01APR10       2100  30SEP10   +0300
    +
    +# From Arthur David Olson (2008-03-17):
    +# Here's a link to English-language coverage by the Syrian Arab News
    +# Agency (SANA)...
    +# 
    +# http://www.sana.sy/eng/21/2008/03/11/165173.htm
    +# ...which reads (in part) "The Cabinet approved the suggestion of the
    +# Ministry of Electricity to begin daylight savings time on Friday April
    +# 4th, advancing clocks one hour ahead on midnight of Thursday April 3rd."
    +# Since Syria is two hours east of UTC, the 2200 and 2100 transition times
    +# shown above match up with midnight in Syria.
    +
    +# From Arthur David Olson (2008-03-18):
    +# My buest guess at a Syrian rule is "the Friday nearest April 1";
    +# coding that involves either using a "Mar Fri>=29" construct that old time zone
    +# compilers can't handle  or having multiple Rules (a la Israel).
    +# For now, use "Apr Fri>=1", and go with IATA on a uniform Sep 30 end.
    +
    +# From Steffen Thorsen (2008-10-07):
    +# Syria has now officially decided to end DST on 2008-11-01 this year,
    +# according to the following article in the Syrian Arab News Agency (SANA).
    +#
    +# The article is in Arabic, and seems to tell that they will go back to
    +# winter time on 2008-11-01 at 00:00 local daylight time (delaying/setting
    +# clocks back 60 minutes).
    +#
    +# 
    +# http://sana.sy/ara/2/2008/10/07/195459.htm
    +# 
    +
    +# From Steffen Thorsen (2009-03-19):
    +# Syria will start DST on 2009-03-27 00:00 this year according to many sources,
    +# two examples:
    +#
    +# 
    +# http://www.sana.sy/eng/21/2009/03/17/217563.htm
    +# 
    +# (English, Syrian Arab News # Agency)
    +# 
    +# http://thawra.alwehda.gov.sy/_View_news2.asp?FileName=94459258720090318012209
    +# 
    +# (Arabic, gov-site)
    +#
    +# We have not found any sources saying anything about when DST ends this year.
    +#
    +# Our summary
    +# 
    +# http://www.timeanddate.com/news/time/syria-dst-starts-march-27-2009.html
    +# 
    +
    +# From Steffen Thorsen (2009-10-27):
    +# The Syrian Arab News Network on 2009-09-29 reported that Syria will
    +# revert back to winter (standard) time on midnight between Thursday
    +# 2009-10-29 and Friday 2009-10-30:
    +# 
    +# http://www.sana.sy/ara/2/2009/09/29/247012.htm (Arabic)
    +# 
    +
    +# From Arthur David Olson (2009-10-28):
    +# We'll see if future DST switching times turn out to be end of the last
    +# Thursday of the month or the start of the last Friday of the month or
    +# something else. For now, use the start of the last Friday.
    +
    +# From Steffen Thorsen (2010-03-17):
    +# The "Syrian News Station" reported on 2010-03-16 that the Council of
    +# Ministers has decided that Syria will start DST on midnight Thursday
    +# 2010-04-01: (midnight between Thursday and Friday):
    +# 
    +# http://sns.sy/sns/?path=news/read/11421 (Arabic)
    +# 
    +
    +# From Steffen Thorsen (2012-03-26):
    +# Today, Syria's government announced that they will start DST early on Friday
    +# (00:00). This is a bit earlier than the past two years.
    +#
    +# From Syrian Arab News Agency, in Arabic:
    +# 
    +# http://www.sana.sy/ara/2/2012/03/26/408215.htm
    +# 
    +#
    +# Our brief summary:
    +# 
    +# http://www.timeanddate.com/news/time/syria-dst-2012.html
    +# 
    +
    +# From Arthur David Olson (2012-03-27):
    +# Assume last Friday in March going forward XXX.
    +
    +Rule	Syria	2008	only	-	Apr	Fri>=1	0:00	1:00	S
    +Rule	Syria	2008	only	-	Nov	1	0:00	0	-
    +Rule	Syria	2009	only	-	Mar	lastFri	0:00	1:00	S
    +Rule	Syria	2010	2011	-	Apr	Fri>=1	0:00	1:00	S
    +Rule	Syria	2012	max	-	Mar	lastFri	0:00	1:00	S
    +Rule	Syria	2009	max	-	Oct	lastFri	0:00	0	-
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Damascus	2:25:12 -	LMT	1920	# Dimashq
    +			2:00	Syria	EE%sT
    +
    +# Tajikistan
    +# From Shanks & Pottenger.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Dushanbe	4:35:12 -	LMT	1924 May  2
    +			5:00	-	DUST	1930 Jun 21 # Dushanbe Time
    +			6:00 RussiaAsia DUS%sT	1991 Mar 31 2:00s
    +			5:00	1:00	DUSST	1991 Sep  9 2:00s
    +			5:00	-	TJT		    # Tajikistan Time
    +
    +# Thailand
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Bangkok	6:42:04	-	LMT	1880
    +			6:42:04	-	BMT	1920 Apr # Bangkok Mean Time
    +			7:00	-	ICT
    +
    +# Turkmenistan
    +# From Shanks & Pottenger.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Ashgabat	3:53:32 -	LMT	1924 May  2 # or Ashkhabad
    +			4:00	-	ASHT	1930 Jun 21 # Ashkhabad Time
    +			5:00 RussiaAsia	ASH%sT	1991 Mar 31 2:00
    +			4:00 RussiaAsia	ASH%sT	1991 Oct 27 # independence
    +			4:00 RussiaAsia	TM%sT	1992 Jan 19 2:00
    +			5:00	-	TMT
    +
    +# United Arab Emirates
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Dubai	3:41:12 -	LMT	1920
    +			4:00	-	GST
    +
    +# Uzbekistan
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Samarkand	4:27:12 -	LMT	1924 May  2
    +			4:00	-	SAMT	1930 Jun 21 # Samarkand Time
    +			5:00	-	SAMT	1981 Apr  1
    +			5:00	1:00	SAMST	1981 Oct  1
    +			6:00	-	TAST	1982 Apr  1 # Tashkent Time
    +			5:00 RussiaAsia	SAM%sT	1991 Sep  1 # independence
    +			5:00 RussiaAsia	UZ%sT	1992
    +			5:00	-	UZT
    +Zone	Asia/Tashkent	4:37:12 -	LMT	1924 May  2
    +			5:00	-	TAST	1930 Jun 21 # Tashkent Time
    +			6:00 RussiaAsia	TAS%sT	1991 Mar 31 2:00
    +			5:00 RussiaAsia	TAS%sT	1991 Sep  1 # independence
    +			5:00 RussiaAsia	UZ%sT	1992
    +			5:00	-	UZT
    +
    +# Vietnam
    +
    +# From Arthur David Olson (2008-03-18):
    +# The English-language name of Vietnam's most populous city is "Ho Chi Min City";
    +# we use Ho_Chi_Minh below to avoid a name of more than 14 characters.
    +
    +# From Shanks & Pottenger:
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Ho_Chi_Minh	7:06:40 -	LMT	1906 Jun  9
    +			7:06:20	-	SMT	1911 Mar 11 0:01 # Saigon MT?
    +			7:00	-	ICT	1912 May
    +			8:00	-	ICT	1931 May
    +			7:00	-	ICT
    +
    +# Yemen
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Asia/Aden	3:00:48	-	LMT	1950
    +			3:00	-	AST
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/australasia b/jdk/test/sun/util/calendar/zi/tzdata/australasia
    new file mode 100644
    index 00000000000..7f83448f3fb
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/australasia
    @@ -0,0 +1,1742 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# This file also includes Pacific islands.
    +
    +# Notes are at the end of this file
    +
    +###############################################################################
    +
    +# Australia
    +
    +# Please see the notes below for the controversy about "EST" versus "AEST" etc.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Aus	1917	only	-	Jan	 1	0:01	1:00	-
    +Rule	Aus	1917	only	-	Mar	25	2:00	0	-
    +Rule	Aus	1942	only	-	Jan	 1	2:00	1:00	-
    +Rule	Aus	1942	only	-	Mar	29	2:00	0	-
    +Rule	Aus	1942	only	-	Sep	27	2:00	1:00	-
    +Rule	Aus	1943	1944	-	Mar	lastSun	2:00	0	-
    +Rule	Aus	1943	only	-	Oct	 3	2:00	1:00	-
    +# Go with Whitman and the Australian National Standards Commission, which
    +# says W Australia didn't use DST in 1943/1944.  Ignore Whitman's claim that
    +# 1944/1945 was just like 1943/1944.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +# Northern Territory
    +Zone Australia/Darwin	 8:43:20 -	LMT	1895 Feb
    +			 9:00	-	CST	1899 May
    +			 9:30	Aus	CST
    +# Western Australia
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	AW	1974	only	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AW	1975	only	-	Mar	Sun>=1	2:00s	0	-
    +Rule	AW	1983	only	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AW	1984	only	-	Mar	Sun>=1	2:00s	0	-
    +Rule	AW	1991	only	-	Nov	17	2:00s	1:00	-
    +Rule	AW	1992	only	-	Mar	Sun>=1	2:00s	0	-
    +Rule	AW	2006	only	-	Dec	 3	2:00s	1:00	-
    +Rule	AW	2007	2009	-	Mar	lastSun	2:00s	0	-
    +Rule	AW	2007	2008	-	Oct	lastSun	2:00s	1:00	-
    +Zone Australia/Perth	 7:43:24 -	LMT	1895 Dec
    +			 8:00	Aus	WST	1943 Jul
    +			 8:00	AW	WST
    +Zone Australia/Eucla	 8:35:28 -	LMT	1895 Dec
    +			 8:45	Aus	CWST	1943 Jul
    +			 8:45	AW	CWST
    +
    +# Queensland
    +#
    +# From Alex Livingston (1996-11-01):
    +# I have heard or read more than once that some resort islands off the coast
    +# of Queensland chose to keep observing daylight-saving time even after
    +# Queensland ceased to.
    +#
    +# From Paul Eggert (1996-11-22):
    +# IATA SSIM (1993-02/1994-09) say that the Holiday Islands (Hayman, Lindeman,
    +# Hamilton) observed DST for two years after the rest of Queensland stopped.
    +# Hamilton is the largest, but there is also a Hamilton in Victoria,
    +# so use Lindeman.
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	AQ	1971	only	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AQ	1972	only	-	Feb	lastSun	2:00s	0	-
    +Rule	AQ	1989	1991	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AQ	1990	1992	-	Mar	Sun>=1	2:00s	0	-
    +Rule	Holiday	1992	1993	-	Oct	lastSun	2:00s	1:00	-
    +Rule	Holiday	1993	1994	-	Mar	Sun>=1	2:00s	0	-
    +Zone Australia/Brisbane	10:12:08 -	LMT	1895
    +			10:00	Aus	EST	1971
    +			10:00	AQ	EST
    +Zone Australia/Lindeman  9:55:56 -	LMT	1895
    +			10:00	Aus	EST	1971
    +			10:00	AQ	EST	1992 Jul
    +			10:00	Holiday	EST
    +
    +# South Australia
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	AS	1971	1985	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AS	1986	only	-	Oct	19	2:00s	1:00	-
    +Rule	AS	1987	2007	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AS	1972	only	-	Feb	27	2:00s	0	-
    +Rule	AS	1973	1985	-	Mar	Sun>=1	2:00s	0	-
    +Rule	AS	1986	1990	-	Mar	Sun>=15	2:00s	0	-
    +Rule	AS	1991	only	-	Mar	3	2:00s	0	-
    +Rule	AS	1992	only	-	Mar	22	2:00s	0	-
    +Rule	AS	1993	only	-	Mar	7	2:00s	0	-
    +Rule	AS	1994	only	-	Mar	20	2:00s	0	-
    +Rule	AS	1995	2005	-	Mar	lastSun	2:00s	0	-
    +Rule	AS	2006	only	-	Apr	2	2:00s	0	-
    +Rule	AS	2007	only	-	Mar	lastSun	2:00s	0	-
    +Rule	AS	2008	max	-	Apr	Sun>=1	2:00s	0	-
    +Rule	AS	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Australia/Adelaide	9:14:20 -	LMT	1895 Feb
    +			9:00	-	CST	1899 May
    +			9:30	Aus	CST	1971
    +			9:30	AS	CST
    +
    +# Tasmania
    +#
    +# From Paul Eggert (2005-08-16):
    +# 
    +# says King Island didn't observe DST from WWII until late 1971.
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	AT	1967	only	-	Oct	Sun>=1	2:00s	1:00	-
    +Rule	AT	1968	only	-	Mar	lastSun	2:00s	0	-
    +Rule	AT	1968	1985	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AT	1969	1971	-	Mar	Sun>=8	2:00s	0	-
    +Rule	AT	1972	only	-	Feb	lastSun	2:00s	0	-
    +Rule	AT	1973	1981	-	Mar	Sun>=1	2:00s	0	-
    +Rule	AT	1982	1983	-	Mar	lastSun	2:00s	0	-
    +Rule	AT	1984	1986	-	Mar	Sun>=1	2:00s	0	-
    +Rule	AT	1986	only	-	Oct	Sun>=15	2:00s	1:00	-
    +Rule	AT	1987	1990	-	Mar	Sun>=15	2:00s	0	-
    +Rule	AT	1987	only	-	Oct	Sun>=22	2:00s	1:00	-
    +Rule	AT	1988	1990	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AT	1991	1999	-	Oct	Sun>=1	2:00s	1:00	-
    +Rule	AT	1991	2005	-	Mar	lastSun	2:00s	0	-
    +Rule	AT	2000	only	-	Aug	lastSun	2:00s	1:00	-
    +Rule	AT	2001	max	-	Oct	Sun>=1	2:00s	1:00	-
    +Rule	AT	2006	only	-	Apr	Sun>=1	2:00s	0	-
    +Rule	AT	2007	only	-	Mar	lastSun	2:00s	0	-
    +Rule	AT	2008	max	-	Apr	Sun>=1	2:00s	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Australia/Hobart	9:49:16	-	LMT	1895 Sep
    +			10:00	-	EST	1916 Oct 1 2:00
    +			10:00	1:00	EST	1917 Feb
    +			10:00	Aus	EST	1967
    +			10:00	AT	EST
    +Zone Australia/Currie	9:35:28	-	LMT	1895 Sep
    +			10:00	-	EST	1916 Oct 1 2:00
    +			10:00	1:00	EST	1917 Feb
    +			10:00	Aus	EST	1971 Jul
    +			10:00	AT	EST
    +
    +# Victoria
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	AV	1971	1985	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AV	1972	only	-	Feb	lastSun	2:00s	0	-
    +Rule	AV	1973	1985	-	Mar	Sun>=1	2:00s	0	-
    +Rule	AV	1986	1990	-	Mar	Sun>=15	2:00s	0	-
    +Rule	AV	1986	1987	-	Oct	Sun>=15	2:00s	1:00	-
    +Rule	AV	1988	1999	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AV	1991	1994	-	Mar	Sun>=1	2:00s	0	-
    +Rule	AV	1995	2005	-	Mar	lastSun	2:00s	0	-
    +Rule	AV	2000	only	-	Aug	lastSun	2:00s	1:00	-
    +Rule	AV	2001	2007	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AV	2006	only	-	Apr	Sun>=1	2:00s	0	-
    +Rule	AV	2007	only	-	Mar	lastSun	2:00s	0	-
    +Rule	AV	2008	max	-	Apr	Sun>=1	2:00s	0	-
    +Rule	AV	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Australia/Melbourne 9:39:52 -	LMT	1895 Feb
    +			10:00	Aus	EST	1971
    +			10:00	AV	EST
    +
    +# New South Wales
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	AN	1971	1985	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AN	1972	only	-	Feb	27	2:00s	0	-
    +Rule	AN	1973	1981	-	Mar	Sun>=1	2:00s	0	-
    +Rule	AN	1982	only	-	Apr	Sun>=1	2:00s	0	-
    +Rule	AN	1983	1985	-	Mar	Sun>=1	2:00s	0	-
    +Rule	AN	1986	1989	-	Mar	Sun>=15	2:00s	0	-
    +Rule	AN	1986	only	-	Oct	19	2:00s	1:00	-
    +Rule	AN	1987	1999	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AN	1990	1995	-	Mar	Sun>=1	2:00s	0	-
    +Rule	AN	1996	2005	-	Mar	lastSun	2:00s	0	-
    +Rule	AN	2000	only	-	Aug	lastSun	2:00s	1:00	-
    +Rule	AN	2001	2007	-	Oct	lastSun	2:00s	1:00	-
    +Rule	AN	2006	only	-	Apr	Sun>=1	2:00s	0	-
    +Rule	AN	2007	only	-	Mar	lastSun	2:00s	0	-
    +Rule	AN	2008	max	-	Apr	Sun>=1	2:00s	0	-
    +Rule	AN	2008	max	-	Oct	Sun>=1	2:00s	1:00	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Australia/Sydney	10:04:52 -	LMT	1895 Feb
    +			10:00	Aus	EST	1971
    +			10:00	AN	EST
    +Zone Australia/Broken_Hill 9:25:48 -	LMT	1895 Feb
    +			10:00	-	EST	1896 Aug 23
    +			9:00	-	CST	1899 May
    +			9:30	Aus	CST	1971
    +			9:30	AN	CST	2000
    +			9:30	AS	CST
    +
    +# Lord Howe Island
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	LH	1981	1984	-	Oct	lastSun	2:00	1:00	-
    +Rule	LH	1982	1985	-	Mar	Sun>=1	2:00	0	-
    +Rule	LH	1985	only	-	Oct	lastSun	2:00	0:30	-
    +Rule	LH	1986	1989	-	Mar	Sun>=15	2:00	0	-
    +Rule	LH	1986	only	-	Oct	19	2:00	0:30	-
    +Rule	LH	1987	1999	-	Oct	lastSun	2:00	0:30	-
    +Rule	LH	1990	1995	-	Mar	Sun>=1	2:00	0	-
    +Rule	LH	1996	2005	-	Mar	lastSun	2:00	0	-
    +Rule	LH	2000	only	-	Aug	lastSun	2:00	0:30	-
    +Rule	LH	2001	2007	-	Oct	lastSun	2:00	0:30	-
    +Rule	LH	2006	only	-	Apr	Sun>=1	2:00	0	-
    +Rule	LH	2007	only	-	Mar	lastSun	2:00	0	-
    +Rule	LH	2008	max	-	Apr	Sun>=1	2:00	0	-
    +Rule	LH	2008	max	-	Oct	Sun>=1	2:00	0:30	-
    +Zone Australia/Lord_Howe 10:36:20 -	LMT	1895 Feb
    +			10:00	-	EST	1981 Mar
    +			10:30	LH	LHST
    +
    +# Australian miscellany
    +#
    +# Ashmore Is, Cartier
    +# no indigenous inhabitants; only seasonal caretakers
    +# no times are set
    +#
    +# Coral Sea Is
    +# no indigenous inhabitants; only meteorologists
    +# no times are set
    +#
    +# Macquarie
    +# permanent occupation (scientific station) since 1948;
    +# sealing and penguin oil station operated 1888/1917
    +# like Australia/Hobart
    +
    +# Christmas
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Indian/Christmas	7:02:52 -	LMT	1895 Feb
    +			7:00	-	CXT	# Christmas Island Time
    +
    +# Cook Is
    +# From Shanks & Pottenger:
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Cook	1978	only	-	Nov	12	0:00	0:30	HS
    +Rule	Cook	1979	1991	-	Mar	Sun>=1	0:00	0	-
    +Rule	Cook	1979	1990	-	Oct	lastSun	0:00	0:30	HS
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Rarotonga	-10:39:04 -	LMT	1901		# Avarua
    +			-10:30	-	CKT	1978 Nov 12	# Cook Is Time
    +			-10:00	Cook	CK%sT
    +
    +# Cocos
    +# These islands were ruled by the Ross family from about 1830 to 1978.
    +# We don't know when standard time was introduced; for now, we guess 1900.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Indian/Cocos	6:27:40	-	LMT	1900
    +			6:30	-	CCT	# Cocos Islands Time
    +
    +# Fiji
    +# From Alexander Krivenyshev (2009-11-10):
    +# According to Fiji Broadcasting Corporation,  Fiji plans to re-introduce DST
    +# from November 29th 2009  to April 25th 2010.
    +#
    +# "Daylight savings to commence this month"
    +# 
    +# http://www.radiofiji.com.fj/fullstory.php?id=23719
    +# 
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_fiji01.html
    +# 
    +
    +# From Steffen Thorsen (2009-11-10):
    +# The Fiji Government has posted some more details about the approved
    +# amendments:
    +# 
    +# http://www.fiji.gov.fj/publish/page_16198.shtml
    +# 
    +
    +# From Steffen Thorsen (2010-03-03):
    +# The Cabinet in Fiji has decided to end DST about a month early, on
    +# 2010-03-28 at 03:00.
    +# The plan is to observe DST again, from 2010-10-24 to sometime in March
    +# 2011 (last Sunday a good guess?).
    +#
    +# Official source:
    +# 
    +# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=1096:3310-cabinet-approves-change-in-daylight-savings-dates&catid=49:cabinet-releases&Itemid=166
    +# 
    +#
    +# A bit more background info here:
    +# 
    +# http://www.timeanddate.com/news/time/fiji-dst-ends-march-2010.html
    +# 
    +
    +# From Alexander Krivenyshev (2010-10-24):
    +# According to Radio Fiji and Fiji Times online, Fiji will end DST 3
    +# weeks earlier than expected - on March 6, 2011, not March 27, 2011...
    +# Here is confirmation from Government of the Republic of the Fiji Islands,
    +# Ministry of Information (fiji.gov.fj) web site:
    +# 
    +# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=2608:daylight-savings&catid=71:press-releases&Itemid=155
    +# 
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_fiji04.html
    +# 
    +
    +# From Steffen Thorsen (2011-10-03):
    +# Now the dates have been confirmed, and at least our start date
    +# assumption was correct (end date was one week wrong).
    +#
    +# 
    +# www.fiji.gov.fj/index.php?option=com_content&view=article&id=4966:daylight-saving-starts-in-fiji&catid=71:press-releases&Itemid=155
    +# 
    +# which says
    +# Members of the public are reminded to change their time to one hour in
    +# advance at 2am to 3am on October 23, 2011 and one hour back at 3am to
    +# 2am on February 26 next year.
    +
    +# From Ken Rylander (2011-10-24)
    +# Another change to the Fiji DST end date. In the TZ database the end date for
    +# Fiji DST 2012, is currently Feb 26. This has been changed to Jan 22.
    +#
    +# 
    +# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=5017:amendments-to-daylight-savings&catid=71:press-releases&Itemid=155
    +# 
    +# states:
    +#
    +# The end of daylight saving scheduled initially for the 26th of February 2012
    +# has been brought forward to the 22nd of January 2012.
    +# The commencement of daylight saving will remain unchanged and start
    +# on the  23rd of October, 2011.
    +
    +# From the Fiji Government Online Portal (2012-08-21) via Steffen Thorsen:
    +# The Minister for Labour, Industrial Relations and Employment Mr Jone Usamate
    +# today confirmed that Fiji will start daylight savings at 2 am on Sunday 21st
    +# October 2012 and end at 3 am on Sunday 20th January 2013.
    +# http://www.fiji.gov.fj/index.php?option=com_content&view=article&id=6702&catid=71&Itemid=155
    +#
    +# From Paul Eggert (2012-08-31):
    +# For now, guess a pattern of the penultimate Sundays in October and January.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Fiji	1998	1999	-	Nov	Sun>=1	2:00	1:00	S
    +Rule	Fiji	1999	2000	-	Feb	lastSun	3:00	0	-
    +Rule	Fiji	2009	only	-	Nov	29	2:00	1:00	S
    +Rule	Fiji	2010	only	-	Mar	lastSun	3:00	0	-
    +Rule	Fiji	2010	max	-	Oct	Sun>=18	2:00	1:00	S
    +Rule	Fiji	2011	only	-	Mar	Sun>=1	3:00	0	-
    +Rule	Fiji	2012	max	-	Jan	Sun>=18	3:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Pacific/Fiji	11:53:40 -	LMT	1915 Oct 26	# Suva
    +			12:00	Fiji	FJ%sT	# Fiji Time
    +
    +# French Polynesia
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Pacific/Gambier	 -8:59:48 -	LMT	1912 Oct	# Rikitea
    +			 -9:00	-	GAMT	# Gambier Time
    +Zone	Pacific/Marquesas -9:18:00 -	LMT	1912 Oct
    +			 -9:30	-	MART	# Marquesas Time
    +Zone	Pacific/Tahiti	 -9:58:16 -	LMT	1912 Oct	# Papeete
    +			-10:00	-	TAHT	# Tahiti Time
    +# Clipperton (near North America) is administered from French Polynesia;
    +# it is uninhabited.
    +
    +# Guam
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Pacific/Guam	-14:21:00 -	LMT	1844 Dec 31
    +			 9:39:00 -	LMT	1901		# Agana
    +			10:00	-	GST	2000 Dec 23	# Guam
    +			10:00	-	ChST	# Chamorro Standard Time
    +
    +# Kiribati
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Tarawa	 11:32:04 -	LMT	1901		# Bairiki
    +			 12:00	-	GILT		 # Gilbert Is Time
    +Zone Pacific/Enderbury	-11:24:20 -	LMT	1901
    +			-12:00	-	PHOT	1979 Oct # Phoenix Is Time
    +			-11:00	-	PHOT	1995
    +			 13:00	-	PHOT
    +Zone Pacific/Kiritimati	-10:29:20 -	LMT	1901
    +			-10:40	-	LINT	1979 Oct # Line Is Time
    +			-10:00	-	LINT	1995
    +			 14:00	-	LINT
    +
    +# N Mariana Is
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Saipan	-14:17:00 -	LMT	1844 Dec 31
    +			 9:43:00 -	LMT	1901
    +			 9:00	-	MPT	1969 Oct # N Mariana Is Time
    +			10:00	-	MPT	2000 Dec 23
    +			10:00	-	ChST	# Chamorro Standard Time
    +
    +# Marshall Is
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Majuro	11:24:48 -	LMT	1901
    +			11:00	-	MHT	1969 Oct # Marshall Islands Time
    +			12:00	-	MHT
    +Zone Pacific/Kwajalein	11:09:20 -	LMT	1901
    +			11:00	-	MHT	1969 Oct
    +			-12:00	-	KWAT	1993 Aug 20	# Kwajalein Time
    +			12:00	-	MHT
    +
    +# Micronesia
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Chuuk	10:07:08 -	LMT	1901
    +			10:00	-	CHUT			# Chuuk Time
    +Zone Pacific/Pohnpei	10:32:52 -	LMT	1901		# Kolonia
    +			11:00	-	PONT			# Pohnpei Time
    +Zone Pacific/Kosrae	10:51:56 -	LMT	1901
    +			11:00	-	KOST	1969 Oct	# Kosrae Time
    +			12:00	-	KOST	1999
    +			11:00	-	KOST
    +
    +# Nauru
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Pacific/Nauru	11:07:40 -	LMT	1921 Jan 15	# Uaobe
    +			11:30	-	NRT	1942 Mar 15	# Nauru Time
    +			9:00	-	JST	1944 Aug 15
    +			11:30	-	NRT	1979 May
    +			12:00	-	NRT
    +
    +# New Caledonia
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	NC	1977	1978	-	Dec	Sun>=1	0:00	1:00	S
    +Rule	NC	1978	1979	-	Feb	27	0:00	0	-
    +Rule	NC	1996	only	-	Dec	 1	2:00s	1:00	S
    +# Shanks & Pottenger say the following was at 2:00; go with IATA.
    +Rule	NC	1997	only	-	Mar	 2	2:00s	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Pacific/Noumea	11:05:48 -	LMT	1912 Jan 13
    +			11:00	NC	NC%sT
    +
    +
    +###############################################################################
    +
    +# New Zealand
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	NZ	1927	only	-	Nov	 6	2:00	1:00	S
    +Rule	NZ	1928	only	-	Mar	 4	2:00	0	M
    +Rule	NZ	1928	1933	-	Oct	Sun>=8	2:00	0:30	S
    +Rule	NZ	1929	1933	-	Mar	Sun>=15	2:00	0	M
    +Rule	NZ	1934	1940	-	Apr	lastSun	2:00	0	M
    +Rule	NZ	1934	1940	-	Sep	lastSun	2:00	0:30	S
    +Rule	NZ	1946	only	-	Jan	 1	0:00	0	S
    +# Since 1957 Chatham has been 45 minutes ahead of NZ, but there's no
    +# convenient notation for this so we must duplicate the Rule lines.
    +Rule	NZ	1974	only	-	Nov	Sun>=1	2:00s	1:00	D
    +Rule	Chatham	1974	only	-	Nov	Sun>=1	2:45s	1:00	D
    +Rule	NZ	1975	only	-	Feb	lastSun	2:00s	0	S
    +Rule	Chatham	1975	only	-	Feb	lastSun	2:45s	0	S
    +Rule	NZ	1975	1988	-	Oct	lastSun	2:00s	1:00	D
    +Rule	Chatham	1975	1988	-	Oct	lastSun	2:45s	1:00	D
    +Rule	NZ	1976	1989	-	Mar	Sun>=1	2:00s	0	S
    +Rule	Chatham	1976	1989	-	Mar	Sun>=1	2:45s	0	S
    +Rule	NZ	1989	only	-	Oct	Sun>=8	2:00s	1:00	D
    +Rule	Chatham	1989	only	-	Oct	Sun>=8	2:45s	1:00	D
    +Rule	NZ	1990	2006	-	Oct	Sun>=1	2:00s	1:00	D
    +Rule	Chatham	1990	2006	-	Oct	Sun>=1	2:45s	1:00	D
    +Rule	NZ	1990	2007	-	Mar	Sun>=15	2:00s	0	S
    +Rule	Chatham	1990	2007	-	Mar	Sun>=15	2:45s	0	S
    +Rule	NZ	2007	max	-	Sep	lastSun	2:00s	1:00	D
    +Rule	Chatham	2007	max	-	Sep	lastSun	2:45s	1:00	D
    +Rule	NZ	2008	max	-	Apr	Sun>=1	2:00s	0	S
    +Rule	Chatham	2008	max	-	Apr	Sun>=1	2:45s	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Auckland	11:39:04 -	LMT	1868 Nov  2
    +			11:30	NZ	NZ%sT	1946 Jan  1
    +			12:00	NZ	NZ%sT
    +Zone Pacific/Chatham	12:13:48 -	LMT	1957 Jan  1
    +			12:45	Chatham	CHA%sT
    +
    +
    +# Auckland Is
    +# uninhabited; Maori and Moriori, colonial settlers, pastoralists, sealers,
    +# and scientific personnel have wintered
    +
    +# Campbell I
    +# minor whaling stations operated 1909/1914
    +# scientific station operated 1941/1995;
    +# previously whalers, sealers, pastoralists, and scientific personnel wintered
    +# was probably like Pacific/Auckland
    +
    +###############################################################################
    +
    +
    +# Niue
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Pacific/Niue	-11:19:40 -	LMT	1901		# Alofi
    +			-11:20	-	NUT	1951	# Niue Time
    +			-11:30	-	NUT	1978 Oct 1
    +			-11:00	-	NUT
    +
    +# Norfolk
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Pacific/Norfolk	11:11:52 -	LMT	1901		# Kingston
    +			11:12	-	NMT	1951	# Norfolk Mean Time
    +			11:30	-	NFT		# Norfolk Time
    +
    +# Palau (Belau)
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Palau	8:57:56 -	LMT	1901		# Koror
    +			9:00	-	PWT	# Palau Time
    +
    +# Papua New Guinea
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Port_Moresby 9:48:40 -	LMT	1880
    +			9:48:32	-	PMMT	1895	# Port Moresby Mean Time
    +			10:00	-	PGT		# Papua New Guinea Time
    +
    +# Pitcairn
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Pitcairn	-8:40:20 -	LMT	1901		# Adamstown
    +			-8:30	-	PNT	1998 Apr 27 00:00
    +			-8:00	-	PST	# Pitcairn Standard Time
    +
    +# American Samoa
    +Zone Pacific/Pago_Pago	 12:37:12 -	LMT	1879 Jul  5
    +			-11:22:48 -	LMT	1911
    +			-11:30	-	SAMT	1950		# Samoa Time
    +			-11:00	-	NST	1967 Apr	# N=Nome
    +			-11:00	-	BST	1983 Nov 30	# B=Bering
    +			-11:00	-	SST			# S=Samoa
    +
    +# Samoa
    +
    +# From Steffen Thorsen (2009-10-16):
    +# We have been in contact with the government of Samoa again, and received
    +# the following info:
    +#
    +# "Cabinet has now approved Daylight Saving to be effected next year
    +# commencing from the last Sunday of September 2010 and conclude first
    +# Sunday of April 2011."
    +#
    +# Background info:
    +# 
    +# http://www.timeanddate.com/news/time/samoa-dst-plan-2009.html
    +# 
    +#
    +# Samoa's Daylight Saving Time Act 2009 is available here, but does not
    +# contain any dates:
    +# 
    +# http://www.parliament.gov.ws/documents/acts/Daylight%20Saving%20Act%20%202009%20%28English%29%20-%20Final%207-7-091.pdf
    +# 
    +
    +# From Laupue Raymond Hughes (2010-10-07):
    +# Please see
    +# 
    +# http://www.mcil.gov.ws
    +# ,
    +# the Ministry of Commerce, Industry and Labour (sideframe) "Last Sunday
    +# September 2010 (26/09/10) - adjust clocks forward from 12:00 midnight
    +# to 01:00am and First Sunday April 2011 (03/04/11) - adjust clocks
    +# backwards from 1:00am to 12:00am"
    +
    +# From Laupue Raymond Hughes (2011-03-07):
    +# I believe this will be posted shortly on the website
    +# 
    +# www.mcil.gov.ws
    +# 
    +#
    +# PUBLIC NOTICE ON DAYLIGHT SAVING TIME
    +#
    +# Pursuant to the Daylight Saving Act 2009 and Cabinets decision,
    +# businesses and the general public are hereby advised that daylight
    +# saving time is on the first Saturday of April 2011 (02/04/11).
    +#
    +# The public is therefore advised that when the standard time strikes
    +# the hour of four oclock (4.00am or 0400 Hours) on the 2nd April 2011,
    +# then all instruments used to measure standard time are to be
    +# adjusted/changed to three oclock (3:00am or 0300Hrs).
    +#
    +# Margaret Fruean ACTING CHIEF EXECUTIVE OFFICER MINISTRY OF COMMERCE,
    +# INDUSTRY AND LABOUR 28th February 2011
    +
    +# From David Zuelke (2011-05-09):
    +# Subject: Samoa to move timezone from east to west of international date line
    +#
    +# 
    +# http://www.morningstar.co.uk/uk/markets/newsfeeditem.aspx?id=138501958347963
    +# 
    +
    +# From Mark Sim-Smith (2011-08-17):
    +# I have been in contact with Leilani Tuala Warren from the Samoa Law
    +# Reform Commission, and she has sent me a copy of the Bill that she
    +# confirmed has been passed...Most of the sections are about maps rather
    +# than the time zone change, but I'll paste the relevant bits below. But
    +# the essence is that at midnight 29 Dec (UTC-11 I suppose), Samoa
    +# changes from UTC-11 to UTC+13:
    +#
    +# International Date Line Bill 2011
    +#
    +# AN ACT to provide for the change to standard time in Samoa and to make
    +# consequential amendments to the position of the International Date
    +# Line, and for related purposes.
    +#
    +# BE IT ENACTED by the Legislative Assembly of Samoa in Parliament
    +# assembled as follows:
    +#
    +# 1. Short title and commencement-(1) This Act may be cited as the
    +# International Date Line Act 2011. (2) Except for section 5(3) this Act
    +# commences at 12 o'clock midnight, on Thursday 29th December 2011. (3)
    +# Section 5(3) commences on the date of assent by the Head of State.
    +#
    +# [snip]
    +#
    +# 3. Interpretation - [snip] "Samoa standard time" in this Act and any
    +# other statute of Samoa which refers to 'Samoa standard time' means the
    +# time 13 hours in advance of Co-ordinated Universal Time.
    +#
    +# 4. Samoa standard time - (1) Upon the commencement of this Act, Samoa
    +# standard time shall be set at 13 hours in advance of Co-ordinated
    +# Universal Time for the whole of Samoa. (2) All references to Samoa's
    +# time zone and to Samoa standard time in Samoa in all legislation and
    +# instruments after the commencement of this Act shall be references to
    +# Samoa standard time as provided for in this Act. (3) Nothing in this
    +# Act affects the provisions of the Daylight Saving Act 2009, except that
    +# it defines Samoa standard time....
    +
    +# From Laupue Raymond Hughes (2011-09-02):
    +# 
    +# http://www.mcil.gov.ws/mcil_publications.html
    +# 
    +#
    +# here is the official website publication for Samoa DST and dateline change
    +#
    +# DST
    +# Year	End	Time	Start	Time
    +# 2011	- - -	- - -	24 September	3:00am to 4:00am
    +# 2012	01 April	4:00am to 3:00am	- - -	- - -
    +#
    +# Dateline Change skip Friday 30th Dec 2011
    +# Thursday 29th December 2011	23:59:59 Hours
    +# Saturday 31st December 2011	00:00:00 Hours
    +#
    +# Clarification by Tim Parenti (2012-01-03):
    +# Although Samoa has used Daylight Saving Time in the 2010-2011 and 2011-2012
    +# seasons, there is not yet any indication that this trend will continue on
    +# a regular basis. For now, we have explicitly listed the transitions below.
    +#
    +# From Nicky (2012-09-10):
    +# Daylight Saving Time commences on Sunday 30th September 2012 and
    +# ends on Sunday 7th of April 2013.
    +#
    +# Please find link below for more information.
    +# http://www.mcil.gov.ws/mcil_publications.html
    +#
    +# That publication also includes dates for Summer of 2013/4 as well
    +# which give the impression of a pattern in selecting dates for the
    +# future, so for now, we will guess this will continue.
    +
    +# Western Samoa
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	WS	2012	max	-	Sep	lastSun	3:00	1	D
    +Rule	WS	2012	max	-	Apr	Sun>=1	4:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Apia	 12:33:04 -	LMT	1879 Jul  5
    +			-11:26:56 -	LMT	1911
    +			-11:30	-	SAMT	1950		# Samoa Time
    +			-11:00	-	WST	2010 Sep 26
    +			-11:00	1:00	WSDT	2011 Apr 2 4:00
    +			-11:00	-	WST	2011 Sep 24 3:00
    +			-11:00	1:00	WSDT	2011 Dec 30
    +			 13:00	1:00	WSDT	2012 Apr Sun>=1 4:00
    +			 13:00	WS	WS%sT
    +
    +# Solomon Is
    +# excludes Bougainville, for which see Papua New Guinea
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Guadalcanal 10:39:48 -	LMT	1912 Oct	# Honiara
    +			11:00	-	SBT	# Solomon Is Time
    +
    +# Tokelau Is
    +#
    +# From Gwillim Law (2011-12-29)
    +# A correspondent informed me that Tokelau, like Samoa, will be skipping
    +# December 31 this year ...
    +#
    +# From Steffen Thorsen (2012-07-25)
    +# ... we double checked by calling hotels and offices based in Tokelau asking
    +# about the time there, and they all told a time that agrees with UTC+13....
    +# Shanks says UTC-10 from 1901 [but] ... there is a good chance the change
    +# actually was to UTC-11 back then.
    +#
    +# From Paul Eggert (2012-07-25)
    +# A Google Books snippet of Appendix to the Journals of the House of
    +# Representatives of New Zealand, Session 1948,
    +# , page 65, says Tokelau
    +# was "11 hours slow on G.M.T."  Go with Thorsen and assume Shanks & Pottenger
    +# are off by an hour starting in 1901.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Pacific/Fakaofo	-11:24:56 -	LMT	1901
    +			-11:00	-	TKT 2011 Dec 30	# Tokelau Time
    +			13:00	-	TKT
    +
    +# Tonga
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Tonga	1999	only	-	Oct	 7	2:00s	1:00	S
    +Rule	Tonga	2000	only	-	Mar	19	2:00s	0	-
    +Rule	Tonga	2000	2001	-	Nov	Sun>=1	2:00	1:00	S
    +Rule	Tonga	2001	2002	-	Jan	lastSun	2:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Tongatapu	12:19:20 -	LMT	1901
    +			12:20	-	TOT	1941 # Tonga Time
    +			13:00	-	TOT	1999
    +			13:00	Tonga	TO%sT
    +
    +# Tuvalu
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Funafuti	11:56:52 -	LMT	1901
    +			12:00	-	TVT	# Tuvalu Time
    +
    +
    +# US minor outlying islands
    +
    +# Howland, Baker
    +# Howland was mined for guano by American companies 1857-1878 and British
    +# 1886-1891; Baker was similar but exact dates are not known.
    +# Inhabited by civilians 1935-1942; U.S. military bases 1943-1944;
    +# uninhabited thereafter.
    +# Howland observed Hawaii Standard Time (UTC-10:30) in 1937;
    +# see page 206 of Elgen M. Long and Marie K. Long,
    +# Amelia Earhart: the Mystery Solved, Simon & Schuster (2000).
    +# So most likely Howland and Baker observed Hawaii Time from 1935
    +# until they were abandoned after the war.
    +
    +# Jarvis
    +# Mined for guano by American companies 1857-1879 and British 1883?-1891?.
    +# Inhabited by civilians 1935-1942; IGY scientific base 1957-1958;
    +# uninhabited thereafter.
    +# no information; was probably like Pacific/Kiritimati
    +
    +# Johnston
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Pacific/Johnston	-10:00	-	HST
    +
    +# Kingman
    +# uninhabited
    +
    +# Midway
    +#
    +# From Mark Brader (2005-01-23):
    +# [Fallacies and Fantasies of Air Transport History, by R.E.G. Davies,
    +# published 1994 by Paladwr Press, McLean, VA, USA; ISBN 0-9626483-5-3]
    +# reproduced a Pan American Airways timeables from 1936, for their weekly
    +# "Orient Express" flights between San Francisco and Manila, and connecting
    +# flights to Chicago and the US East Coast.  As it uses some time zone
    +# designations that I've never seen before:....
    +# Fri. 6:30A Lv. HONOLOLU (Pearl Harbor), H.I.   H.L.T. Ar. 5:30P Sun.
    +#  "   3:00P Ar. MIDWAY ISLAND . . . . . . . . . M.L.T. Lv. 6:00A  "
    +#
    +Zone Pacific/Midway	-11:49:28 -	LMT	1901
    +			-11:00	-	NST	1956 Jun  3
    +			-11:00	1:00	NDT	1956 Sep  2
    +			-11:00	-	NST	1967 Apr	# N=Nome
    +			-11:00	-	BST	1983 Nov 30	# B=Bering
    +			-11:00	-	SST			# S=Samoa
    +
    +# Palmyra
    +# uninhabited since World War II; was probably like Pacific/Kiritimati
    +
    +# Wake
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Pacific/Wake	11:06:28 -	LMT	1901
    +			12:00	-	WAKT	# Wake Time
    +
    +
    +# Vanuatu
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Vanuatu	1983	only	-	Sep	25	0:00	1:00	S
    +Rule	Vanuatu	1984	1991	-	Mar	Sun>=23	0:00	0	-
    +Rule	Vanuatu	1984	only	-	Oct	23	0:00	1:00	S
    +Rule	Vanuatu	1985	1991	-	Sep	Sun>=23	0:00	1:00	S
    +Rule	Vanuatu	1992	1993	-	Jan	Sun>=23	0:00	0	-
    +Rule	Vanuatu	1992	only	-	Oct	Sun>=23	0:00	1:00	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Pacific/Efate	11:13:16 -	LMT	1912 Jan 13		# Vila
    +			11:00	Vanuatu	VU%sT	# Vanuatu Time
    +
    +# Wallis and Futuna
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Pacific/Wallis	12:15:20 -	LMT	1901
    +			12:00	-	WFT	# Wallis & Futuna Time
    +
    +###############################################################################
    +
    +# NOTES
    +
    +# This data is by no means authoritative; if you think you know better,
    +# go ahead and edit the file (and please send any changes to
    +# tz@elsie.nci.nih.gov for general use in the future).
    +
    +# From Paul Eggert (2006-03-22):
    +# A good source for time zone historical data outside the U.S. is
    +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
    +# San Diego: ACS Publications, Inc. (2003).
    +#
    +# Gwillim Law writes that a good source
    +# for recent time zone data is the International Air Transport
    +# Association's Standard Schedules Information Manual (IATA SSIM),
    +# published semiannually.  Law sent in several helpful summaries
    +# of the IATA's data after 1990.
    +#
    +# Except where otherwise noted, Shanks & Pottenger is the source for
    +# entries through 1990, and IATA SSIM is the source for entries afterwards.
    +#
    +# Another source occasionally used is Edward W. Whitman, World Time Differences,
    +# Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated), which
    +# I found in the UCLA library.
    +#
    +# A reliable and entertaining source about time zones is
    +# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
    +#
    +# I invented the abbreviations marked `*' in the following table;
    +# the rest are from earlier versions of this file, or from other sources.
    +# Corrections are welcome!
    +#		std dst
    +#		LMT	Local Mean Time
    +#	  8:00	WST WST	Western Australia
    +#	  8:45	CWST CWST Central Western Australia*
    +#	  9:00	JST	Japan
    +#	  9:30	CST CST	Central Australia
    +#	 10:00	EST EST	Eastern Australia
    +#	 10:00	ChST	Chamorro
    +#	 10:30	LHST LHST Lord Howe*
    +#	 11:30	NZMT NZST New Zealand through 1945
    +#	 12:00	NZST NZDT New Zealand 1946-present
    +#	 12:45	CHAST CHADT Chatham*
    +#	-11:00	SST	Samoa
    +#	-10:00	HST	Hawaii
    +#	- 8:00	PST	Pitcairn*
    +#
    +# See the `northamerica' file for Hawaii.
    +# See the `southamerica' file for Easter I and the Galapagos Is.
    +
    +###############################################################################
    +
    +# Australia
    +
    +# From Paul Eggert (2005-12-08):
    +# 
    +# Implementation Dates of Daylight Saving Time within Australia
    +#  summarizes daylight saving issues in Australia.
    +
    +# From Arthur David Olson (2005-12-12):
    +# 
    +# Lawlink NSW:Daylight Saving in New South Wales
    +#  covers New South Wales in particular.
    +
    +# From John Mackin (1991-03-06):
    +# We in Australia have _never_ referred to DST as `daylight' time.
    +# It is called `summer' time.  Now by a happy coincidence, `summer'
    +# and `standard' happen to start with the same letter; hence, the
    +# abbreviation does _not_ change...
    +# The legislation does not actually define abbreviations, at least
    +# in this State, but the abbreviation is just commonly taken to be the
    +# initials of the phrase, and the legislation here uniformly uses
    +# the phrase `summer time' and does not use the phrase `daylight
    +# time'.
    +# Announcers on the Commonwealth radio network, the ABC (for Australian
    +# Broadcasting Commission), use the phrases `Eastern Standard Time'
    +# or `Eastern Summer Time'.  (Note, though, that as I say in the
    +# current australasia file, there is really no such thing.)  Announcers
    +# on its overseas service, Radio Australia, use the same phrases
    +# prefixed by the word `Australian' when referring to local times;
    +# time announcements on that service, naturally enough, are made in UTC.
    +
    +# From Arthur David Olson (1992-03-08):
    +# Given the above, what's chosen for year-round use is:
    +#	CST	for any place operating at a GMTOFF of 9:30
    +#	WST	for any place operating at a GMTOFF of 8:00
    +#	EST	for any place operating at a GMTOFF of 10:00
    +
    +# From Chuck Soper (2006-06-01):
    +# I recently found this Australian government web page on time zones:
    +# 
    +# And this government web page lists time zone names and abbreviations:
    +# 
    +
    +# From Paul Eggert (2001-04-05), summarizing a long discussion about "EST"
    +# versus "AEST" etc.:
    +#
    +# I see the following points of dispute:
    +#
    +# * How important are unique time zone abbreviations?
    +#
    +#   Here I tend to agree with the point (most recently made by Chris
    +#   Newman) that unique abbreviations should not be essential for proper
    +#   operation of software.  We have other instances of ambiguity
    +#   (e.g. "IST" denoting both "Israel Standard Time" and "Indian
    +#   Standard Time"), and they are not likely to go away any time soon.
    +#   In the old days, some software mistakenly relied on unique
    +#   abbreviations, but this is becoming less true with time, and I don't
    +#   think it's that important to cater to such software these days.
    +#
    +#   On the other hand, there is another motivation for unambiguous
    +#   abbreviations: it cuts down on human confusion.  This is
    +#   particularly true for Australia, where "EST" can mean one thing for
    +#   time T and a different thing for time T plus 1 second.
    +#
    +# * Does the relevant legislation indicate which abbreviations should be used?
    +#
    +#   Here I tend to think that things are a mess, just as they are in
    +#   many other countries.  We Americans are currently disagreeing about
    +#   which abbreviation to use for the newly legislated Chamorro Standard
    +#   Time, for example.
    +#
    +#   Personally, I would prefer to use common practice; I would like to
    +#   refer to legislation only for examples of common practice, or as a
    +#   tiebreaker.
    +#
    +# * Do Australians more often use "Eastern Daylight Time" or "Eastern
    +#   Summer Time"?  Do they typically prefix the time zone names with
    +#   the word "Australian"?
    +#
    +#   My own impression is that both "Daylight Time" and "Summer Time" are
    +#   common and are widely understood, but that "Summer Time" is more
    +#   popular; and that the leading "A" is also common but is omitted more
    +#   often than not.  I just used AltaVista advanced search and got the
    +#   following count of page hits:
    +#
    +#     1,103 "Eastern Summer Time" AND domain:au
    +#       971 "Australian Eastern Summer Time" AND domain:au
    +#       613 "Eastern Daylight Time" AND domain:au
    +#       127 "Australian Eastern Daylight Time" AND domain:au
    +#
    +#   Here "Summer" seems quite a bit more popular than "Daylight",
    +#   particularly when we know the time zone is Australian and not US,
    +#   say.  The "Australian" prefix seems to be popular for Eastern Summer
    +#   Time, but unpopular for Eastern Daylight Time.
    +#
    +#   For abbreviations, tools like AltaVista are less useful because of
    +#   ambiguity.  Many hits are not really time zones, unfortunately, and
    +#   many hits denote US time zones and not Australian ones.  But here
    +#   are the hit counts anyway:
    +#
    +#     161,304 "EST" and domain:au
    +#      25,156 "EDT" and domain:au
    +#      18,263 "AEST" and domain:au
    +#      10,416 "AEDT" and domain:au
    +#
    +#      14,538 "CST" and domain:au
    +#       5,728 "CDT" and domain:au
    +#         176 "ACST" and domain:au
    +#          29 "ACDT" and domain:au
    +#
    +#       7,539 "WST" and domain:au
    +#          68 "AWST" and domain:au
    +#
    +#   This data suggest that Australians tend to omit the "A" prefix in
    +#   practice.  The situation for "ST" versus "DT" is less clear, given
    +#   the ambiguities involved.
    +#
    +# * How do Australians feel about the abbreviations in the tz database?
    +#
    +#   If you just count Australians on this list, I count 2 in favor and 3
    +#   against.  One of the "against" votes (David Keegel) counseled delay,
    +#   saying that both AEST/AEDT and EST/EST are widely used and
    +#   understood in Australia.
    +
    +# From Paul Eggert (1995-12-19):
    +# Shanks & Pottenger report 2:00 for all autumn changes in Australia and NZ.
    +# Mark Prior writes that his newspaper
    +# reports that NSW's fall 1995 change will occur at 2:00,
    +# but Robert Elz says it's been 3:00 in Victoria since 1970
    +# and perhaps the newspaper's `2:00' is referring to standard time.
    +# For now we'll continue to assume 2:00s for changes since 1960.
    +
    +# From Eric Ulevik (1998-01-05):
    +#
    +# Here are some URLs to Australian time legislation. These URLs are stable,
    +# and should probably be included in the data file. There are probably more
    +# relevant entries in this database.
    +#
    +# NSW (including LHI and Broken Hill):
    +# 
    +# Standard Time Act 1987 (updated 1995-04-04)
    +# 
    +# ACT
    +# 
    +# Standard Time and Summer Time Act 1972
    +# 
    +# SA
    +# 
    +# Standard Time Act, 1898
    +# 
    +
    +# From David Grosz (2005-06-13):
    +# It was announced last week that Daylight Saving would be extended by
    +# one week next year to allow for the 2006 Commonwealth Games.
    +# Daylight Saving is now to end for next year only on the first Sunday
    +# in April instead of the last Sunday in March.
    +#
    +# From Gwillim Law (2005-06-14):
    +# I did some Googling and found that all of those states (and territory) plan
    +# to extend DST together in 2006.
    +# ACT: http://www.cmd.act.gov.au/mediareleases/fileread.cfm?file=86.txt
    +# New South Wales: http://www.thecouriermail.news.com.au/common/story_page/0,5936,15538869%255E1702,00.html
    +# South Australia: http://www.news.com.au/story/0,10117,15555031-1246,00.html
    +# Tasmania: http://www.media.tas.gov.au/release.php?id=14772
    +# Victoria: I wasn't able to find anything separate, but the other articles
    +# allude to it.
    +# But not Queensland
    +# http://www.news.com.au/story/0,10117,15564030-1248,00.html.
    +
    +# Northern Territory
    +
    +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
    +# # The NORTHERN TERRITORY..  [ Courtesy N.T. Dept of the Chief Minister ]
    +# #					[ Nov 1990 ]
    +# #	N.T. have never utilised any DST due to sub-tropical/tropical location.
    +# ...
    +# Zone        Australia/North         9:30    -       CST
    +
    +# From Bradley White (1991-03-04):
    +# A recent excerpt from an Australian newspaper...
    +# the Northern Territory do[es] not have daylight saving.
    +
    +# Western Australia
    +
    +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
    +# #  The state of WESTERN AUSTRALIA..  [ Courtesy W.A. dept Premier+Cabinet ]
    +# #						[ Nov 1990 ]
    +# #	W.A. suffers from a great deal of public and political opposition to
    +# #	DST in principle. A bill is brought before parliament in most years, but
    +# #	usually defeated either in the upper house, or in party caucus
    +# #	before reaching parliament.
    +# ...
    +# Zone	Australia/West		8:00	AW	%sST
    +# ...
    +# Rule	AW	1974	only	-	Oct	lastSun	2:00	1:00	D
    +# Rule	AW	1975	only	-	Mar	Sun>=1	3:00	0	W
    +# Rule	AW	1983	only	-	Oct	lastSun	2:00	1:00	D
    +# Rule	AW	1984	only	-	Mar	Sun>=1	3:00	0	W
    +
    +# From Bradley White (1991-03-04):
    +# A recent excerpt from an Australian newspaper...
    +# Western Australia...do[es] not have daylight saving.
    +
    +# From John D. Newman via Bradley White (1991-11-02):
    +# Western Australia is still on "winter time". Some DH in Sydney
    +# rang me at home a few days ago at 6.00am. (He had just arrived at
    +# work at 9.00am.)
    +# W.A. is switching to Summer Time on Nov 17th just to confuse
    +# everybody again.
    +
    +# From Arthur David Olson (1992-03-08):
    +# The 1992 ending date used in the rules is a best guess;
    +# it matches what was used in the past.
    +
    +# 
    +# The Australian Bureau of Meteorology FAQ
    +#  (1999-09-27) writes that Giles Meteorological Station uses
    +# South Australian time even though it's located in Western Australia.
    +
    +# Queensland
    +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
    +# #   The state of QUEENSLAND.. [ Courtesy Qld. Dept Premier Econ&Trade Devel ]
    +# #						[ Dec 1990 ]
    +# ...
    +# Zone	Australia/Queensland	10:00	AQ	%sST
    +# ...
    +# Rule	AQ	1971	only	-	Oct	lastSun	2:00	1:00	D
    +# Rule	AQ	1972	only	-	Feb	lastSun	3:00	0	E
    +# Rule	AQ	1989	max	-	Oct	lastSun	2:00	1:00	D
    +# Rule	AQ	1990	max	-	Mar	Sun>=1	3:00	0	E
    +
    +# From Bradley White (1989-12-24):
    +# "Australia/Queensland" now observes daylight time (i.e. from
    +# October 1989).
    +
    +# From Bradley White (1991-03-04):
    +# A recent excerpt from an Australian newspaper...
    +# ...Queensland...[has] agreed to end daylight saving
    +# at 3am tomorrow (March 3)...
    +
    +# From John Mackin (1991-03-06):
    +# I can certainly confirm for my part that Daylight Saving in NSW did in fact
    +# end on Sunday, 3 March.  I don't know at what hour, though.  (It surprised
    +# me.)
    +
    +# From Bradley White (1992-03-08):
    +# ...there was recently a referendum in Queensland which resulted
    +# in the experimental daylight saving system being abandoned. So, ...
    +# ...
    +# Rule	QLD	1989	1991	-	Oct	lastSun	2:00	1:00	D
    +# Rule	QLD	1990	1992	-	Mar	Sun>=1	3:00	0	S
    +# ...
    +
    +# From Arthur David Olson (1992-03-08):
    +# The chosen rules the union of the 1971/1972 change and the 1989-1992 changes.
    +
    +# From Christopher Hunt (2006-11-21), after an advance warning
    +# from Jesper Norgaard Welen (2006-11-01):
    +# WA are trialing DST for three years.
    +# 
    +
    +# From Rives McDow (2002-04-09):
    +# The most interesting region I have found consists of three towns on the
    +# southern coast....  South Australia observes daylight saving time; Western
    +# Australia does not.  The two states are one and a half hours apart.  The
    +# residents decided to forget about this nonsense of changing the clock so
    +# much and set the local time 20 hours and 45 minutes from the
    +# international date line, or right in the middle of the time of South
    +# Australia and Western Australia....
    +#
    +# From Paul Eggert (2002-04-09):
    +# This is confirmed by the section entitled
    +# "What's the deal with time zones???" in
    +# .
    +#
    +# From Alex Livingston (2006-12-07):
    +# ... it was just on four years ago that I drove along the Eyre Highway,
    +# which passes through eastern Western Australia close to the southern
    +# coast of the continent.
    +#
    +# I paid particular attention to the time kept there. There can be no
    +# dispute that UTC+08:45 was considered "the time" from the border
    +# village just inside the border with South Australia to as far west
    +# as just east of Caiguna. There can also be no dispute that Eucla is
    +# the largest population centre in this zone....
    +#
    +# Now that Western Australia is observing daylight saving, the
    +# question arose whether this part of the state would follow suit. I
    +# just called the border village and confirmed that indeed they have,
    +# meaning that they are now observing UTC+09:45.
    +#
    +# (2006-12-09):
    +# I personally doubt that either experimentation with daylight saving
    +# in WA or its introduction in SA had anything to do with the genesis
    +# of this time zone.  My hunch is that it's been around since well
    +# before 1975.  I remember seeing it noted on road maps decades ago.
    +
    +# From Paul Eggert (2006-12-15):
    +# For lack of better info, assume the tradition dates back to the
    +# introduction of standard time in 1895.
    +
    +
    +# southeast Australia
    +#
    +# From Paul Eggert (2007-07-23):
    +# Starting autumn 2008 Victoria, NSW, South Australia, Tasmania and the ACT
    +# end DST the first Sunday in April and start DST the first Sunday in October.
    +# http://www.theage.com.au/news/national/daylight-savings-to-span-six-months/2007/06/27/1182623966703.html
    +
    +
    +# South Australia
    +
    +# From Bradley White (1991-03-04):
    +# A recent excerpt from an Australian newspaper...
    +# ...South Australia...[has] agreed to end daylight saving
    +# at 3am tomorrow (March 3)...
    +
    +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
    +# #   The state of SOUTH AUSTRALIA....[ Courtesy of S.A. Dept of Labour ]
    +# #						[ Nov 1990 ]
    +# ...
    +# Zone	Australia/South		9:30	AS	%sST
    +# ...
    +# Rule	 AS	1971	max	-	Oct	lastSun	2:00	1:00	D
    +# Rule	 AS	1972	1985	-	Mar	Sun>=1	3:00	0	C
    +# Rule	 AS	1986	1990	-	Mar	Sun>=15	3:00	0	C
    +# Rule	 AS	1991	max	-	Mar	Sun>=1	3:00	0	C
    +
    +# From Bradley White (1992-03-11):
    +# Recent correspondence with a friend in Adelaide
    +# contained the following exchange:  "Due to the Adelaide Festival,
    +# South Australia delays setting back our clocks for a few weeks."
    +
    +# From Robert Elz (1992-03-13):
    +# I heard that apparently (or at least, it appears that)
    +# South Aus will have an extra 3 weeks daylight saving every even
    +# numbered year (from 1990).  That's when the Adelaide Festival
    +# is on...
    +
    +# From Robert Elz (1992-03-16, 00:57:07 +1000):
    +# DST didn't end in Adelaide today (yesterday)....
    +# But whether it's "4th Sunday" or "2nd last Sunday" I have no idea whatever...
    +# (it's just as likely to be "the Sunday we pick for this year"...).
    +
    +# From Bradley White (1994-04-11):
    +# If Sun, 15 March, 1992 was at +1030 as kre asserts, but yet Sun, 20 March,
    +# 1994 was at +0930 as John Connolly's customer seems to assert, then I can
    +# only conclude that the actual rule is more complicated....
    +
    +# From John Warburton (1994-10-07):
    +# The new Daylight Savings dates for South Australia ...
    +# was gazetted in the Government Hansard on Sep 26 1994....
    +# start on last Sunday in October and end in last sunday in March.
    +
    +# From Paul Eggert (2007-07-23):
    +# See "southeast Australia" above for 2008 and later.
    +
    +# Tasmania
    +
    +# The rules for 1967 through 1991 were reported by George Shepherd
    +# via Simon Woodhead via Robert Elz (1991-03-06):
    +# #  The state of TASMANIA.. [Courtesy Tasmanian Dept of Premier + Cabinet ]
    +# #					[ Nov 1990 ]
    +
    +# From Bill Hart via Guy Harris (1991-10-10):
    +# Oh yes, the new daylight savings rules are uniquely tasmanian, we have
    +# 6 weeks a year now when we are out of sync with the rest of Australia
    +# (but nothing new about that).
    +
    +# From Alex Livingston (1999-10-04):
    +# I heard on the ABC (Australian Broadcasting Corporation) radio news on the
    +# (long) weekend that Tasmania, which usually goes its own way in this regard,
    +# has decided to join with most of NSW, the ACT, and most of Victoria
    +# (Australia) and start daylight saving on the last Sunday in August in 2000
    +# instead of the first Sunday in October.
    +
    +# Sim Alam (2000-07-03) reported a legal citation for the 2000/2001 rules:
    +# http://www.thelaw.tas.gov.au/fragview/42++1968+GS3A@EN+2000070300
    +
    +# From Paul Eggert (2007-07-23):
    +# See "southeast Australia" above for 2008 and later.
    +
    +# Victoria
    +
    +# The rules for 1971 through 1991 were reported by George Shepherd
    +# via Simon Woodhead via Robert Elz (1991-03-06):
    +# #   The state of VICTORIA.. [ Courtesy of Vic. Dept of Premier + Cabinet ]
    +# #						[ Nov 1990 ]
    +
    +# From Scott Harrington (2001-08-29):
    +# On KQED's "City Arts and Lectures" program last night I heard an
    +# interesting story about daylight savings time.  Dr. John Heilbron was
    +# discussing his book "The Sun in the Church: Cathedrals as Solar
    +# Observatories"[1], and in particular the Shrine of Remembrance[2] located
    +# in Melbourne, Australia.
    +#
    +# Apparently the shrine's main purpose is a beam of sunlight which
    +# illuminates a special spot on the floor at the 11th hour of the 11th day
    +# of the 11th month (Remembrance Day) every year in memory of Australia's
    +# fallen WWI soldiers.  And if you go there on Nov. 11, at 11am local time,
    +# you will indeed see the sunbeam illuminate the special spot at the
    +# expected time.
    +#
    +# However, that is only because of some special mirror contraption that had
    +# to be employed, since due to daylight savings time, the true solar time of
    +# the remembrance moment occurs one hour later (or earlier?).  Perhaps
    +# someone with more information on this jury-rig can tell us more.
    +#
    +# [1] http://www.hup.harvard.edu/catalog/HEISUN.html
    +# [2] http://www.shrine.org.au
    +
    +# From Paul Eggert (2007-07-23):
    +# See "southeast Australia" above for 2008 and later.
    +
    +# New South Wales
    +
    +# From Arthur David Olson:
    +# New South Wales and subjurisdictions have their own ideas of a fun time.
    +# Based on law library research by John Mackin,
    +# who notes:
    +#	In Australia, time is not legislated federally, but rather by the
    +#	individual states.  Thus, while such terms as ``Eastern Standard Time''
    +#	[I mean, of course, Australian EST, not any other kind] are in common
    +#	use, _they have NO REAL MEANING_, as they are not defined in the
    +#	legislation.  This is very important to understand.
    +#	I have researched New South Wales time only...
    +
    +# From Eric Ulevik (1999-05-26):
    +# DST will start in NSW on the last Sunday of August, rather than the usual
    +# October in 2000.  [See: Matthew Moore,
    +# 
    +# Two months more daylight saving
    +# 
    +# Sydney Morning Herald (1999-05-26).]
    +
    +# From Paul Eggert (1999-09-27):
    +# See the following official NSW source:
    +# 
    +# Daylight Saving in New South Wales.
    +# 
    +#
    +# Narrabri Shire (NSW) council has announced it will ignore the extension of
    +# daylight saving next year.  See:
    +# 
    +# Narrabri Council to ignore daylight saving
    +#  (1999-07-22).  For now, we'll wait to see if this really happens.
    +#
    +# Victoria will following NSW.  See:
    +# 
    +# Vic to extend daylight saving
    +#  (1999-07-28).
    +#
    +# However, South Australia rejected the DST request.  See:
    +# 
    +# South Australia rejects Olympics daylight savings request
    +#  (1999-07-19).
    +#
    +# Queensland also will not observe DST for the Olympics.  See:
    +# 
    +# Qld says no to daylight savings for Olympics
    +#  (1999-06-01), which quotes Queensland Premier Peter Beattie as saying
    +# ``Look you've got to remember in my family when this came up last time
    +# I voted for it, my wife voted against it and she said to me it's all very
    +# well for you, you don't have to worry about getting the children out of
    +# bed, getting them to school, getting them to sleep at night.
    +# I've been through all this argument domestically...my wife rules.''
    +#
    +# Broken Hill will stick with South Australian time in 2000.  See:
    +# 
    +# Broken Hill to be behind the times
    +#  (1999-07-21).
    +
    +# IATA SSIM (1998-09) says that the spring 2000 change for Australian
    +# Capital Territory, New South Wales except Lord Howe Island and Broken
    +# Hill, and Victoria will be August 27, presumably due to the Sydney Olympics.
    +
    +# From Eric Ulevik, referring to Sydney's Sun Herald (2000-08-13), page 29:
    +# The Queensland Premier Peter Beattie is encouraging northern NSW
    +# towns to use Queensland time.
    +
    +# From Paul Eggert (2007-07-23):
    +# See "southeast Australia" above for 2008 and later.
    +
    +# Yancowinna
    +
    +# From John Mackin (1989-01-04):
    +# `Broken Hill' means the County of Yancowinna.
    +
    +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
    +# # YANCOWINNA..  [ Confirmation courtesy of Broken Hill Postmaster ]
    +# #					[ Dec 1990 ]
    +# ...
    +# # Yancowinna uses Central Standard Time, despite [its] location on the
    +# # New South Wales side of the S.A. border. Most business and social dealings
    +# # are with CST zones, therefore CST is legislated by local government
    +# # although the switch to Summer Time occurs in line with N.S.W. There have
    +# # been years when this did not apply, but the historical data is not
    +# # presently available.
    +# Zone	Australia/Yancowinna	9:30	 AY	%sST
    +# ...
    +# Rule	 AY	1971	1985	-	Oct	lastSun	2:00	1:00	D
    +# Rule	 AY	1972	only	-	Feb	lastSun	3:00	0	C
    +# [followed by other Rules]
    +
    +# Lord Howe Island
    +
    +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
    +# LHI...		[ Courtesy of Pauline Van Winsen ]
    +#					[ Dec 1990 ]
    +# Lord Howe Island is located off the New South Wales coast, and is half an
    +# hour ahead of NSW time.
    +
    +# From James Lonergan, Secretary, Lord Howe Island Board (2000-01-27):
    +# Lord Howe Island summer time in 2000/2001 will commence on the same
    +# date as the rest of NSW (i.e. 2000-08-27).  For your information the
    +# Lord Howe Island Board (controlling authority for the Island) is
    +# seeking the community's views on various options for summer time
    +# arrangements on the Island, e.g. advance clocks by 1 full hour
    +# instead of only 30 minutes.  [Dependent] on the wishes of residents
    +# the Board may approach the NSW government to change the existing
    +# arrangements.  The starting date for summer time on the Island will
    +# however always coincide with the rest of NSW.
    +
    +# From James Lonergan, Secretary, Lord Howe Island Board (2000-10-25):
    +# Lord Howe Island advances clocks by 30 minutes during DST in NSW and retards
    +# clocks by 30 minutes when DST finishes. Since DST was most recently
    +# introduced in NSW, the "changeover" time on the Island has been 02:00 as
    +# shown on clocks on LHI. I guess this means that for 30 minutes at the start
    +# of DST, LHI is actually 1 hour ahead of the rest of NSW.
    +
    +# From Paul Eggert (2006-03-22):
    +# For Lord Howe dates we use Shanks & Pottenger through 1989, and
    +# Lonergan thereafter.  For times we use Lonergan.
    +
    +# From Paul Eggert (2007-07-23):
    +# See "southeast Australia" above for 2008 and later.
    +
    +# From Steffen Thorsen (2009-04-28):
    +# According to the official press release, South Australia's extended daylight
    +# saving period will continue with the same rules as used during the 2008-2009
    +# summer (southern hemisphere).
    +#
    +# From
    +# 
    +# http://www.safework.sa.gov.au/uploaded_files/DaylightDatesSet.pdf
    +# 
    +# The extended daylight saving period that South Australia has been trialling
    +# for over the last year is now set to be ongoing.
    +# Daylight saving will continue to start on the first Sunday in October each
    +# year and finish on the first Sunday in April the following year.
    +# Industrial Relations Minister, Paul Caica, says this provides South Australia
    +# with a consistent half hour time difference with NSW, Victoria, Tasmania and
    +# the ACT for all 52 weeks of the year...
    +#
    +# We have a wrap-up here:
    +# 
    +# http://www.timeanddate.com/news/time/south-australia-extends-dst.html
    +# 
    +###############################################################################
    +
    +# New Zealand
    +
    +# From Mark Davies (1990-10-03):
    +# the 1989/90 year was a trial of an extended "daylight saving" period.
    +# This trial was deemed successful and the extended period adopted for
    +# subsequent years (with the addition of a further week at the start).
    +# source -- phone call to Ministry of Internal Affairs Head Office.
    +
    +# From George Shepherd via Simon Woodhead via Robert Elz (1991-03-06):
    +# # The Country of New Zealand   (Australia's east island -) Gee they hate that!
    +# #				   or is Australia the west island of N.Z.
    +# #	[ courtesy of Geoff Tribble.. Auckland N.Z. ]
    +# #				[ Nov 1990 ]
    +# ...
    +# Rule	NZ      1974    1988	-	Oct	lastSun	2:00	1:00	D
    +# Rule	NZ	1989	max	-	Oct	Sun>=1	2:00	1:00	D
    +# Rule	NZ      1975    1989	-	Mar	Sun>=1	3:00	0	S
    +# Rule	NZ	1990	max	-	Mar	lastSun	3:00	0	S
    +# ...
    +# Zone	NZ			12:00	NZ		NZ%sT	# New Zealand
    +# Zone	NZ-CHAT			12:45	-		NZ-CHAT # Chatham Island
    +
    +# From Arthur David Olson (1992-03-08):
    +# The chosen rules use the Davies October 8 values for the start of DST in 1989
    +# rather than the October 1 value.
    +
    +# From Paul Eggert (1995-12-19);
    +# Shank & Pottenger report 2:00 for all autumn changes in Australia and NZ.
    +# Robert Uzgalis writes that the New Zealand Daylight
    +# Savings Time Order in Council dated 1990-06-18 specifies 2:00 standard
    +# time on both the first Sunday in October and the third Sunday in March.
    +# As with Australia, we'll assume the tradition is 2:00s, not 2:00.
    +#
    +# From Paul Eggert (2006-03-22):
    +# The Department of Internal Affairs (DIA) maintains a brief history,
    +# as does Carol Squires; see tz-link.htm for the full references.
    +# Use these sources in preference to Shanks & Pottenger.
    +#
    +# For Chatham, IATA SSIM (1991/1999) gives the NZ rules but with
    +# transitions at 2:45 local standard time; this confirms that Chatham
    +# is always exactly 45 minutes ahead of Auckland.
    +
    +# From Colin Sharples (2007-04-30):
    +# DST will now start on the last Sunday in September, and end on the
    +# first Sunday in April.  The changes take effect this year, meaning
    +# that DST will begin on 2007-09-30 2008-04-06.
    +# http://www.dia.govt.nz/diawebsite.nsf/wpg_URL/Services-Daylight-Saving-Daylight-saving-to-be-extended
    +
    +###############################################################################
    +
    +
    +# Fiji
    +
    +# Howse writes (p 153) that in 1879 the British governor of Fiji
    +# enacted an ordinance standardizing the islands on Antipodean Time
    +# instead of the American system (which was one day behind).
    +
    +# From Rives McDow (1998-10-08):
    +# Fiji will introduce DST effective 0200 local time, 1998-11-01
    +# until 0300 local time 1999-02-28.  Each year the DST period will
    +# be from the first Sunday in November until the last Sunday in February.
    +
    +# From Paul Eggert (2000-01-08):
    +# IATA SSIM (1999-09) says DST ends 0100 local time.  Go with McDow.
    +
    +# From the BBC World Service (1998-10-31 11:32 UTC):
    +# The Fijiian government says the main reasons for the time change is to
    +# improve productivity and reduce road accidents.  But correspondents say it
    +# also hopes the move will boost Fiji's ability to compete with other pacific
    +# islands in the effort to attract tourists to witness the dawning of the new
    +# millenium.
    +
    +# http://www.fiji.gov.fj/press/2000_09/2000_09_13-05.shtml (2000-09-13)
    +# reports that Fiji has discontinued DST.
    +
    +# Johnston
    +
    +# Johnston data is from usno1995.
    +
    +
    +# Kiribati
    +
    +# From Paul Eggert (1996-01-22):
    +# Today's _Wall Street Journal_ (page 1) reports that Kiribati
    +# ``declared it the same day [throughout] the country as of Jan. 1, 1995''
    +# as part of the competition to be first into the 21st century.
    +
    +
    +# Kwajalein
    +
    +# In comp.risks 14.87 (26 August 1993), Peter Neumann writes:
    +# I wonder what happened in Kwajalein, where there was NO Friday,
    +# 1993-08-20.  Thursday night at midnight Kwajalein switched sides with
    +# respect to the International Date Line, to rejoin its fellow islands,
    +# going from 11:59 p.m. Thursday to 12:00 m. Saturday in a blink.
    +
    +
    +# N Mariana Is, Guam
    +
    +# Howse writes (p 153) ``The Spaniards, on the other hand, reached the
    +# Philippines and the Ladrones from America,'' and implies that the Ladrones
    +# (now called the Marianas) kept American date for quite some time.
    +# For now, we assume the Ladrones switched at the same time as the Philippines;
    +# see Asia/Manila.
    +
    +# US Public Law 106-564 (2000-12-23) made UTC+10 the official standard time,
    +# under the name "Chamorro Standard Time".  There is no official abbreviation,
    +# but Congressman Robert A. Underwood, author of the bill that became law,
    +# wrote in a press release (2000-12-27) that he will seek the use of "ChST".
    +
    +
    +# Micronesia
    +
    +# Alan Eugene Davis writes (1996-03-16),
    +# ``I am certain, having lived there for the past decade, that "Truk"
    +# (now properly known as Chuuk) ... is in the time zone GMT+10.''
    +#
    +# Shanks & Pottenger write that Truk switched from UTC+10 to UTC+11
    +# on 1978-10-01; ignore this for now.
    +
    +# From Paul Eggert (1999-10-29):
    +# The Federated States of Micronesia Visitors Board writes in
    +# 
    +# The Federated States of Micronesia - Visitor Information
    +#  (1999-01-26)
    +# that Truk and Yap are UTC+10, and Ponape and Kosrae are UTC+11.
    +# We don't know when Kosrae switched from UTC+12; assume January 1 for now.
    +
    +
    +# Midway
    +
    +# From Charles T O'Connor, KMTH DJ (1956),
    +# quoted in the KTMH section of the Radio Heritage Collection
    +#  (2002-12-31):
    +# For the past two months we've been on what is known as Daylight
    +# Saving Time.  This time has put us on air at 5am in the morning,
    +# your time down there in New Zealand.  Starting September 2, 1956
    +# we'll again go back to Standard Time.  This'll mean that we'll go to
    +# air at 6am your time.
    +#
    +# From Paul Eggert (2003-03-23):
    +# We don't know the date of that quote, but we'll guess they
    +# started DST on June 3.  Possibly DST was observed other years
    +# in Midway, but we have no record of it.
    +
    +
    +# Pitcairn
    +
    +# From Rives McDow (1999-11-08):
    +# A Proclamation was signed by the Governor of Pitcairn on the 27th March 1998
    +# with regard to Pitcairn Standard Time.  The Proclamation is as follows.
    +#
    +#	The local time for general purposes in the Islands shall be
    +#	Co-ordinated Universal time minus 8 hours and shall be known
    +#	as Pitcairn Standard Time.
    +#
    +# ... I have also seen Pitcairn listed as UTC minus 9 hours in several
    +# references, and can only assume that this was an error in interpretation
    +# somehow in light of this proclamation.
    +
    +# From Rives McDow (1999-11-09):
    +# The Proclamation regarding Pitcairn time came into effect on 27 April 1998
    +# ... at midnight.
    +
    +# From Howie Phelps (1999-11-10), who talked to a Pitcairner via shortwave:
    +# Betty Christian told me yesterday that their local time is the same as
    +# Pacific Standard Time. They used to be 1/2 hour different from us here in
    +# Sacramento but it was changed a couple of years ago.
    +
    +
    +# Samoa
    +
    +# Howse writes (p 153, citing p 10 of the 1883-11-18 New York Herald)
    +# that in 1879 the King of Samoa decided to change
    +# ``the date in his kingdom from the Antipodean to the American system,
    +# ordaining -- by a masterpiece of diplomatic flattery -- that
    +# the Fourth of July should be celebrated twice in that year.''
    +
    +
    +# Tonga
    +
    +# From Paul Eggert (1996-01-22):
    +# Today's _Wall Street Journal_ (p 1) reports that ``Tonga has been plotting
    +# to sneak ahead of [New Zealanders] by introducing daylight-saving time.''
    +# Since Kiribati has moved the Date Line it's not clear what Tonga will do.
    +
    +# Don Mundell writes in the 1997-02-20 Tonga Chronicle
    +# 
    +# How Tonga became `The Land where Time Begins'
    +# :
    +
    +# Until 1941 Tonga maintained a standard time 50 minutes ahead of NZST
    +# 12 hours and 20 minutes ahead of GMT.  When New Zealand adjusted its
    +# standard time in 1940s, Tonga had the choice of subtracting from its
    +# local time to come on the same standard time as New Zealand or of
    +# advancing its time to maintain the differential of 13 degrees
    +# (approximately 50 minutes ahead of New Zealand time).
    +#
    +# Because His Majesty King Taufa'ahau Tupou IV, then Crown Prince
    +# Tungi, preferred to ensure Tonga's title as the land where time
    +# begins, the Legislative Assembly approved the latter change.
    +#
    +# But some of the older, more conservative members from the outer
    +# islands objected. "If at midnight on Dec. 31, we move ahead 40
    +# minutes, as your Royal Highness wishes, what becomes of the 40
    +# minutes we have lost?"
    +#
    +# The Crown Prince, presented an unanswerable argument: "Remember that
    +# on the World Day of Prayer, you would be the first people on Earth
    +# to say your prayers in the morning."
    +
    +# From Paul Eggert (2006-03-22):
    +# Shanks & Pottenger say the transition was on 1968-10-01; go with Mundell.
    +
    +# From Eric Ulevik (1999-05-03):
    +# Tonga's director of tourism, who is also secretary of the National Millenium
    +# Committee, has a plan to get Tonga back in front.
    +# He has proposed a one-off move to tropical daylight saving for Tonga from
    +# October to March, which has won approval in principle from the Tongan
    +# Government.
    +
    +# From Steffen Thorsen (1999-09-09):
    +# * Tonga will introduce DST in November
    +#
    +# I was given this link by John Letts:
    +# 
    +# http://news.bbc.co.uk/hi/english/world/asia-pacific/newsid_424000/424764.stm
    +# 
    +#
    +# I have not been able to find exact dates for the transition in November
    +# yet. By reading this article it seems like Fiji will be 14 hours ahead
    +# of UTC as well, but as far as I know Fiji will only be 13 hours ahead
    +# (12 + 1 hour DST).
    +
    +# From Arthur David Olson (1999-09-20):
    +# According to 
    +# http://www.tongaonline.com/news/sept1799.html
    +# :
    +# "Daylight Savings Time will take effect on Oct. 2 through April 15, 2000
    +# and annually thereafter from the first Saturday in October through the
    +# third Saturday of April.  Under the system approved by Privy Council on
    +# Sept. 10, clocks must be turned ahead one hour on the opening day and
    +# set back an hour on the closing date."
    +# Alas, no indication of the time of day.
    +
    +# From Rives McDow (1999-10-06):
    +# Tonga started its Daylight Saving on Saturday morning October 2nd at 0200am.
    +# Daylight Saving ends on April 16 at 0300am which is Sunday morning.
    +
    +# From Steffen Thorsen (2000-10-31):
    +# Back in March I found a notice on the website http://www.tongaonline.com
    +# that Tonga changed back to standard time one month early, on March 19
    +# instead of the original reported date April 16. Unfortunately, the article
    +# is no longer available on the site, and I did not make a copy of the
    +# text, and I have forgotten to report it here.
    +# (Original URL was: http://www.tongaonline.com/news/march162000.htm )
    +
    +# From Rives McDow (2000-12-01):
    +# Tonga is observing DST as of 2000-11-04 and will stop on 2001-01-27.
    +
    +# From Sione Moala-Mafi (2001-09-20) via Rives McDow:
    +# At 2:00am on the first Sunday of November, the standard time in the Kingdom
    +# shall be moved forward by one hour to 3:00am.  At 2:00am on the last Sunday
    +# of January the standard time in the Kingdom shall be moved backward by one
    +# hour to 1:00am.
    +
    +# From Pulu 'Anau (2002-11-05):
    +# The law was for 3 years, supposedly to get renewed.  It wasn't.
    +
    +
    +# Wake
    +
    +# From Vernice Anderson, Personal Secretary to Philip Jessup,
    +# US Ambassador At Large (oral history interview, 1971-02-02):
    +#
    +# Saturday, the 14th [of October, 1950] -- ...  The time was all the
    +# more confusing at that point, because we had crossed the
    +# International Date Line, thus getting two Sundays.  Furthermore, we
    +# discovered that Wake Island had two hours of daylight saving time
    +# making calculation of time in Washington difficult if not almost
    +# impossible.
    +#
    +# http://www.trumanlibrary.org/wake/meeting.htm
    +
    +# From Paul Eggert (2003-03-23):
    +# We have no other report of DST in Wake Island, so omit this info for now.
    +
    +###############################################################################
    +
    +# The International Date Line
    +
    +# From Gwillim Law (2000-01-03):
    +#
    +# The International Date Line is not defined by any international standard,
    +# convention, or treaty.  Mapmakers are free to draw it as they please.
    +# Reputable mapmakers will simply ensure that every point of land appears on
    +# the correct side of the IDL, according to the date legally observed there.
    +#
    +# When Kiribati adopted a uniform date in 1995, thereby moving the Phoenix and
    +# Line Islands to the west side of the IDL (or, if you prefer, moving the IDL
    +# to the east side of the Phoenix and Line Islands), I suppose that most
    +# mapmakers redrew the IDL following the boundary of Kiribati.  Even that line
    +# has a rather arbitrary nature.  The straight-line boundaries between Pacific
    +# island nations that are shown on many maps are based on an international
    +# convention, but are not legally binding national borders.... The date is
    +# governed by the IDL; therefore, even on the high seas, there may be some
    +# places as late as fourteen hours later than UTC.  And, since the IDL is not
    +# an international standard, there are some places on the high seas where the
    +# correct date is ambiguous.
    +
    +# From Wikipedia  (2005-08-31):
    +# Before 1920, all ships kept local apparent time on the high seas by setting
    +# their clocks at night or at the morning sight so that, given the ship's
    +# speed and direction, it would be 12 o'clock when the Sun crossed the ship's
    +# meridian (12 o'clock = local apparent noon).  During 1917, at the
    +# Anglo-French Conference on Time-keeping at Sea, it was recommended that all
    +# ships, both military and civilian, should adopt hourly standard time zones
    +# on the high seas.  Whenever a ship was within the territorial waters of any
    +# nation it would use that nation's standard time.  The captain was permitted
    +# to change his ship's clocks at a time of his choice following his ship's
    +# entry into another zone time--he often chose midnight.  These zones were
    +# adopted by all major fleets between 1920 and 1925 but not by many
    +# independent merchant ships until World War II.
    +
    +# From Paul Eggert, using references suggested by Oscar van Vlijmen
    +# (2005-03-20):
    +#
    +# The American Practical Navigator (2002)
    +# 
    +# talks only about the 180-degree meridian with respect to ships in
    +# international waters; it ignores the international date line.
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/backward b/jdk/test/sun/util/calendar/zi/tzdata/backward
    new file mode 100644
    index 00000000000..4ccea7c7dbe
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/backward
    @@ -0,0 +1,140 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# This file provides links between current names for time zones
    +# and their old names.  Many names changed in late 1993.
    +
    +Link	Africa/Asmara		Africa/Asmera
    +Link	Africa/Bamako		Africa/Timbuktu
    +Link	America/Argentina/Catamarca	America/Argentina/ComodRivadavia
    +Link	America/Adak		America/Atka
    +Link	America/Argentina/Buenos_Aires	America/Buenos_Aires
    +Link	America/Argentina/Catamarca	America/Catamarca
    +Link	America/Atikokan	America/Coral_Harbour
    +Link	America/Argentina/Cordoba	America/Cordoba
    +Link	America/Tijuana		America/Ensenada
    +Link	America/Indiana/Indianapolis	America/Fort_Wayne
    +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/Rio_Branco	America/Porto_Acre
    +Link	America/Argentina/Cordoba	America/Rosario
    +Link	America/St_Thomas	America/Virgin
    +Link	Asia/Ashgabat		Asia/Ashkhabad
    +Link	Asia/Chongqing		Asia/Chungking
    +Link	Asia/Dhaka		Asia/Dacca
    +Link	Asia/Kathmandu		Asia/Katmandu
    +Link	Asia/Kolkata		Asia/Calcutta
    +Link	Asia/Macau		Asia/Macao
    +Link	Asia/Jerusalem		Asia/Tel_Aviv
    +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/Oslo		Atlantic/Jan_Mayen
    +Link	Australia/Sydney	Australia/ACT
    +Link	Australia/Sydney	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
    +Link	America/Noronha		Brazil/DeNoronha
    +Link	America/Sao_Paulo	Brazil/East
    +Link	America/Manaus		Brazil/West
    +Link	America/Halifax		Canada/Atlantic
    +Link	America/Winnipeg	Canada/Central
    +Link	America/Regina		Canada/East-Saskatchewan
    +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	Africa/Cairo		Egypt
    +Link	Europe/Dublin		Eire
    +Link	Europe/London		Europe/Belfast
    +Link	Europe/Chisinau		Europe/Tiraspol
    +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	Atlantic/Reykjavik	Iceland
    +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	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
    +Link	Asia/Shanghai		PRC
    +Link	Pacific/Pago_Pago	Pacific/Samoa
    +Link	Pacific/Chuuk		Pacific/Yap
    +Link	Pacific/Chuuk		Pacific/Truk
    +Link	Pacific/Pohnpei		Pacific/Ponape
    +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/UCT			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
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/etcetera b/jdk/test/sun/util/calendar/zi/tzdata/etcetera
    new file mode 100644
    index 00000000000..609b305493c
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/etcetera
    @@ -0,0 +1,104 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# These entries are mostly present for historical reasons, so that
    +# people in areas not otherwise covered by the tz files could "zic -l"
    +# to a time zone that was right for their area.  These days, the
    +# tz files cover almost all the inhabited world, and the only practical
    +# need now for the entries that are not on UTC are for ships at sea
    +# that cannot use POSIX TZ settings.
    +
    +Zone	Etc/GMT		0	-	GMT
    +Zone	Etc/UTC		0	-	UTC
    +Zone	Etc/UCT		0	-	UCT
    +
    +# The following link uses older naming conventions,
    +# but it belongs here, not in the file `backward',
    +# as functions like gmtime load the "GMT" file to handle leap seconds properly.
    +# We want this to work even on installations that omit the other older names.
    +Link	Etc/GMT				GMT
    +
    +Link	Etc/UTC				Etc/Universal
    +Link	Etc/UTC				Etc/Zulu
    +
    +Link	Etc/GMT				Etc/Greenwich
    +Link	Etc/GMT				Etc/GMT-0
    +Link	Etc/GMT				Etc/GMT+0
    +Link	Etc/GMT				Etc/GMT0
    +
    +# We use POSIX-style signs in the Zone names and the output abbreviations,
    +# even though this is the opposite of what many people expect.
    +# POSIX has positive signs west of Greenwich, but many people expect
    +# positive signs east of Greenwich.  For example, TZ='Etc/GMT+4' uses
    +# the abbreviation "GMT+4" and corresponds to 4 hours behind UTC
    +# (i.e. west of Greenwich) even though many people would expect it to
    +# mean 4 hours ahead of UTC (i.e. east of Greenwich).
    +#
    +# In the draft 5 of POSIX 1003.1-200x, the angle bracket notation allows for
    +# TZ='+4'; if you want time zone abbreviations conforming to
    +# ISO 8601 you can use TZ='<-0400>+4'.  Thus the commonly-expected
    +# offset is kept within the angle bracket (and is used for display)
    +# while the POSIX sign is kept outside the angle bracket (and is used
    +# for calculation).
    +#
    +# Do not use a TZ setting like TZ='GMT+4', which is four hours behind
    +# GMT but uses the completely misleading abbreviation "GMT".
    +
    +# Earlier incarnations of this package were not POSIX-compliant,
    +# and had lines such as
    +#		Zone	GMT-12		-12	-	GMT-1200
    +# We did not want things to change quietly if someone accustomed to the old
    +# way does a
    +#		zic -l GMT-12
    +# so we moved the names into the Etc subdirectory.
    +
    +Zone	Etc/GMT-14	14	-	GMT-14	# 14 hours ahead of GMT
    +Zone	Etc/GMT-13	13	-	GMT-13
    +Zone	Etc/GMT-12	12	-	GMT-12
    +Zone	Etc/GMT-11	11	-	GMT-11
    +Zone	Etc/GMT-10	10	-	GMT-10
    +Zone	Etc/GMT-9	9	-	GMT-9
    +Zone	Etc/GMT-8	8	-	GMT-8
    +Zone	Etc/GMT-7	7	-	GMT-7
    +Zone	Etc/GMT-6	6	-	GMT-6
    +Zone	Etc/GMT-5	5	-	GMT-5
    +Zone	Etc/GMT-4	4	-	GMT-4
    +Zone	Etc/GMT-3	3	-	GMT-3
    +Zone	Etc/GMT-2	2	-	GMT-2
    +Zone	Etc/GMT-1	1	-	GMT-1
    +Zone	Etc/GMT+1	-1	-	GMT+1
    +Zone	Etc/GMT+2	-2	-	GMT+2
    +Zone	Etc/GMT+3	-3	-	GMT+3
    +Zone	Etc/GMT+4	-4	-	GMT+4
    +Zone	Etc/GMT+5	-5	-	GMT+5
    +Zone	Etc/GMT+6	-6	-	GMT+6
    +Zone	Etc/GMT+7	-7	-	GMT+7
    +Zone	Etc/GMT+8	-8	-	GMT+8
    +Zone	Etc/GMT+9	-9	-	GMT+9
    +Zone	Etc/GMT+10	-10	-	GMT+10
    +Zone	Etc/GMT+11	-11	-	GMT+11
    +Zone	Etc/GMT+12	-12	-	GMT+12
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/europe b/jdk/test/sun/util/calendar/zi/tzdata/europe
    new file mode 100644
    index 00000000000..9a0d0b9db94
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/europe
    @@ -0,0 +1,2879 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# This data is by no means authoritative; if you think you know better,
    +# go ahead and edit the file (and please send any changes to
    +# tz@elsie.nci.nih.gov for general use in the future).
    +
    +# From Paul Eggert (2006-03-22):
    +# A good source for time zone historical data outside the U.S. is
    +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
    +# San Diego: ACS Publications, Inc. (2003).
    +#
    +# Gwillim Law writes that a good source
    +# for recent time zone data is the International Air Transport
    +# Association's Standard Schedules Information Manual (IATA SSIM),
    +# published semiannually.  Law sent in several helpful summaries
    +# of the IATA's data after 1990.
    +#
    +# Except where otherwise noted, Shanks & Pottenger is the source for
    +# entries through 1991, and IATA SSIM is the source for entries afterwards.
    +#
    +# Other sources occasionally used include:
    +#
    +#	Edward W. Whitman, World Time Differences,
    +#	Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated),
    +#	which I found in the UCLA library.
    +#
    +#	
    +#	William Willett, The Waste of Daylight, 19th edition
    +#	 (1914-03)
    +#
    +#	Brazil's Departamento Servico da Hora (DSH),
    +#	
    +#	History of Summer Time
    +#	 (1998-09-21, in Portuguese)
    +
    +#
    +# I invented the abbreviations marked `*' in the following table;
    +# the rest are from earlier versions of this file, or from other sources.
    +# Corrections are welcome!
    +#                   std dst  2dst
    +#                   LMT           Local Mean Time
    +#       -4:00       AST ADT       Atlantic
    +#       -3:00       WGT WGST      Western Greenland*
    +#       -1:00       EGT EGST      Eastern Greenland*
    +#        0:00       GMT BST  BDST Greenwich, British Summer
    +#        0:00       GMT IST       Greenwich, Irish Summer
    +#        0:00       WET WEST WEMT Western Europe
    +#        0:19:32.13 AMT NST       Amsterdam, Netherlands Summer (1835-1937)*
    +#        0:20       NET NEST      Netherlands (1937-1940)*
    +#        1:00       CET CEST CEMT Central Europe
    +#        1:00:14    SET           Swedish (1879-1899)*
    +#        2:00       EET EEST      Eastern Europe
    +#        3:00       MSK MSD       Moscow
    +#
    +# A reliable and entertaining source about time zones, especially in Britain,
    +# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
    +
    +# From Peter Ilieve (1994-12-04),
    +# The original six [EU members]: Belgium, France, (West) Germany, Italy,
    +# Luxembourg, the Netherlands.
    +# Plus, from 1 Jan 73: Denmark, Ireland, United Kingdom.
    +# Plus, from 1 Jan 81: Greece.
    +# Plus, from 1 Jan 86: Spain, Portugal.
    +# Plus, from 1 Jan 95: Austria, Finland, Sweden. (Norway negotiated terms for
    +# entry but in a referendum on 28 Nov 94 the people voted No by 52.2% to 47.8%
    +# on a turnout of 88.6%. This was almost the same result as Norway's previous
    +# referendum in 1972, they are the only country to have said No twice.
    +# Referendums in the other three countries voted Yes.)
    +# ...
    +# Estonia ... uses EU dates but not at 01:00 GMT, they use midnight GMT.
    +# I don't think they know yet what they will do from 1996 onwards.
    +# ...
    +# There shouldn't be any [current members who are not using EU rules].
    +# A Directive has the force of law, member states are obliged to enact
    +# national law to implement it. The only contentious issue was the
    +# different end date for the UK and Ireland, and this was always allowed
    +# in the Directive.
    +
    +
    +###############################################################################
    +
    +# Britain (United Kingdom) and Ireland (Eire)
    +
    +# From Peter Ilieve (1994-07-06):
    +#
    +# On 17 Jan 1994 the Independent, a UK quality newspaper, had a piece about
    +# historical vistas along the Thames in west London. There was a photo
    +# and a sketch map showing some of the sightlines involved. One paragraph
    +# of the text said:
    +#
    +# `An old stone obelisk marking a forgotten terrestrial meridian stands
    +# beside the river at Kew. In the 18th century, before time and longitude
    +# was standardised by the Royal Observatory in Greenwich, scholars observed
    +# this stone and the movement of stars from Kew Observatory nearby. They
    +# made their calculations and set the time for the Horse Guards and Parliament,
    +# but now the stone is obscured by scrubwood and can only be seen by walking
    +# along the towpath within a few yards of it.'
    +#
    +# I have a one inch to one mile map of London and my estimate of the stone's
    +# position is 51 deg. 28' 30" N, 0 deg. 18' 45" W. The longitude should
    +# be within about +-2". The Ordnance Survey grid reference is TQ172761.
    +#
    +# [This yields GMTOFF = -0:01:15 for London LMT in the 18th century.]
    +
    +# From Paul Eggert (1993-11-18):
    +#
    +# Howse writes that Britain was the first country to use standard time.
    +# The railways cared most about the inconsistencies of local mean time,
    +# and it was they who forced a uniform time on the country.
    +# The original idea was credited to Dr. William Hyde Wollaston (1766-1828)
    +# and was popularized by Abraham Follett Osler (1808-1903).
    +# The first railway to adopt London time was the Great Western Railway
    +# in November 1840; other railways followed suit, and by 1847 most
    +# (though not all) railways used London time.  On 1847-09-22 the
    +# Railway Clearing House, an industry standards body, recommended that GMT be
    +# adopted at all stations as soon as the General Post Office permitted it.
    +# The transition occurred on 12-01 for the L&NW, the Caledonian,
    +# and presumably other railways; the January 1848 Bradshaw's lists many
    +# railways as using GMT.  By 1855 the vast majority of public
    +# clocks in Britain were set to GMT (though some, like the great clock
    +# on Tom Tower at Christ Church, Oxford, were fitted with two minute hands,
    +# one for local time and one for GMT).  The last major holdout was the legal
    +# system, which stubbornly stuck to local time for many years, leading
    +# to oddities like polls opening at 08:13 and closing at 16:13.
    +# The legal system finally switched to GMT when the Statutes (Definition
    +# of Time) Act took effect; it received the Royal Assent on 1880-08-02.
    +#
    +# In the tables below, we condense this complicated story into a single
    +# transition date for London, namely 1847-12-01.  We don't know as much
    +# about Dublin, so we use 1880-08-02, the legal transition time.
    +
    +# From Paul Eggert (2003-09-27):
    +# Summer Time was first seriously proposed by William Willett (1857-1915),
    +# a London builder and member of the Royal Astronomical Society
    +# who circulated a pamphlet ``The Waste of Daylight'' (1907)
    +# that proposed advancing clocks 20 minutes on each of four Sundays in April,
    +# and retarding them by the same amount on four Sundays in September.
    +# A bill was drafted in 1909 and introduced in Parliament several times,
    +# but it met with ridicule and opposition, especially from farming interests.
    +# Later editions of the pamphlet proposed one-hour summer time, and
    +# it was eventually adopted as a wartime measure in 1916.
    +# See: Summer Time Arrives Early, The Times (2000-05-18).
    +# A monument to Willett was unveiled on 1927-05-21, in an open space in
    +# a 45-acre wood near Chislehurst, Kent that was purchased by popular
    +# subscription and open to the public.  On the south face of the monolith,
    +# designed by G. W. Miller, is the...William Willett Memorial Sundial,
    +# which is permanently set to Summer Time.
    +
    +# From Winston Churchill (1934-04-28):
    +# It is one of the paradoxes of history that we should owe the boon of
    +# summer time, which gives every year to the people of this country
    +# between 160 and 170 hours more daylight leisure, to a war which
    +# plunged Europe into darkness for four years, and shook the
    +# foundations of civilization throughout the world.
    +#	-- 
    +#	"A Silent Toast to William Willett", Pictorial Weekly
    +#	
    +
    +# From Paul Eggert (1996-09-03):
    +# The OED Supplement says that the English originally said ``Daylight Saving''
    +# when they were debating the adoption of DST in 1908; but by 1916 this
    +# term appears only in quotes taken from DST's opponents, whereas the
    +# proponents (who eventually won the argument) are quoted as using ``Summer''.
    +
    +# From Arthur David Olson (1989-01-19):
    +#
    +# A source at the British Information Office in New York avers that it's
    +# known as "British" Summer Time in all parts of the United Kingdom.
    +
    +# Date: 4 Jan 89 08:57:25 GMT (Wed)
    +# From: Jonathan Leffler
    +# [British Summer Time] is fixed annually by Act of Parliament.
    +# If you can predict what Parliament will do, you should be in
    +# politics making a fortune, not computing.
    +
    +# From Chris Carrier (1996-06-14):
    +# I remember reading in various wartime issues of the London Times the
    +# acronym BDST for British Double Summer Time.  Look for the published
    +# time of sunrise and sunset in The Times, when BDST was in effect, and
    +# if you find a zone reference it will say, "All times B.D.S.T."
    +
    +# From Joseph S. Myers (1999-09-02):
    +# ... some military cables (WO 219/4100 - this is a copy from the
    +# main SHAEF archives held in the US National Archives, SHAEF/5252/8/516)
    +# agree that the usage is BDST (this appears in a message dated 17 Feb 1945).
    +
    +# From Joseph S. Myers (2000-10-03):
    +# On 18th April 1941, Sir Stephen Tallents of the BBC wrote to Sir
    +# Alexander Maxwell of the Home Office asking whether there was any
    +# official designation; the reply of the 21st was that there wasn't
    +# but he couldn't think of anything better than the "Double British
    +# Summer Time" that the BBC had been using informally.
    +# http://student.cusu.cam.ac.uk/~jsm28/british-time/bbc-19410418.png
    +# http://student.cusu.cam.ac.uk/~jsm28/british-time/ho-19410421.png
    +
    +# From Sir Alexander Maxwell in the above-mentioned letter (1941-04-21):
    +# [N]o official designation has as far as I know been adopted for the time
    +# which is to be introduced in May....
    +# I cannot think of anything better than "Double British Summer Time"
    +# which could not be said to run counter to any official description.
    +
    +# From Paul Eggert (2000-10-02):
    +# Howse writes (p 157) `DBST' too, but `BDST' seems to have been common
    +# and follows the more usual convention of putting the location name first,
    +# so we use `BDST'.
    +
    +# Peter Ilieve (1998-04-19) described at length
    +# the history of summer time legislation in the United Kingdom.
    +# Since 1998 Joseph S. Myers has been updating
    +# and extending this list, which can be found in
    +# http://student.cusu.cam.ac.uk/~jsm28/british-time/
    +# 
    +# History of legal time in Britain
    +# 
    +# Rob Crowther (2012-01-04) reports that that URL no longer
    +# exists, and the article can now be found at:
    +# 
    +# http://www.polyomino.org.uk/british-time/
    +# 
    +
    +# From Joseph S. Myers (1998-01-06):
    +#
    +# The legal time in the UK outside of summer time is definitely GMT, not UTC;
    +# see Lord Tanlaw's speech
    +# 
    +# (Lords Hansard 11 June 1997 columns 964 to 976)
    +# .
    +
    +# From Paul Eggert (2006-03-22):
    +#
    +# For lack of other data, follow Shanks & Pottenger for Eire in 1940-1948.
    +#
    +# Given Ilieve and Myers's data, the following claims by Shanks & Pottenger
    +# are incorrect:
    +#     * Wales did not switch from GMT to daylight saving time until
    +#	1921 Apr 3, when they began to conform with the rest of Great Britain.
    +# Actually, Wales was identical after 1880.
    +#     * Eire had two transitions on 1916 Oct 1.
    +# It actually just had one transition.
    +#     * Northern Ireland used single daylight saving time throughout WW II.
    +# Actually, it conformed to Britain.
    +#     * GB-Eire changed standard time to 1 hour ahead of GMT on 1968-02-18.
    +# Actually, that date saw the usual switch to summer time.
    +# Standard time was not changed until 1968-10-27 (the clocks didn't change).
    +#
    +# Here is another incorrect claim by Shanks & Pottenger:
    +#     * Jersey, Guernsey, and the Isle of Man did not switch from GMT
    +#	to daylight saving time until 1921 Apr 3, when they began to
    +#	conform with Great Britain.
    +# S.R.&O. 1916, No. 382 and HO 45/10811/312364 (quoted above) say otherwise.
    +#
    +# The following claim by Shanks & Pottenger is possible though doubtful;
    +# we'll ignore it for now.
    +#     * Dublin's 1971-10-31 switch was at 02:00, even though London's was 03:00.
    +#
    +#
    +# Whitman says Dublin Mean Time was -0:25:21, which is more precise than
    +# Shanks & Pottenger.
    +# Perhaps this was Dunsink Observatory Time, as Dunsink Observatory
    +# (8 km NW of Dublin's center) seemingly was to Dublin as Greenwich was
    +# to London.  For example:
    +#
    +#   "Timeball on the ballast office is down.  Dunsink time."
    +#   -- James Joyce, Ulysses
    +
    +# From Joseph S. Myers (2005-01-26):
    +# Irish laws are available online at www.irishstatutebook.ie.  These include
    +# various relating to legal time, for example:
    +#
    +# ZZA13Y1923.html ZZA12Y1924.html ZZA8Y1925.html ZZSIV20PG1267.html
    +#
    +# ZZSI71Y1947.html ZZSI128Y1948.html ZZSI23Y1949.html ZZSI41Y1950.html
    +# ZZSI27Y1951.html ZZSI73Y1952.html
    +#
    +# ZZSI11Y1961.html ZZSI232Y1961.html ZZSI182Y1962.html
    +# ZZSI167Y1963.html ZZSI257Y1964.html ZZSI198Y1967.html
    +# ZZA23Y1968.html ZZA17Y1971.html
    +#
    +# ZZSI67Y1981.html ZZSI212Y1982.html ZZSI45Y1986.html
    +# ZZSI264Y1988.html ZZSI52Y1990.html ZZSI371Y1992.html
    +# ZZSI395Y1994.html ZZSI484Y1997.html ZZSI506Y2001.html
    +#
    +# [These are all relative to the root, e.g., the first is
    +# .]
    +#
    +# (These are those I found, but there could be more.  In any case these
    +# should allow various updates to the comments in the europe file to cover
    +# the laws applicable in Ireland.)
    +#
    +# (Note that the time in the Republic of Ireland since 1968 has been defined
    +# in terms of standard time being GMT+1 with a period of winter time when it
    +# is GMT, rather than standard time being GMT with a period of summer time
    +# being GMT+1.)
    +
    +# From Paul Eggert (1999-03-28):
    +# Clive Feather (, 1997-03-31)
    +# reports that Folkestone (Cheriton) Shuttle Terminal uses Concession Time
    +# (CT), equivalent to French civil time.
    +# Julian Hill (, 1998-09-30) reports that
    +# trains between Dollands Moor (the freight facility next door)
    +# and Frethun run in CT.
    +# My admittedly uninformed guess is that the terminal has two authorities,
    +# the French concession operators and the British civil authorities,
    +# and that the time depends on who you're talking to.
    +# If, say, the British police were called to the station for some reason,
    +# I would expect the official police report to use GMT/BST and not CET/CEST.
    +# This is a borderline case, but for now let's stick to GMT/BST.
    +
    +# From an anonymous contributor (1996-06-02):
    +# The law governing time in Ireland is under Statutory Instrument SI 395/94,
    +# which gives force to European Union 7th Council Directive # 94/21/EC.
    +# Under this directive, the Minister for Justice in Ireland makes appropriate
    +# regulations. I spoke this morning with the Secretary of the Department of
    +# Justice (tel +353 1 678 9711) who confirmed to me that the correct name is
    +# "Irish Summer Time", abbreviated to "IST".
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +# Summer Time Act, 1916
    +Rule	GB-Eire	1916	only	-	May	21	2:00s	1:00	BST
    +Rule	GB-Eire	1916	only	-	Oct	 1	2:00s	0	GMT
    +# S.R.&O. 1917, No. 358
    +Rule	GB-Eire	1917	only	-	Apr	 8	2:00s	1:00	BST
    +Rule	GB-Eire	1917	only	-	Sep	17	2:00s	0	GMT
    +# S.R.&O. 1918, No. 274
    +Rule	GB-Eire	1918	only	-	Mar	24	2:00s	1:00	BST
    +Rule	GB-Eire	1918	only	-	Sep	30	2:00s	0	GMT
    +# S.R.&O. 1919, No. 297
    +Rule	GB-Eire	1919	only	-	Mar	30	2:00s	1:00	BST
    +Rule	GB-Eire	1919	only	-	Sep	29	2:00s	0	GMT
    +# S.R.&O. 1920, No. 458
    +Rule	GB-Eire	1920	only	-	Mar	28	2:00s	1:00	BST
    +# S.R.&O. 1920, No. 1844
    +Rule	GB-Eire	1920	only	-	Oct	25	2:00s	0	GMT
    +# S.R.&O. 1921, No. 363
    +Rule	GB-Eire	1921	only	-	Apr	 3	2:00s	1:00	BST
    +Rule	GB-Eire	1921	only	-	Oct	 3	2:00s	0	GMT
    +# S.R.&O. 1922, No. 264
    +Rule	GB-Eire	1922	only	-	Mar	26	2:00s	1:00	BST
    +Rule	GB-Eire	1922	only	-	Oct	 8	2:00s	0	GMT
    +# The Summer Time Act, 1922
    +Rule	GB-Eire	1923	only	-	Apr	Sun>=16	2:00s	1:00	BST
    +Rule	GB-Eire	1923	1924	-	Sep	Sun>=16	2:00s	0	GMT
    +Rule	GB-Eire	1924	only	-	Apr	Sun>=9	2:00s	1:00	BST
    +Rule	GB-Eire	1925	1926	-	Apr	Sun>=16	2:00s	1:00	BST
    +# The Summer Time Act, 1925
    +Rule	GB-Eire	1925	1938	-	Oct	Sun>=2	2:00s	0	GMT
    +Rule	GB-Eire	1927	only	-	Apr	Sun>=9	2:00s	1:00	BST
    +Rule	GB-Eire	1928	1929	-	Apr	Sun>=16	2:00s	1:00	BST
    +Rule	GB-Eire	1930	only	-	Apr	Sun>=9	2:00s	1:00	BST
    +Rule	GB-Eire	1931	1932	-	Apr	Sun>=16	2:00s	1:00	BST
    +Rule	GB-Eire	1933	only	-	Apr	Sun>=9	2:00s	1:00	BST
    +Rule	GB-Eire	1934	only	-	Apr	Sun>=16	2:00s	1:00	BST
    +Rule	GB-Eire	1935	only	-	Apr	Sun>=9	2:00s	1:00	BST
    +Rule	GB-Eire	1936	1937	-	Apr	Sun>=16	2:00s	1:00	BST
    +Rule	GB-Eire	1938	only	-	Apr	Sun>=9	2:00s	1:00	BST
    +Rule	GB-Eire	1939	only	-	Apr	Sun>=16	2:00s	1:00	BST
    +# S.R.&O. 1939, No. 1379
    +Rule	GB-Eire	1939	only	-	Nov	Sun>=16	2:00s	0	GMT
    +# S.R.&O. 1940, No. 172 and No. 1883
    +Rule	GB-Eire	1940	only	-	Feb	Sun>=23	2:00s	1:00	BST
    +# S.R.&O. 1941, No. 476
    +Rule	GB-Eire	1941	only	-	May	Sun>=2	1:00s	2:00	BDST
    +Rule	GB-Eire	1941	1943	-	Aug	Sun>=9	1:00s	1:00	BST
    +# S.R.&O. 1942, No. 506
    +Rule	GB-Eire	1942	1944	-	Apr	Sun>=2	1:00s	2:00	BDST
    +# S.R.&O. 1944, No. 932
    +Rule	GB-Eire	1944	only	-	Sep	Sun>=16	1:00s	1:00	BST
    +# S.R.&O. 1945, No. 312
    +Rule	GB-Eire	1945	only	-	Apr	Mon>=2	1:00s	2:00	BDST
    +Rule	GB-Eire	1945	only	-	Jul	Sun>=9	1:00s	1:00	BST
    +# S.R.&O. 1945, No. 1208
    +Rule	GB-Eire	1945	1946	-	Oct	Sun>=2	2:00s	0	GMT
    +Rule	GB-Eire	1946	only	-	Apr	Sun>=9	2:00s	1:00	BST
    +# The Summer Time Act, 1947
    +Rule	GB-Eire	1947	only	-	Mar	16	2:00s	1:00	BST
    +Rule	GB-Eire	1947	only	-	Apr	13	1:00s	2:00	BDST
    +Rule	GB-Eire	1947	only	-	Aug	10	1:00s	1:00	BST
    +Rule	GB-Eire	1947	only	-	Nov	 2	2:00s	0	GMT
    +# Summer Time Order, 1948 (S.I. 1948/495)
    +Rule	GB-Eire	1948	only	-	Mar	14	2:00s	1:00	BST
    +Rule	GB-Eire	1948	only	-	Oct	31	2:00s	0	GMT
    +# Summer Time Order, 1949 (S.I. 1949/373)
    +Rule	GB-Eire	1949	only	-	Apr	 3	2:00s	1:00	BST
    +Rule	GB-Eire	1949	only	-	Oct	30	2:00s	0	GMT
    +# Summer Time Order, 1950 (S.I. 1950/518)
    +# Summer Time Order, 1951 (S.I. 1951/430)
    +# Summer Time Order, 1952 (S.I. 1952/451)
    +Rule	GB-Eire	1950	1952	-	Apr	Sun>=14	2:00s	1:00	BST
    +Rule	GB-Eire	1950	1952	-	Oct	Sun>=21	2:00s	0	GMT
    +# revert to the rules of the Summer Time Act, 1925
    +Rule	GB-Eire	1953	only	-	Apr	Sun>=16	2:00s	1:00	BST
    +Rule	GB-Eire	1953	1960	-	Oct	Sun>=2	2:00s	0	GMT
    +Rule	GB-Eire	1954	only	-	Apr	Sun>=9	2:00s	1:00	BST
    +Rule	GB-Eire	1955	1956	-	Apr	Sun>=16	2:00s	1:00	BST
    +Rule	GB-Eire	1957	only	-	Apr	Sun>=9	2:00s	1:00	BST
    +Rule	GB-Eire	1958	1959	-	Apr	Sun>=16	2:00s	1:00	BST
    +Rule	GB-Eire	1960	only	-	Apr	Sun>=9	2:00s	1:00	BST
    +# Summer Time Order, 1961 (S.I. 1961/71)
    +# Summer Time (1962) Order, 1961 (S.I. 1961/2465)
    +# Summer Time Order, 1963 (S.I. 1963/81)
    +Rule	GB-Eire	1961	1963	-	Mar	lastSun	2:00s	1:00	BST
    +Rule	GB-Eire	1961	1968	-	Oct	Sun>=23	2:00s	0	GMT
    +# Summer Time (1964) Order, 1963 (S.I. 1963/2101)
    +# Summer Time Order, 1964 (S.I. 1964/1201)
    +# Summer Time Order, 1967 (S.I. 1967/1148)
    +Rule	GB-Eire	1964	1967	-	Mar	Sun>=19	2:00s	1:00	BST
    +# Summer Time Order, 1968 (S.I. 1968/117)
    +Rule	GB-Eire	1968	only	-	Feb	18	2:00s	1:00	BST
    +# The British Standard Time Act, 1968
    +#	(no summer time)
    +# The Summer Time Act, 1972
    +Rule	GB-Eire	1972	1980	-	Mar	Sun>=16	2:00s	1:00	BST
    +Rule	GB-Eire	1972	1980	-	Oct	Sun>=23	2:00s	0	GMT
    +# Summer Time Order, 1980 (S.I. 1980/1089)
    +# Summer Time Order, 1982 (S.I. 1982/1673)
    +# Summer Time Order, 1986 (S.I. 1986/223)
    +# Summer Time Order, 1988 (S.I. 1988/931)
    +Rule	GB-Eire	1981	1995	-	Mar	lastSun	1:00u	1:00	BST
    +Rule	GB-Eire 1981	1989	-	Oct	Sun>=23	1:00u	0	GMT
    +# Summer Time Order, 1989 (S.I. 1989/985)
    +# Summer Time Order, 1992 (S.I. 1992/1729)
    +# Summer Time Order 1994 (S.I. 1994/2798)
    +Rule	GB-Eire 1990	1995	-	Oct	Sun>=22	1:00u	0	GMT
    +# Summer Time Order 1997 (S.I. 1997/2982)
    +# See EU for rules starting in 1996.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/London	-0:01:15 -	LMT	1847 Dec  1 0:00s
    +			 0:00	GB-Eire	%s	1968 Oct 27
    +			 1:00	-	BST	1971 Oct 31 2:00u
    +			 0:00	GB-Eire	%s	1996
    +			 0:00	EU	GMT/BST
    +Link	Europe/London	Europe/Jersey
    +Link	Europe/London	Europe/Guernsey
    +Link	Europe/London	Europe/Isle_of_Man
    +Zone	Europe/Dublin	-0:25:00 -	LMT	1880 Aug  2
    +			-0:25:21 -	DMT	1916 May 21 2:00
    +			-0:25:21 1:00	IST	1916 Oct  1 2:00s
    +			 0:00	GB-Eire	%s	1921 Dec  6 # independence
    +			 0:00	GB-Eire	GMT/IST	1940 Feb 25 2:00
    +			 0:00	1:00	IST	1946 Oct  6 2:00
    +			 0:00	-	GMT	1947 Mar 16 2:00
    +			 0:00	1:00	IST	1947 Nov  2 2:00
    +			 0:00	-	GMT	1948 Apr 18 2:00
    +			 0:00	GB-Eire	GMT/IST	1968 Oct 27
    +			 1:00	-	IST	1971 Oct 31 2:00u
    +			 0:00	GB-Eire	GMT/IST	1996
    +			 0:00	EU	GMT/IST
    +
    +###############################################################################
    +
    +# Europe
    +
    +# EU rules are for the European Union, previously known as the EC, EEC,
    +# Common Market, etc.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	EU	1977	1980	-	Apr	Sun>=1	 1:00u	1:00	S
    +Rule	EU	1977	only	-	Sep	lastSun	 1:00u	0	-
    +Rule	EU	1978	only	-	Oct	 1	 1:00u	0	-
    +Rule	EU	1979	1995	-	Sep	lastSun	 1:00u	0	-
    +Rule	EU	1981	max	-	Mar	lastSun	 1:00u	1:00	S
    +Rule	EU	1996	max	-	Oct	lastSun	 1:00u	0	-
    +# The most recent directive covers the years starting in 2002.  See:
    +# 
    +# Directive 2000/84/EC of the European Parliament and of the Council
    +# of 19 January 2001 on summer-time arrangements.
    +# 
    +
    +# W-Eur differs from EU only in that W-Eur uses standard time.
    +Rule	W-Eur	1977	1980	-	Apr	Sun>=1	 1:00s	1:00	S
    +Rule	W-Eur	1977	only	-	Sep	lastSun	 1:00s	0	-
    +Rule	W-Eur	1978	only	-	Oct	 1	 1:00s	0	-
    +Rule	W-Eur	1979	1995	-	Sep	lastSun	 1:00s	0	-
    +Rule	W-Eur	1981	max	-	Mar	lastSun	 1:00s	1:00	S
    +Rule	W-Eur	1996	max	-	Oct	lastSun	 1:00s	0	-
    +
    +# Older C-Eur rules are for convenience in the tables.
    +# From 1977 on, C-Eur differs from EU only in that C-Eur uses standard time.
    +Rule	C-Eur	1916	only	-	Apr	30	23:00	1:00	S
    +Rule	C-Eur	1916	only	-	Oct	 1	 1:00	0	-
    +Rule	C-Eur	1917	1918	-	Apr	Mon>=15	 2:00s	1:00	S
    +Rule	C-Eur	1917	1918	-	Sep	Mon>=15	 2:00s	0	-
    +Rule	C-Eur	1940	only	-	Apr	 1	 2:00s	1:00	S
    +Rule	C-Eur	1942	only	-	Nov	 2	 2:00s	0	-
    +Rule	C-Eur	1943	only	-	Mar	29	 2:00s	1:00	S
    +Rule	C-Eur	1943	only	-	Oct	 4	 2:00s	0	-
    +Rule	C-Eur	1944	1945	-	Apr	Mon>=1	 2:00s	1:00	S
    +# Whitman gives 1944 Oct 7; go with Shanks & Pottenger.
    +Rule	C-Eur	1944	only	-	Oct	 2	 2:00s	0	-
    +# From Jesper Norgaard Welen (2008-07-13):
    +#
    +# I found what is probably a typo of 2:00 which should perhaps be 2:00s
    +# in the C-Eur rule from tz database version 2008d (this part was
    +# corrected in version 2008d). The circumstancial evidence is simply the
    +# tz database itself, as seen below:
    +#
    +# Zone Europe/Paris 0:09:21 - LMT 1891 Mar 15  0:01
    +#    0:00 France WE%sT 1945 Sep 16  3:00
    +#
    +# Zone Europe/Monaco 0:29:32 - LMT 1891 Mar 15
    +#    0:00 France WE%sT 1945 Sep 16 3:00
    +#
    +# Zone Europe/Belgrade 1:22:00 - LMT 1884
    +#    1:00 1:00 CEST 1945 Sep 16  2:00s
    +#
    +# Rule France 1945 only - Sep 16  3:00 0 -
    +# Rule Belgium 1945 only - Sep 16  2:00s 0 -
    +# Rule Neth 1945 only - Sep 16 2:00s 0 -
    +#
    +# The rule line to be changed is:
    +#
    +# Rule C-Eur 1945 only - Sep 16  2:00 0 -
    +#
    +# It seems that Paris, Monaco, Rule France, Rule Belgium all agree on
    +# 2:00 standard time, e.g. 3:00 local time.  However there are no
    +# countries that use C-Eur rules in September 1945, so the only items
    +# affected are apparently these ficticious zones that translates acronyms
    +# CET and MET:
    +#
    +# Zone CET  1:00 C-Eur CE%sT
    +# Zone MET  1:00 C-Eur ME%sT
    +#
    +# It this is right then the corrected version would look like:
    +#
    +# Rule C-Eur 1945 only - Sep 16  2:00s 0 -
    +#
    +# A small step for mankind though 8-)
    +Rule	C-Eur	1945	only	-	Sep	16	 2:00s	0	-
    +Rule	C-Eur	1977	1980	-	Apr	Sun>=1	 2:00s	1:00	S
    +Rule	C-Eur	1977	only	-	Sep	lastSun	 2:00s	0	-
    +Rule	C-Eur	1978	only	-	Oct	 1	 2:00s	0	-
    +Rule	C-Eur	1979	1995	-	Sep	lastSun	 2:00s	0	-
    +Rule	C-Eur	1981	max	-	Mar	lastSun	 2:00s	1:00	S
    +Rule	C-Eur	1996	max	-	Oct	lastSun	 2:00s	0	-
    +
    +# E-Eur differs from EU only in that E-Eur switches at midnight local time.
    +Rule	E-Eur	1977	1980	-	Apr	Sun>=1	 0:00	1:00	S
    +Rule	E-Eur	1977	only	-	Sep	lastSun	 0:00	0	-
    +Rule	E-Eur	1978	only	-	Oct	 1	 0:00	0	-
    +Rule	E-Eur	1979	1995	-	Sep	lastSun	 0:00	0	-
    +Rule	E-Eur	1981	max	-	Mar	lastSun	 0:00	1:00	S
    +Rule	E-Eur	1996	max	-	Oct	lastSun	 0:00	0	-
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Russia	1917	only	-	Jul	 1	23:00	1:00	MST	# Moscow Summer Time
    +Rule	Russia	1917	only	-	Dec	28	 0:00	0	MMT	# Moscow Mean Time
    +Rule	Russia	1918	only	-	May	31	22:00	2:00	MDST	# Moscow Double Summer Time
    +Rule	Russia	1918	only	-	Sep	16	 1:00	1:00	MST
    +Rule	Russia	1919	only	-	May	31	23:00	2:00	MDST
    +Rule	Russia	1919	only	-	Jul	 1	 2:00	1:00	S
    +Rule	Russia	1919	only	-	Aug	16	 0:00	0	-
    +Rule	Russia	1921	only	-	Feb	14	23:00	1:00	S
    +Rule	Russia	1921	only	-	Mar	20	23:00	2:00	M # Midsummer
    +Rule	Russia	1921	only	-	Sep	 1	 0:00	1:00	S
    +Rule	Russia	1921	only	-	Oct	 1	 0:00	0	-
    +# Act No.925 of the Council of Ministers of the USSR (1980-10-24):
    +Rule	Russia	1981	1984	-	Apr	 1	 0:00	1:00	S
    +Rule	Russia	1981	1983	-	Oct	 1	 0:00	0	-
    +# Act No.967 of the Council of Ministers of the USSR (1984-09-13), repeated in
    +# Act No.227 of the Council of Ministers of the USSR (1989-03-14):
    +Rule	Russia	1984	1991	-	Sep	lastSun	 2:00s	0	-
    +Rule	Russia	1985	1991	-	Mar	lastSun	 2:00s	1:00	S
    +#
    +Rule	Russia	1992	only	-	Mar	lastSat	 23:00	1:00	S
    +Rule	Russia	1992	only	-	Sep	lastSat	 23:00	0	-
    +Rule	Russia	1993	2010	-	Mar	lastSun	 2:00s	1:00	S
    +Rule	Russia	1993	1995	-	Sep	lastSun	 2:00s	0	-
    +Rule	Russia	1996	2010	-	Oct	lastSun	 2:00s	0	-
    +
    +# From Alexander Krivenyshev (2011-06-14):
    +# According to Kremlin press service, Russian President Dmitry Medvedev
    +# signed a federal law "On calculation of time" on June 9, 2011.
    +# According to the law Russia is abolishing daylight saving time.
    +#
    +# Medvedev signed a law "On the Calculation of Time" (in russian):
    +# 
    +# http://bmockbe.ru/events/?ID=7583
    +# 
    +#
    +# Medvedev signed a law on the calculation of the time (in russian):
    +# 
    +# http://www.regnum.ru/news/polit/1413906.html
    +# 
    +
    +# From Arthur David Olson (2011-06-15):
    +# Take "abolishing daylight saving time" to mean that time is now considered
    +# to be standard.
    +
    +# These are for backward compatibility with older versions.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	WET		0:00	EU	WE%sT
    +Zone	CET		1:00	C-Eur	CE%sT
    +Zone	MET		1:00	C-Eur	ME%sT
    +Zone	EET		2:00	EU	EE%sT
    +
    +# Previous editions of this database used abbreviations like MET DST
    +# for Central European Summer Time, but this didn't agree with common usage.
    +
    +# From Markus Kuhn (1996-07-12):
    +# The official German names ... are
    +#
    +#	Mitteleuropaeische Zeit (MEZ)         = UTC+01:00
    +#	Mitteleuropaeische Sommerzeit (MESZ)  = UTC+02:00
    +#
    +# as defined in the German Time Act (Gesetz ueber die Zeitbestimmung (ZeitG),
    +# 1978-07-25, Bundesgesetzblatt, Jahrgang 1978, Teil I, S. 1110-1111)....
    +# I wrote ... to the German Federal Physical-Technical Institution
    +#
    +#	Physikalisch-Technische Bundesanstalt (PTB)
    +#	Laboratorium 4.41 "Zeiteinheit"
    +#	Postfach 3345
    +#	D-38023 Braunschweig
    +#	phone: +49 531 592-0
    +#
    +# ... I received today an answer letter from Dr. Peter Hetzel, head of the PTB
    +# department for time and frequency transmission.  He explained that the
    +# PTB translates MEZ and MESZ into English as
    +#
    +#	Central European Time (CET)         = UTC+01:00
    +#	Central European Summer Time (CEST) = UTC+02:00
    +
    +
    +# Albania
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Albania	1940	only	-	Jun	16	0:00	1:00	S
    +Rule	Albania	1942	only	-	Nov	 2	3:00	0	-
    +Rule	Albania	1943	only	-	Mar	29	2:00	1:00	S
    +Rule	Albania	1943	only	-	Apr	10	3:00	0	-
    +Rule	Albania	1974	only	-	May	 4	0:00	1:00	S
    +Rule	Albania	1974	only	-	Oct	 2	0:00	0	-
    +Rule	Albania	1975	only	-	May	 1	0:00	1:00	S
    +Rule	Albania	1975	only	-	Oct	 2	0:00	0	-
    +Rule	Albania	1976	only	-	May	 2	0:00	1:00	S
    +Rule	Albania	1976	only	-	Oct	 3	0:00	0	-
    +Rule	Albania	1977	only	-	May	 8	0:00	1:00	S
    +Rule	Albania	1977	only	-	Oct	 2	0:00	0	-
    +Rule	Albania	1978	only	-	May	 6	0:00	1:00	S
    +Rule	Albania	1978	only	-	Oct	 1	0:00	0	-
    +Rule	Albania	1979	only	-	May	 5	0:00	1:00	S
    +Rule	Albania	1979	only	-	Sep	30	0:00	0	-
    +Rule	Albania	1980	only	-	May	 3	0:00	1:00	S
    +Rule	Albania	1980	only	-	Oct	 4	0:00	0	-
    +Rule	Albania	1981	only	-	Apr	26	0:00	1:00	S
    +Rule	Albania	1981	only	-	Sep	27	0:00	0	-
    +Rule	Albania	1982	only	-	May	 2	0:00	1:00	S
    +Rule	Albania	1982	only	-	Oct	 3	0:00	0	-
    +Rule	Albania	1983	only	-	Apr	18	0:00	1:00	S
    +Rule	Albania	1983	only	-	Oct	 1	0:00	0	-
    +Rule	Albania	1984	only	-	Apr	 1	0:00	1:00	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Tirane	1:19:20 -	LMT	1914
    +			1:00	-	CET	1940 Jun 16
    +			1:00	Albania	CE%sT	1984 Jul
    +			1:00	EU	CE%sT
    +
    +# Andorra
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Andorra	0:06:04 -	LMT	1901
    +			0:00	-	WET	1946 Sep 30
    +			1:00	-	CET	1985 Mar 31 2:00
    +			1:00	EU	CE%sT
    +
    +# Austria
    +
    +# From Paul Eggert (2006-03-22): Shanks & Pottenger give 1918-06-16 and
    +# 1945-11-18, but the Austrian Federal Office of Metrology and
    +# Surveying (BEV) gives 1918-09-16 and for Vienna gives the "alleged"
    +# date of 1945-04-12 with no time.  For the 1980-04-06 transition
    +# Shanks & Pottenger give 02:00, the BEV 00:00.  Go with the BEV,
    +# and guess 02:00 for 1945-04-12.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Austria	1920	only	-	Apr	 5	2:00s	1:00	S
    +Rule	Austria	1920	only	-	Sep	13	2:00s	0	-
    +Rule	Austria	1946	only	-	Apr	14	2:00s	1:00	S
    +Rule	Austria	1946	1948	-	Oct	Sun>=1	2:00s	0	-
    +Rule	Austria	1947	only	-	Apr	 6	2:00s	1:00	S
    +Rule	Austria	1948	only	-	Apr	18	2:00s	1:00	S
    +Rule	Austria	1980	only	-	Apr	 6	0:00	1:00	S
    +Rule	Austria	1980	only	-	Sep	28	0:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Vienna	1:05:20 -	LMT	1893 Apr
    +			1:00	C-Eur	CE%sT	1920
    +			1:00	Austria	CE%sT	1940 Apr  1 2:00s
    +			1:00	C-Eur	CE%sT	1945 Apr  2 2:00s
    +			1:00	1:00	CEST	1945 Apr 12 2:00s
    +			1:00	-	CET	1946
    +			1:00	Austria	CE%sT	1981
    +			1:00	EU	CE%sT
    +
    +# Belarus
    +# From Yauhen Kharuzhy (2011-09-16):
    +# By latest Belarus government act Europe/Minsk timezone was changed to
    +# GMT+3 without DST (was GMT+2 with DST).
    +#
    +# Sources (Russian language):
    +# 1.
    +# 
    +# http://www.belta.by/ru/all_news/society/V-Belarusi-otmenjaetsja-perexod-na-sezonnoe-vremja_i_572952.html
    +# 
    +# 2.
    +# 
    +# http://naviny.by/rubrics/society/2011/09/16/ic_articles_116_175144/
    +# 
    +# 3.
    +# 
    +# http://news.tut.by/society/250578.html
    +# 
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Minsk	1:50:16 -	LMT	1880
    +			1:50	-	MMT	1924 May 2 # Minsk Mean Time
    +			2:00	-	EET	1930 Jun 21
    +			3:00	-	MSK	1941 Jun 28
    +			1:00	C-Eur	CE%sT	1944 Jul  3
    +			3:00	Russia	MSK/MSD	1990
    +			3:00	-	MSK	1991 Mar 31 2:00s
    +			2:00	1:00	EEST	1991 Sep 29 2:00s
    +			2:00	-	EET	1992 Mar 29 0:00s
    +			2:00	1:00	EEST	1992 Sep 27 0:00s
    +			2:00	Russia	EE%sT	2011 Mar 27 2:00s
    +			3:00	-	FET # Further-eastern European Time
    +
    +# Belgium
    +#
    +# From Paul Eggert (1997-07-02):
    +# Entries from 1918 through 1991 are taken from:
    +#	Annuaire de L'Observatoire Royal de Belgique,
    +#	Avenue Circulaire, 3, B-1180 BRUXELLES, CLVIIe annee, 1991
    +#	(Imprimerie HAYEZ, s.p.r.l., Rue Fin, 4, 1080 BRUXELLES, MCMXC),
    +#	pp 8-9.
    +# LMT before 1892 was 0:17:30, according to the official journal of Belgium:
    +#	Moniteur Belge, Samedi 30 Avril 1892, N.121.
    +# Thanks to Pascal Delmoitie for these references.
    +# The 1918 rules are listed for completeness; they apply to unoccupied Belgium.
    +# Assume Brussels switched to WET in 1918 when the armistice took effect.
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Belgium	1918	only	-	Mar	 9	 0:00s	1:00	S
    +Rule	Belgium	1918	1919	-	Oct	Sat>=1	23:00s	0	-
    +Rule	Belgium	1919	only	-	Mar	 1	23:00s	1:00	S
    +Rule	Belgium	1920	only	-	Feb	14	23:00s	1:00	S
    +Rule	Belgium	1920	only	-	Oct	23	23:00s	0	-
    +Rule	Belgium	1921	only	-	Mar	14	23:00s	1:00	S
    +Rule	Belgium	1921	only	-	Oct	25	23:00s	0	-
    +Rule	Belgium	1922	only	-	Mar	25	23:00s	1:00	S
    +Rule	Belgium	1922	1927	-	Oct	Sat>=1	23:00s	0	-
    +Rule	Belgium	1923	only	-	Apr	21	23:00s	1:00	S
    +Rule	Belgium	1924	only	-	Mar	29	23:00s	1:00	S
    +Rule	Belgium	1925	only	-	Apr	 4	23:00s	1:00	S
    +# DSH writes that a royal decree of 1926-02-22 specified the Sun following 3rd
    +# Sat in Apr (except if it's Easter, in which case it's one Sunday earlier),
    +# to Sun following 1st Sat in Oct, and that a royal decree of 1928-09-15
    +# changed the transition times to 02:00 GMT.
    +Rule	Belgium	1926	only	-	Apr	17	23:00s	1:00	S
    +Rule	Belgium	1927	only	-	Apr	 9	23:00s	1:00	S
    +Rule	Belgium	1928	only	-	Apr	14	23:00s	1:00	S
    +Rule	Belgium	1928	1938	-	Oct	Sun>=2	 2:00s	0	-
    +Rule	Belgium	1929	only	-	Apr	21	 2:00s	1:00	S
    +Rule	Belgium	1930	only	-	Apr	13	 2:00s	1:00	S
    +Rule	Belgium	1931	only	-	Apr	19	 2:00s	1:00	S
    +Rule	Belgium	1932	only	-	Apr	 3	 2:00s	1:00	S
    +Rule	Belgium	1933	only	-	Mar	26	 2:00s	1:00	S
    +Rule	Belgium	1934	only	-	Apr	 8	 2:00s	1:00	S
    +Rule	Belgium	1935	only	-	Mar	31	 2:00s	1:00	S
    +Rule	Belgium	1936	only	-	Apr	19	 2:00s	1:00	S
    +Rule	Belgium	1937	only	-	Apr	 4	 2:00s	1:00	S
    +Rule	Belgium	1938	only	-	Mar	27	 2:00s	1:00	S
    +Rule	Belgium	1939	only	-	Apr	16	 2:00s	1:00	S
    +Rule	Belgium	1939	only	-	Nov	19	 2:00s	0	-
    +Rule	Belgium	1940	only	-	Feb	25	 2:00s	1:00	S
    +Rule	Belgium	1944	only	-	Sep	17	 2:00s	0	-
    +Rule	Belgium	1945	only	-	Apr	 2	 2:00s	1:00	S
    +Rule	Belgium	1945	only	-	Sep	16	 2:00s	0	-
    +Rule	Belgium	1946	only	-	May	19	 2:00s	1:00	S
    +Rule	Belgium	1946	only	-	Oct	 7	 2:00s	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Brussels	0:17:30 -	LMT	1880
    +			0:17:30	-	BMT	1892 May  1 12:00 # Brussels MT
    +			0:00	-	WET	1914 Nov  8
    +			1:00	-	CET	1916 May  1  0:00
    +			1:00	C-Eur	CE%sT	1918 Nov 11 11:00u
    +			0:00	Belgium	WE%sT	1940 May 20  2:00s
    +			1:00	C-Eur	CE%sT	1944 Sep  3
    +			1:00	Belgium	CE%sT	1977
    +			1:00	EU	CE%sT
    +
    +# Bosnia and Herzegovina
    +# see Serbia
    +
    +# Bulgaria
    +#
    +# From Plamen Simenov via Steffen Thorsen (1999-09-09):
    +# A document of Government of Bulgaria (No.94/1997) says:
    +# EET --> EETDST is in 03:00 Local time in last Sunday of March ...
    +# EETDST --> EET is in 04:00 Local time in last Sunday of October
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Bulg	1979	only	-	Mar	31	23:00	1:00	S
    +Rule	Bulg	1979	only	-	Oct	 1	 1:00	0	-
    +Rule	Bulg	1980	1982	-	Apr	Sat>=1	23:00	1:00	S
    +Rule	Bulg	1980	only	-	Sep	29	 1:00	0	-
    +Rule	Bulg	1981	only	-	Sep	27	 2:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Sofia	1:33:16 -	LMT	1880
    +			1:56:56	-	IMT	1894 Nov 30 # Istanbul MT?
    +			2:00	-	EET	1942 Nov  2  3:00
    +			1:00	C-Eur	CE%sT	1945
    +			1:00	-	CET	1945 Apr 2 3:00
    +			2:00	-	EET	1979 Mar 31 23:00
    +			2:00	Bulg	EE%sT	1982 Sep 26  2:00
    +			2:00	C-Eur	EE%sT	1991
    +			2:00	E-Eur	EE%sT	1997
    +			2:00	EU	EE%sT
    +
    +# Croatia
    +# see Serbia
    +
    +# Cyprus
    +# Please see the `asia' file for Asia/Nicosia.
    +
    +# Czech Republic
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Czech	1945	only	-	Apr	 8	2:00s	1:00	S
    +Rule	Czech	1945	only	-	Nov	18	2:00s	0	-
    +Rule	Czech	1946	only	-	May	 6	2:00s	1:00	S
    +Rule	Czech	1946	1949	-	Oct	Sun>=1	2:00s	0	-
    +Rule	Czech	1947	only	-	Apr	20	2:00s	1:00	S
    +Rule	Czech	1948	only	-	Apr	18	2:00s	1:00	S
    +Rule	Czech	1949	only	-	Apr	 9	2:00s	1:00	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Prague	0:57:44 -	LMT	1850
    +			0:57:44	-	PMT	1891 Oct     # Prague Mean Time
    +			1:00	C-Eur	CE%sT	1944 Sep 17 2:00s
    +			1:00	Czech	CE%sT	1979
    +			1:00	EU	CE%sT
    +
    +# Denmark, Faroe Islands, and Greenland
    +
    +# From Jesper Norgaard Welen (2005-04-26):
    +# http://www.hum.aau.dk/~poe/tid/tine/DanskTid.htm says that the law
    +# [introducing standard time] was in effect from 1894-01-01....
    +# The page http://www.retsinfo.dk/_GETDOCI_/ACCN/A18930008330-REGL
    +# confirms this, and states that the law was put forth 1893-03-29.
    +#
    +# The EU treaty with effect from 1973:
    +# http://www.retsinfo.dk/_GETDOCI_/ACCN/A19722110030-REGL
    +#
    +# This provoked a new law from 1974 to make possible summer time changes
    +# in subsequenet decrees with the law
    +# http://www.retsinfo.dk/_GETDOCI_/ACCN/A19740022330-REGL
    +#
    +# It seems however that no decree was set forward until 1980.  I have
    +# not found any decree, but in another related law, the effecting DST
    +# changes are stated explicitly to be from 1980-04-06 at 02:00 to
    +# 1980-09-28 at 02:00.  If this is true, this differs slightly from
    +# the EU rule in that DST runs to 02:00, not 03:00.  We don't know
    +# when Denmark began using the EU rule correctly, but we have only
    +# confirmation of the 1980-time, so I presume it was correct in 1981:
    +# The law is about the management of the extra hour, concerning
    +# working hours reported and effect on obligatory-rest rules (which
    +# was suspended on that night):
    +# http://www.retsinfo.dk/_GETDOCI_/ACCN/C19801120554-REGL
    +
    +# From Jesper Norgaard Welen (2005-06-11):
    +# The Herning Folkeblad (1980-09-26) reported that the night between
    +# Saturday and Sunday the clock is set back from three to two.
    +
    +# From Paul Eggert (2005-06-11):
    +# Hence the "02:00" of the 1980 law refers to standard time, not
    +# wall-clock time, and so the EU rules were in effect in 1980.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Denmark	1916	only	-	May	14	23:00	1:00	S
    +Rule	Denmark	1916	only	-	Sep	30	23:00	0	-
    +Rule	Denmark	1940	only	-	May	15	 0:00	1:00	S
    +Rule	Denmark	1945	only	-	Apr	 2	 2:00s	1:00	S
    +Rule	Denmark	1945	only	-	Aug	15	 2:00s	0	-
    +Rule	Denmark	1946	only	-	May	 1	 2:00s	1:00	S
    +Rule	Denmark	1946	only	-	Sep	 1	 2:00s	0	-
    +Rule	Denmark	1947	only	-	May	 4	 2:00s	1:00	S
    +Rule	Denmark	1947	only	-	Aug	10	 2:00s	0	-
    +Rule	Denmark	1948	only	-	May	 9	 2:00s	1:00	S
    +Rule	Denmark	1948	only	-	Aug	 8	 2:00s	0	-
    +#
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Europe/Copenhagen	 0:50:20 -	LMT	1890
    +			 0:50:20 -	CMT	1894 Jan  1 # Copenhagen MT
    +			 1:00	Denmark	CE%sT	1942 Nov  2 2:00s
    +			 1:00	C-Eur	CE%sT	1945 Apr  2 2:00
    +			 1:00	Denmark	CE%sT	1980
    +			 1:00	EU	CE%sT
    +Zone Atlantic/Faroe	-0:27:04 -	LMT	1908 Jan 11	# Torshavn
    +			 0:00	-	WET	1981
    +			 0:00	EU	WE%sT
    +#
    +# From Paul Eggert (2004-10-31):
    +# During World War II, Germany maintained secret manned weather stations in
    +# East Greenland and Franz Josef Land, but we don't know their time zones.
    +# My source for this is Wilhelm Dege's book mentioned under Svalbard.
    +#
    +# From Paul Eggert (2006-03-22):
    +# Greenland joined the EU as part of Denmark, obtained home rule on 1979-05-01,
    +# and left the EU on 1985-02-01.  It therefore should have been using EU
    +# rules at least through 1984.  Shanks & Pottenger say Scoresbysund and Godthab
    +# used C-Eur rules after 1980, but IATA SSIM (1991/1996) says they use EU
    +# rules since at least 1991.  Assume EU rules since 1980.
    +
    +# From Gwillin Law (2001-06-06), citing
    +#  (2001-03-15),
    +# and with translations corrected by Steffen Thorsen:
    +#
    +# Greenland has four local times, and the relation to UTC
    +# is according to the following time line:
    +#
    +# The military zone near Thule	UTC-4
    +# Standard Greenland time	UTC-3
    +# Scoresbysund			UTC-1
    +# Danmarkshavn			UTC
    +#
    +# In the military area near Thule and in Danmarkshavn DST will not be
    +# introduced.
    +
    +# From Rives McDow (2001-11-01):
    +#
    +# I correspond regularly with the Dansk Polarcenter, and wrote them at
    +# the time to clarify the situation in Thule.  Unfortunately, I have
    +# not heard back from them regarding my recent letter.  [But I have
    +# info from earlier correspondence.]
    +#
    +# According to the center, a very small local time zone around Thule
    +# Air Base keeps the time according to UTC-4, implementing daylight
    +# savings using North America rules, changing the time at 02:00 local time....
    +#
    +# The east coast of Greenland north of the community of Scoresbysund
    +# uses UTC in the same way as in Iceland, year round, with no dst.
    +# There are just a few stations on this coast, including the
    +# Danmarkshavn ICAO weather station mentioned in your September 29th
    +# email.  The other stations are two sledge patrol stations in
    +# Mestersvig and Daneborg, the air force base at Station Nord, and the
    +# DPC research station at Zackenberg.
    +#
    +# Scoresbysund and two small villages nearby keep time UTC-1 and use
    +# the same daylight savings time period as in West Greenland (Godthab).
    +#
    +# The rest of Greenland, including Godthab (this area, although it
    +# includes central Greenland, is known as west Greenland), keeps time
    +# UTC-3, with daylight savings methods according to European rules.
    +#
    +# It is common procedure to use UTC 0 in the wilderness of East and
    +# North Greenland, because it is mainly Icelandic aircraft operators
    +# maintaining traffic in these areas.  However, the official status of
    +# this area is that it sticks with Godthab time.  This area might be
    +# considered a dual time zone in some respects because of this.
    +
    +# From Rives McDow (2001-11-19):
    +# I heard back from someone stationed at Thule; the time change took place
    +# there at 2:00 AM.
    +
    +# From Paul Eggert (2006-03-22):
    +# From 1997 on the CIA map shows Danmarkshavn on GMT;
    +# the 1995 map as like Godthab.
    +# For lack of better info, assume they were like Godthab before 1996.
    +# startkart.no says Thule does not observe DST, but this is clearly an error,
    +# so go with Shanks & Pottenger for Thule transitions until this year.
    +# For 2007 on assume Thule will stay in sync with US DST rules.
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Thule	1991	1992	-	Mar	lastSun	2:00	1:00	D
    +Rule	Thule	1991	1992	-	Sep	lastSun	2:00	0	S
    +Rule	Thule	1993	2006	-	Apr	Sun>=1	2:00	1:00	D
    +Rule	Thule	1993	2006	-	Oct	lastSun	2:00	0	S
    +Rule	Thule	2007	max	-	Mar	Sun>=8	2:00	1:00	D
    +Rule	Thule	2007	max	-	Nov	Sun>=1	2:00	0	S
    +#
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Danmarkshavn -1:14:40 -	LMT	1916 Jul 28
    +			-3:00	-	WGT	1980 Apr  6 2:00
    +			-3:00	EU	WG%sT	1996
    +			0:00	-	GMT
    +Zone America/Scoresbysund -1:27:52 -	LMT	1916 Jul 28 # Ittoqqortoormiit
    +			-2:00	-	CGT	1980 Apr  6 2:00
    +			-2:00	C-Eur	CG%sT	1981 Mar 29
    +			-1:00	EU	EG%sT
    +Zone America/Godthab	-3:26:56 -	LMT	1916 Jul 28 # Nuuk
    +			-3:00	-	WGT	1980 Apr  6 2:00
    +			-3:00	EU	WG%sT
    +Zone America/Thule	-4:35:08 -	LMT	1916 Jul 28 # Pituffik air base
    +			-4:00	Thule	A%sT
    +
    +# Estonia
    +# From Peter Ilieve (1994-10-15):
    +# A relative in Tallinn confirms the accuracy of the data for 1989 onwards
    +# [through 1994] and gives the legal authority for it,
    +# a regulation of the Government of Estonia, No. 111 of 1989....
    +#
    +# From Peter Ilieve (1996-10-28):
    +# [IATA SSIM (1992/1996) claims that the Baltic republics switch at 01:00s,
    +# but a relative confirms that Estonia still switches at 02:00s, writing:]
    +# ``I do not [know] exactly but there are some little different
    +# (confusing) rules for International Air and Railway Transport Schedules
    +# conversion in Sunday connected with end of summer time in Estonia....
    +# A discussion is running about the summer time efficiency and effect on
    +# human physiology.  It seems that Estonia maybe will not change to
    +# summer time next spring.''
    +
    +# From Peter Ilieve (1998-11-04), heavily edited:
    +# 
    +# The 1998-09-22 Estonian time law
    +# 
    +# refers to the Eighth Directive and cites the association agreement between
    +# the EU and Estonia, ratified by the Estonian law (RT II 1995, 22--27, 120).
    +#
    +# I also asked [my relative] whether they use any standard abbreviation
    +# for their standard and summer times. He says no, they use "suveaeg"
    +# (summer time) and "talveaeg" (winter time).
    +
    +# From The Baltic Times (1999-09-09)
    +# via Steffen Thorsen:
    +# This year will mark the last time Estonia shifts to summer time,
    +# a council of the ruling coalition announced Sept. 6....
    +# But what this could mean for Estonia's chances of joining the European
    +# Union are still unclear.  In 1994, the EU declared summer time compulsory
    +# for all member states until 2001.  Brussels has yet to decide what to do
    +# after that.
    +
    +# From Mart Oruaas (2000-01-29):
    +# Regulation no. 301 (1999-10-12) obsoletes previous regulation
    +# no. 206 (1998-09-22) and thus sticks Estonia to +02:00 GMT for all
    +# the year round.  The regulation is effective 1999-11-01.
    +
    +# From Toomas Soome (2002-02-21):
    +# The Estonian government has changed once again timezone politics.
    +# Now we are using again EU rules.
    +#
    +# From Urmet Jaanes (2002-03-28):
    +# The legislative reference is Government decree No. 84 on 2002-02-21.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Tallinn	1:39:00	-	LMT	1880
    +			1:39:00	-	TMT	1918 Feb # Tallinn Mean Time
    +			1:00	C-Eur	CE%sT	1919 Jul
    +			1:39:00	-	TMT	1921 May
    +			2:00	-	EET	1940 Aug  6
    +			3:00	-	MSK	1941 Sep 15
    +			1:00	C-Eur	CE%sT	1944 Sep 22
    +			3:00	Russia	MSK/MSD	1989 Mar 26 2:00s
    +			2:00	1:00	EEST	1989 Sep 24 2:00s
    +			2:00	C-Eur	EE%sT	1998 Sep 22
    +			2:00	EU	EE%sT	1999 Nov  1
    +			2:00	-	EET	2002 Feb 21
    +			2:00	EU	EE%sT
    +
    +# Finland
    +
    +# From Hannu Strang (1994-09-25 06:03:37 UTC):
    +# Well, here in Helsinki we're just changing from summer time to regular one,
    +# and it's supposed to change at 4am...
    +
    +# From Janne Snabb (2010-0715):
    +#
    +# I noticed that the Finland data is not accurate for years 1981 and 1982.
    +# During these two first trial years the DST adjustment was made one hour
    +# earlier than in forthcoming years. Starting 1983 the adjustment was made
    +# according to the central European standards.
    +#
    +# This is documented in Heikki Oja: Aikakirja 2007, published by The Almanac
    +# Office of University of Helsinki, ISBN 952-10-3221-9, available online (in
    +# Finnish) at
    +#
    +# 
    +# http://almanakka.helsinki.fi/aikakirja/Aikakirja2007kokonaan.pdf
    +# 
    +#
    +# Page 105 (56 in PDF version) has a handy table of all past daylight savings
    +# transitions. It is easy enough to interpret without Finnish skills.
    +#
    +# This is also confirmed by Finnish Broadcasting Company's archive at:
    +#
    +# 
    +# http://www.yle.fi/elavaarkisto/?s=s&g=1&ag=5&t=&a=3401
    +# 
    +#
    +# The news clip from 1981 says that "the time between 2 and 3 o'clock does not
    +# exist tonight."
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Finland	1942	only	-	Apr	3	0:00	1:00	S
    +Rule	Finland	1942	only	-	Oct	3	0:00	0	-
    +Rule	Finland	1981	1982	-	Mar	lastSun	2:00	1:00	S
    +Rule	Finland	1981	1982	-	Sep	lastSun	3:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Helsinki	1:39:52 -	LMT	1878 May 31
    +			1:39:52	-	HMT	1921 May    # Helsinki Mean Time
    +			2:00	Finland	EE%sT	1983
    +			2:00	EU	EE%sT
    +
    +# Aaland Is
    +Link	Europe/Helsinki	Europe/Mariehamn
    +
    +
    +# France
    +
    +# From Ciro Discepolo (2000-12-20):
    +#
    +# Henri Le Corre, Regimes Horaires pour le monde entier, Editions
    +# Traditionnelles - Paris 2 books, 1993
    +#
    +# Gabriel, Traite de l'heure dans le monde, Guy Tredaniel editeur,
    +# Paris, 1991
    +#
    +# Francoise Gauquelin, Problemes de l'heure resolus en astrologie,
    +# Guy tredaniel, Paris 1987
    +
    +
    +#
    +# Shank & Pottenger seem to use `24:00' ambiguously; resolve it with Whitman.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	France	1916	only	-	Jun	14	23:00s	1:00	S
    +Rule	France	1916	1919	-	Oct	Sun>=1	23:00s	0	-
    +Rule	France	1917	only	-	Mar	24	23:00s	1:00	S
    +Rule	France	1918	only	-	Mar	 9	23:00s	1:00	S
    +Rule	France	1919	only	-	Mar	 1	23:00s	1:00	S
    +Rule	France	1920	only	-	Feb	14	23:00s	1:00	S
    +Rule	France	1920	only	-	Oct	23	23:00s	0	-
    +Rule	France	1921	only	-	Mar	14	23:00s	1:00	S
    +Rule	France	1921	only	-	Oct	25	23:00s	0	-
    +Rule	France	1922	only	-	Mar	25	23:00s	1:00	S
    +# DSH writes that a law of 1923-05-24 specified 3rd Sat in Apr at 23:00 to 1st
    +# Sat in Oct at 24:00; and that in 1930, because of Easter, the transitions
    +# were Apr 12 and Oct 5.  Go with Shanks & Pottenger.
    +Rule	France	1922	1938	-	Oct	Sat>=1	23:00s	0	-
    +Rule	France	1923	only	-	May	26	23:00s	1:00	S
    +Rule	France	1924	only	-	Mar	29	23:00s	1:00	S
    +Rule	France	1925	only	-	Apr	 4	23:00s	1:00	S
    +Rule	France	1926	only	-	Apr	17	23:00s	1:00	S
    +Rule	France	1927	only	-	Apr	 9	23:00s	1:00	S
    +Rule	France	1928	only	-	Apr	14	23:00s	1:00	S
    +Rule	France	1929	only	-	Apr	20	23:00s	1:00	S
    +Rule	France	1930	only	-	Apr	12	23:00s	1:00	S
    +Rule	France	1931	only	-	Apr	18	23:00s	1:00	S
    +Rule	France	1932	only	-	Apr	 2	23:00s	1:00	S
    +Rule	France	1933	only	-	Mar	25	23:00s	1:00	S
    +Rule	France	1934	only	-	Apr	 7	23:00s	1:00	S
    +Rule	France	1935	only	-	Mar	30	23:00s	1:00	S
    +Rule	France	1936	only	-	Apr	18	23:00s	1:00	S
    +Rule	France	1937	only	-	Apr	 3	23:00s	1:00	S
    +Rule	France	1938	only	-	Mar	26	23:00s	1:00	S
    +Rule	France	1939	only	-	Apr	15	23:00s	1:00	S
    +Rule	France	1939	only	-	Nov	18	23:00s	0	-
    +Rule	France	1940	only	-	Feb	25	 2:00	1:00	S
    +# The French rules for 1941-1944 were not used in Paris, but Shanks & Pottenger
    +# write that they were used in Monaco and in many French locations.
    +# Le Corre writes that the upper limit of the free zone was Arneguy, Orthez,
    +# Mont-de-Marsan, Bazas, Langon, Lamotte-Montravel, Marouil, La
    +# Rochefoucault, Champagne-Mouton, La Roche-Posay, La Haye-Descartes,
    +# Loches, Montrichard, Vierzon, Bourges, Moulins, Digoin,
    +# Paray-le-Monial, Montceau-les-Mines, Chalons-sur-Saone, Arbois,
    +# Dole, Morez, St-Claude, and Collonges (Haute-Savoie).
    +Rule	France	1941	only	-	May	 5	 0:00	2:00	M # Midsummer
    +# Shanks & Pottenger say this transition occurred at Oct 6 1:00,
    +# but go with Denis Excoffier (1997-12-12),
    +# who quotes the Ephemerides Astronomiques for 1998 from Bureau des Longitudes
    +# as saying 5/10/41 22hUT.
    +Rule	France	1941	only	-	Oct	 6	 0:00	1:00	S
    +Rule	France	1942	only	-	Mar	 9	 0:00	2:00	M
    +Rule	France	1942	only	-	Nov	 2	 3:00	1:00	S
    +Rule	France	1943	only	-	Mar	29	 2:00	2:00	M
    +Rule	France	1943	only	-	Oct	 4	 3:00	1:00	S
    +Rule	France	1944	only	-	Apr	 3	 2:00	2:00	M
    +Rule	France	1944	only	-	Oct	 8	 1:00	1:00	S
    +Rule	France	1945	only	-	Apr	 2	 2:00	2:00	M
    +Rule	France	1945	only	-	Sep	16	 3:00	0	-
    +# Shanks & Pottenger give Mar 28 2:00 and Sep 26 3:00;
    +# go with Excoffier's 28/3/76 0hUT and 25/9/76 23hUT.
    +Rule	France	1976	only	-	Mar	28	 1:00	1:00	S
    +Rule	France	1976	only	-	Sep	26	 1:00	0	-
    +# Shanks & Pottenger give 0:09:20 for Paris Mean Time, and Whitman 0:09:05,
    +# but Howse quotes the actual French legislation as saying 0:09:21.
    +# Go with Howse.  Howse writes that the time in France was officially based
    +# on PMT-0:09:21 until 1978-08-09, when the time base finally switched to UTC.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Paris	0:09:21 -	LMT	1891 Mar 15  0:01
    +			0:09:21	-	PMT	1911 Mar 11  0:01  # Paris MT
    +# Shanks & Pottenger give 1940 Jun 14 0:00; go with Excoffier and Le Corre.
    +			0:00	France	WE%sT	1940 Jun 14 23:00
    +# Le Corre says Paris stuck with occupied-France time after the liberation;
    +# go with Shanks & Pottenger.
    +			1:00	C-Eur	CE%sT	1944 Aug 25
    +			0:00	France	WE%sT	1945 Sep 16  3:00
    +			1:00	France	CE%sT	1977
    +			1:00	EU	CE%sT
    +
    +# Germany
    +
    +# From Markus Kuhn (1998-09-29):
    +# The German time zone web site by the Physikalisch-Technische
    +# Bundesanstalt contains DST information back to 1916.
    +# [See tz-link.htm for the URL.]
    +
    +# From Joerg Schilling (2002-10-23):
    +# In 1945, Berlin was switched to Moscow Summer time (GMT+4) by
    +# 
    +# General [Nikolai] Bersarin.
    +
    +# From Paul Eggert (2003-03-08):
    +# 
    +# http://www.parlament-berlin.de/pds-fraktion.nsf/727459127c8b66ee8525662300459099/defc77cb784f180ac1256c2b0030274b/$FILE/bersarint.pdf
    +# 
    +# says that Bersarin issued an order to use Moscow time on May 20.
    +# However, Moscow did not observe daylight saving in 1945, so
    +# this was equivalent to CEMT (GMT+3), not GMT+4.
    +
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Germany	1946	only	-	Apr	14	2:00s	1:00	S
    +Rule	Germany	1946	only	-	Oct	 7	2:00s	0	-
    +Rule	Germany	1947	1949	-	Oct	Sun>=1	2:00s	0	-
    +# http://www.ptb.de/de/org/4/44/441/salt.htm says the following transition
    +# occurred at 3:00 MEZ, not the 2:00 MEZ given in Shanks & Pottenger.
    +# Go with the PTB.
    +Rule	Germany	1947	only	-	Apr	 6	3:00s	1:00	S
    +Rule	Germany	1947	only	-	May	11	2:00s	2:00	M
    +Rule	Germany	1947	only	-	Jun	29	3:00	1:00	S
    +Rule	Germany	1948	only	-	Apr	18	2:00s	1:00	S
    +Rule	Germany	1949	only	-	Apr	10	2:00s	1:00	S
    +
    +Rule SovietZone	1945	only	-	May	24	2:00	2:00	M # Midsummer
    +Rule SovietZone	1945	only	-	Sep	24	3:00	1:00	S
    +Rule SovietZone	1945	only	-	Nov	18	2:00s	0	-
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Berlin	0:53:28 -	LMT	1893 Apr
    +			1:00	C-Eur	CE%sT	1945 May 24 2:00
    +			1:00 SovietZone	CE%sT	1946
    +			1:00	Germany	CE%sT	1980
    +			1:00	EU	CE%sT
    +
    +# Georgia
    +# Please see the "asia" file for Asia/Tbilisi.
    +# Herodotus (Histories, IV.45) says Georgia north of the Phasis (now Rioni)
    +# is in Europe.  Our reference location Tbilisi is in the Asian part.
    +
    +# Gibraltar
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Europe/Gibraltar	-0:21:24 -	LMT	1880 Aug  2 0:00s
    +			0:00	GB-Eire	%s	1957 Apr 14 2:00
    +			1:00	-	CET	1982
    +			1:00	EU	CE%sT
    +
    +# Greece
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +# Whitman gives 1932 Jul 5 - Nov 1; go with Shanks & Pottenger.
    +Rule	Greece	1932	only	-	Jul	 7	0:00	1:00	S
    +Rule	Greece	1932	only	-	Sep	 1	0:00	0	-
    +# Whitman gives 1941 Apr 25 - ?; go with Shanks & Pottenger.
    +Rule	Greece	1941	only	-	Apr	 7	0:00	1:00	S
    +# Whitman gives 1942 Feb 2 - ?; go with Shanks & Pottenger.
    +Rule	Greece	1942	only	-	Nov	 2	3:00	0	-
    +Rule	Greece	1943	only	-	Mar	30	0:00	1:00	S
    +Rule	Greece	1943	only	-	Oct	 4	0:00	0	-
    +# Whitman gives 1944 Oct 3 - Oct 31; go with Shanks & Pottenger.
    +Rule	Greece	1952	only	-	Jul	 1	0:00	1:00	S
    +Rule	Greece	1952	only	-	Nov	 2	0:00	0	-
    +Rule	Greece	1975	only	-	Apr	12	0:00s	1:00	S
    +Rule	Greece	1975	only	-	Nov	26	0:00s	0	-
    +Rule	Greece	1976	only	-	Apr	11	2:00s	1:00	S
    +Rule	Greece	1976	only	-	Oct	10	2:00s	0	-
    +Rule	Greece	1977	1978	-	Apr	Sun>=1	2:00s	1:00	S
    +Rule	Greece	1977	only	-	Sep	26	2:00s	0	-
    +Rule	Greece	1978	only	-	Sep	24	4:00	0	-
    +Rule	Greece	1979	only	-	Apr	 1	9:00	1:00	S
    +Rule	Greece	1979	only	-	Sep	29	2:00	0	-
    +Rule	Greece	1980	only	-	Apr	 1	0:00	1:00	S
    +Rule	Greece	1980	only	-	Sep	28	0:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Athens	1:34:52 -	LMT	1895 Sep 14
    +			1:34:52	-	AMT	1916 Jul 28 0:01     # Athens MT
    +			2:00	Greece	EE%sT	1941 Apr 30
    +			1:00	Greece	CE%sT	1944 Apr  4
    +			2:00	Greece	EE%sT	1981
    +			# Shanks & Pottenger say it switched to C-Eur in 1981;
    +			# go with EU instead, since Greece joined it on Jan 1.
    +			2:00	EU	EE%sT
    +
    +# Hungary
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Hungary	1918	only	-	Apr	 1	 3:00	1:00	S
    +Rule	Hungary	1918	only	-	Sep	29	 3:00	0	-
    +Rule	Hungary	1919	only	-	Apr	15	 3:00	1:00	S
    +Rule	Hungary	1919	only	-	Sep	15	 3:00	0	-
    +Rule	Hungary	1920	only	-	Apr	 5	 3:00	1:00	S
    +Rule	Hungary	1920	only	-	Sep	30	 3:00	0	-
    +Rule	Hungary	1945	only	-	May	 1	23:00	1:00	S
    +Rule	Hungary	1945	only	-	Nov	 3	 0:00	0	-
    +Rule	Hungary	1946	only	-	Mar	31	 2:00s	1:00	S
    +Rule	Hungary	1946	1949	-	Oct	Sun>=1	 2:00s	0	-
    +Rule	Hungary	1947	1949	-	Apr	Sun>=4	 2:00s	1:00	S
    +Rule	Hungary	1950	only	-	Apr	17	 2:00s	1:00	S
    +Rule	Hungary	1950	only	-	Oct	23	 2:00s	0	-
    +Rule	Hungary	1954	1955	-	May	23	 0:00	1:00	S
    +Rule	Hungary	1954	1955	-	Oct	 3	 0:00	0	-
    +Rule	Hungary	1956	only	-	Jun	Sun>=1	 0:00	1:00	S
    +Rule	Hungary	1956	only	-	Sep	lastSun	 0:00	0	-
    +Rule	Hungary	1957	only	-	Jun	Sun>=1	 1:00	1:00	S
    +Rule	Hungary	1957	only	-	Sep	lastSun	 3:00	0	-
    +Rule	Hungary	1980	only	-	Apr	 6	 1:00	1:00	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Budapest	1:16:20 -	LMT	1890 Oct
    +			1:00	C-Eur	CE%sT	1918
    +			1:00	Hungary	CE%sT	1941 Apr  6  2:00
    +			1:00	C-Eur	CE%sT	1945
    +			1:00	Hungary	CE%sT	1980 Sep 28  2:00s
    +			1:00	EU	CE%sT
    +
    +# Iceland
    +#
    +# From Adam David (1993-11-06):
    +# The name of the timezone in Iceland for system / mail / news purposes is GMT.
    +#
    +# (1993-12-05):
    +# This material is paraphrased from the 1988 edition of the University of
    +# Iceland Almanak.
    +#
    +# From January 1st, 1908 the whole of Iceland was standardised at 1 hour
    +# behind GMT. Previously, local mean solar time was used in different parts
    +# of Iceland, the almanak had been based on Reykjavik mean solar time which
    +# was 1 hour and 28 minutes behind GMT.
    +#
    +# "first day of winter" referred to [below] means the first day of the 26 weeks
    +# of winter, according to the old icelandic calendar that dates back to the
    +# time the norsemen first settled Iceland.  The first day of winter is always
    +# Saturday, but is not dependent on the Julian or Gregorian calendars.
    +#
    +# (1993-12-10):
    +# I have a reference from the Oxford Icelandic-English dictionary for the
    +# beginning of winter, which ties it to the ecclesiastical calendar (and thus
    +# to the julian/gregorian calendar) over the period in question.
    +#	the winter begins on the Saturday next before St. Luke's day
    +#	(old style), or on St. Luke's day, if a Saturday.
    +# St. Luke's day ought to be traceable from ecclesiastical sources. "old style"
    +# might be a reference to the Julian calendar as opposed to Gregorian, or it
    +# might mean something else (???).
    +#
    +# From Paul Eggert (2006-03-22):
    +# The Iceland Almanak, Shanks & Pottenger, and Whitman disagree on many points.
    +# We go with the Almanak, except for one claim from Shanks & Pottenger, namely
    +# that Reykavik was 21W57 from 1837 to 1908, local mean time before that.
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Iceland	1917	1918	-	Feb	19	23:00	1:00	S
    +Rule	Iceland	1917	only	-	Oct	21	 1:00	0	-
    +Rule	Iceland	1918	only	-	Nov	16	 1:00	0	-
    +Rule	Iceland	1939	only	-	Apr	29	23:00	1:00	S
    +Rule	Iceland	1939	only	-	Nov	29	 2:00	0	-
    +Rule	Iceland	1940	only	-	Feb	25	 2:00	1:00	S
    +Rule	Iceland	1940	only	-	Nov	 3	 2:00	0	-
    +Rule	Iceland	1941	only	-	Mar	 2	 1:00s	1:00	S
    +Rule	Iceland	1941	only	-	Nov	 2	 1:00s	0	-
    +Rule	Iceland	1942	only	-	Mar	 8	 1:00s	1:00	S
    +Rule	Iceland	1942	only	-	Oct	25	 1:00s	0	-
    +# 1943-1946 - first Sunday in March until first Sunday in winter
    +Rule	Iceland	1943	1946	-	Mar	Sun>=1	 1:00s	1:00	S
    +Rule	Iceland	1943	1948	-	Oct	Sun>=22	 1:00s	0	-
    +# 1947-1967 - first Sunday in April until first Sunday in winter
    +Rule	Iceland	1947	1967	-	Apr	Sun>=1	 1:00s	1:00	S
    +# 1949 Oct transition delayed by 1 week
    +Rule	Iceland	1949	only	-	Oct	30	 1:00s	0	-
    +Rule	Iceland	1950	1966	-	Oct	Sun>=22	 1:00s	0	-
    +Rule	Iceland	1967	only	-	Oct	29	 1:00s	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Atlantic/Reykjavik	-1:27:24 -	LMT	1837
    +			-1:27:48 -	RMT	1908 # Reykjavik Mean Time?
    +			-1:00	Iceland	IS%sT	1968 Apr 7 1:00s
    +			 0:00	-	GMT
    +
    +# Italy
    +#
    +# From Paul Eggert (2001-03-06):
    +# Sicily and Sardinia each had their own time zones from 1866 to 1893,
    +# called Palermo Time (+00:53:28) and Cagliari Time (+00:36:32).
    +# During World War II, German-controlled Italy used German time.
    +# But these events all occurred before the 1970 cutoff,
    +# so record only the time in Rome.
    +#
    +# From Paul Eggert (2006-03-22):
    +# For Italian DST we have three sources: Shanks & Pottenger, Whitman, and
    +# F. Pollastri
    +# 
    +# Day-light Saving Time in Italy (2006-02-03)
    +# 
    +# (`FP' below), taken from an Italian National Electrotechnical Institute
    +# publication. When the three sources disagree, guess who's right, as follows:
    +#
    +# year	FP	Shanks&P. (S)	Whitman (W)	Go with:
    +# 1916	06-03	06-03 24:00	06-03 00:00	FP & W
    +#	09-30	09-30 24:00	09-30 01:00	FP; guess 24:00s
    +# 1917	04-01	03-31 24:00	03-31 00:00	FP & S
    +#	09-30	09-29 24:00	09-30 01:00	FP & W
    +# 1918	03-09	03-09 24:00	03-09 00:00	FP & S
    +#	10-06	10-05 24:00	10-06 01:00	FP & W
    +# 1919	03-01	03-01 24:00	03-01 00:00	FP & S
    +#	10-04	10-04 24:00	10-04 01:00	FP; guess 24:00s
    +# 1920	03-20	03-20 24:00	03-20 00:00	FP & S
    +#	09-18	09-18 24:00	10-01 01:00	FP; guess 24:00s
    +# 1944	04-02	04-03 02:00			S (see C-Eur)
    +#	09-16	10-02 03:00			FP; guess 24:00s
    +# 1945	09-14	09-16 24:00			FP; guess 24:00s
    +# 1970	05-21	05-31 00:00			S
    +#	09-20	09-27 00:00			S
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Italy	1916	only	-	Jun	 3	0:00s	1:00	S
    +Rule	Italy	1916	only	-	Oct	 1	0:00s	0	-
    +Rule	Italy	1917	only	-	Apr	 1	0:00s	1:00	S
    +Rule	Italy	1917	only	-	Sep	30	0:00s	0	-
    +Rule	Italy	1918	only	-	Mar	10	0:00s	1:00	S
    +Rule	Italy	1918	1919	-	Oct	Sun>=1	0:00s	0	-
    +Rule	Italy	1919	only	-	Mar	 2	0:00s	1:00	S
    +Rule	Italy	1920	only	-	Mar	21	0:00s	1:00	S
    +Rule	Italy	1920	only	-	Sep	19	0:00s	0	-
    +Rule	Italy	1940	only	-	Jun	15	0:00s	1:00	S
    +Rule	Italy	1944	only	-	Sep	17	0:00s	0	-
    +Rule	Italy	1945	only	-	Apr	 2	2:00	1:00	S
    +Rule	Italy	1945	only	-	Sep	15	0:00s	0	-
    +Rule	Italy	1946	only	-	Mar	17	2:00s	1:00	S
    +Rule	Italy	1946	only	-	Oct	 6	2:00s	0	-
    +Rule	Italy	1947	only	-	Mar	16	0:00s	1:00	S
    +Rule	Italy	1947	only	-	Oct	 5	0:00s	0	-
    +Rule	Italy	1948	only	-	Feb	29	2:00s	1:00	S
    +Rule	Italy	1948	only	-	Oct	 3	2:00s	0	-
    +Rule	Italy	1966	1968	-	May	Sun>=22	0:00	1:00	S
    +Rule	Italy	1966	1969	-	Sep	Sun>=22	0:00	0	-
    +Rule	Italy	1969	only	-	Jun	 1	0:00	1:00	S
    +Rule	Italy	1970	only	-	May	31	0:00	1:00	S
    +Rule	Italy	1970	only	-	Sep	lastSun	0:00	0	-
    +Rule	Italy	1971	1972	-	May	Sun>=22	0:00	1:00	S
    +Rule	Italy	1971	only	-	Sep	lastSun	1:00	0	-
    +Rule	Italy	1972	only	-	Oct	 1	0:00	0	-
    +Rule	Italy	1973	only	-	Jun	 3	0:00	1:00	S
    +Rule	Italy	1973	1974	-	Sep	lastSun	0:00	0	-
    +Rule	Italy	1974	only	-	May	26	0:00	1:00	S
    +Rule	Italy	1975	only	-	Jun	 1	0:00s	1:00	S
    +Rule	Italy	1975	1977	-	Sep	lastSun	0:00s	0	-
    +Rule	Italy	1976	only	-	May	30	0:00s	1:00	S
    +Rule	Italy	1977	1979	-	May	Sun>=22	0:00s	1:00	S
    +Rule	Italy	1978	only	-	Oct	 1	0:00s	0	-
    +Rule	Italy	1979	only	-	Sep	30	0:00s	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Rome	0:49:56 -	LMT	1866 Sep 22
    +			0:49:56	-	RMT	1893 Nov  1 0:00s # Rome Mean
    +			1:00	Italy	CE%sT	1942 Nov  2 2:00s
    +			1:00	C-Eur	CE%sT	1944 Jul
    +			1:00	Italy	CE%sT	1980
    +			1:00	EU	CE%sT
    +
    +Link	Europe/Rome	Europe/Vatican
    +Link	Europe/Rome	Europe/San_Marino
    +
    +# Latvia
    +
    +# From Liene Kanepe (1998-09-17):
    +
    +# I asked about this matter Scientific Secretary of the Institute of Astronomy
    +# of The University of Latvia Dr. paed Mr. Ilgonis Vilks. I also searched the
    +# correct data in juridical acts and I found some juridical documents about
    +# changes in the counting of time in Latvia from 1981....
    +#
    +# Act No.35 of the Council of Ministers of Latvian SSR of 1981-01-22 ...
    +# according to the Act No.925 of the Council of Ministers of USSR of 1980-10-24
    +# ...: all year round the time of 2nd time zone + 1 hour, in addition turning
    +# the hands of the clock 1 hour forward on 1 April at 00:00 (GMT 31 March 21:00)
    +# and 1 hour backward on the 1 October at 00:00 (GMT 30 September 20:00).
    +#
    +# Act No.592 of the Council of Ministers of Latvian SSR of 1984-09-24 ...
    +# according to the Act No.967 of the Council of Ministers of USSR of 1984-09-13
    +# ...: all year round the time of 2nd time zone + 1 hour, in addition turning
    +# the hands of the clock 1 hour forward on the last Sunday of March at 02:00
    +# (GMT 23:00 on the previous day) and 1 hour backward on the last Sunday of
    +# September at 03:00 (GMT 23:00 on the previous day).
    +#
    +# Act No.81 of the Council of Ministers of Latvian SSR of 1989-03-22 ...
    +# according to the Act No.227 of the Council of Ministers of USSR of 1989-03-14
    +# ...: since the last Sunday of March 1989 in Lithuanian SSR, Latvian SSR,
    +# Estonian SSR and Kaliningrad region of Russian Federation all year round the
    +# time of 2nd time zone (Moscow time minus one hour). On the territory of Latvia
    +# transition to summer time is performed on the last Sunday of March at 02:00
    +# (GMT 00:00), turning the hands of the clock 1 hour forward.  The end of
    +# daylight saving time is performed on the last Sunday of September at 03:00
    +# (GMT 00:00), turning the hands of the clock 1 hour backward. Exception is
    +# 1989-03-26, when we must not turn the hands of the clock....
    +#
    +# The Regulations of the Cabinet of Ministers of the Republic of Latvia of
    +# 1997-01-21 on transition to Summer time ... established the same order of
    +# daylight savings time settings as in the States of the European Union.
    +
    +# From Andrei Ivanov (2000-03-06):
    +# This year Latvia will not switch to Daylight Savings Time (as specified in
    +# 
    +# The Regulations of the Cabinet of Ministers of the Rep. of Latvia of
    +# 29-Feb-2000 (#79), in Latvian for subscribers only).
    +
    +# 
    +# From RFE/RL Newsline (2001-01-03), noted after a heads-up by Rives McDow:
    +# 
    +# The Latvian government on 2 January decided that the country will
    +# institute daylight-saving time this spring, LETA reported.
    +# Last February the three Baltic states decided not to turn back their
    +# clocks one hour in the spring....
    +# Minister of Economy Aigars Kalvitis noted that Latvia had too few
    +# daylight hours and thus decided to comply with a draft European
    +# Commission directive that provides for instituting daylight-saving
    +# time in EU countries between 2002 and 2006. The Latvian government
    +# urged Lithuania and Estonia to adopt a similar time policy, but it
    +# appears that they will not do so....
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Latvia	1989	1996	-	Mar	lastSun	 2:00s	1:00	S
    +Rule	Latvia	1989	1996	-	Sep	lastSun	 2:00s	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Riga	1:36:24	-	LMT	1880
    +			1:36:24	-	RMT	1918 Apr 15 2:00 #Riga Mean Time
    +			1:36:24	1:00	LST	1918 Sep 16 3:00 #Latvian Summer
    +			1:36:24	-	RMT	1919 Apr  1 2:00
    +			1:36:24	1:00	LST	1919 May 22 3:00
    +			1:36:24	-	RMT	1926 May 11
    +			2:00	-	EET	1940 Aug  5
    +			3:00	-	MSK	1941 Jul
    +			1:00	C-Eur	CE%sT	1944 Oct 13
    +			3:00	Russia	MSK/MSD	1989 Mar lastSun 2:00s
    +			2:00	1:00	EEST	1989 Sep lastSun 2:00s
    +			2:00	Latvia	EE%sT	1997 Jan 21
    +			2:00	EU	EE%sT	2000 Feb 29
    +			2:00	-	EET	2001 Jan  2
    +			2:00	EU	EE%sT
    +
    +# Liechtenstein
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Vaduz	0:38:04 -	LMT	1894 Jun
    +			1:00	-	CET	1981
    +			1:00	EU	CE%sT
    +
    +# Lithuania
    +
    +# From Paul Eggert (1996-11-22):
    +# IATA SSIM (1992/1996) says Lithuania uses W-Eur rules, but since it is
    +# known to be wrong about Estonia and Latvia, assume it's wrong here too.
    +
    +# From Marius Gedminas (1998-08-07):
    +# I would like to inform that in this year Lithuanian time zone
    +# (Europe/Vilnius) was changed.
    +
    +# From ELTA No. 972 (2582) (1999-09-29),
    +# via Steffen Thorsen:
    +# Lithuania has shifted back to the second time zone (GMT plus two hours)
    +# to be valid here starting from October 31,
    +# as decided by the national government on Wednesday....
    +# The Lithuanian government also announced plans to consider a
    +# motion to give up shifting to summer time in spring, as it was
    +# already done by Estonia.
    +
    +# From the 
    +# Fact File, Lithuanian State Department of Tourism
    +#  (2000-03-27): Local time is GMT+2 hours ..., no daylight saving.
    +
    +# From a user via Klaus Marten (2003-02-07):
    +# As a candidate for membership of the European Union, Lithuania will
    +# observe Summer Time in 2003, changing its clocks at the times laid
    +# down in EU Directive 2000/84 of 19.I.01 (i.e. at the same times as its
    +# neighbour Latvia). The text of the Lithuanian government Order of
    +# 7.XI.02 to this effect can be found at
    +# http://www.lrvk.lt/nut/11/n1749.htm
    +
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Vilnius	1:41:16	-	LMT	1880
    +			1:24:00	-	WMT	1917	    # Warsaw Mean Time
    +			1:35:36	-	KMT	1919 Oct 10 # Kaunas Mean Time
    +			1:00	-	CET	1920 Jul 12
    +			2:00	-	EET	1920 Oct  9
    +			1:00	-	CET	1940 Aug  3
    +			3:00	-	MSK	1941 Jun 24
    +			1:00	C-Eur	CE%sT	1944 Aug
    +			3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
    +			2:00	1:00	EEST	1991 Sep 29 2:00s
    +			2:00	C-Eur	EE%sT	1998
    +			2:00	-	EET	1998 Mar 29 1:00u
    +			1:00	EU	CE%sT	1999 Oct 31 1:00u
    +			2:00	-	EET	2003 Jan  1
    +			2:00	EU	EE%sT
    +
    +# Luxembourg
    +# Whitman disagrees with most of these dates in minor ways;
    +# go with Shanks & Pottenger.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Lux	1916	only	-	May	14	23:00	1:00	S
    +Rule	Lux	1916	only	-	Oct	 1	 1:00	0	-
    +Rule	Lux	1917	only	-	Apr	28	23:00	1:00	S
    +Rule	Lux	1917	only	-	Sep	17	 1:00	0	-
    +Rule	Lux	1918	only	-	Apr	Mon>=15	 2:00s	1:00	S
    +Rule	Lux	1918	only	-	Sep	Mon>=15	 2:00s	0	-
    +Rule	Lux	1919	only	-	Mar	 1	23:00	1:00	S
    +Rule	Lux	1919	only	-	Oct	 5	 3:00	0	-
    +Rule	Lux	1920	only	-	Feb	14	23:00	1:00	S
    +Rule	Lux	1920	only	-	Oct	24	 2:00	0	-
    +Rule	Lux	1921	only	-	Mar	14	23:00	1:00	S
    +Rule	Lux	1921	only	-	Oct	26	 2:00	0	-
    +Rule	Lux	1922	only	-	Mar	25	23:00	1:00	S
    +Rule	Lux	1922	only	-	Oct	Sun>=2	 1:00	0	-
    +Rule	Lux	1923	only	-	Apr	21	23:00	1:00	S
    +Rule	Lux	1923	only	-	Oct	Sun>=2	 2:00	0	-
    +Rule	Lux	1924	only	-	Mar	29	23:00	1:00	S
    +Rule	Lux	1924	1928	-	Oct	Sun>=2	 1:00	0	-
    +Rule	Lux	1925	only	-	Apr	 5	23:00	1:00	S
    +Rule	Lux	1926	only	-	Apr	17	23:00	1:00	S
    +Rule	Lux	1927	only	-	Apr	 9	23:00	1:00	S
    +Rule	Lux	1928	only	-	Apr	14	23:00	1:00	S
    +Rule	Lux	1929	only	-	Apr	20	23:00	1:00	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Europe/Luxembourg	0:24:36 -	LMT	1904 Jun
    +			1:00	Lux	CE%sT	1918 Nov 25
    +			0:00	Lux	WE%sT	1929 Oct  6 2:00s
    +			0:00	Belgium	WE%sT	1940 May 14 3:00
    +			1:00	C-Eur	WE%sT	1944 Sep 18 3:00
    +			1:00	Belgium	CE%sT	1977
    +			1:00	EU	CE%sT
    +
    +# Macedonia
    +# see Serbia
    +
    +# Malta
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Malta	1973	only	-	Mar	31	0:00s	1:00	S
    +Rule	Malta	1973	only	-	Sep	29	0:00s	0	-
    +Rule	Malta	1974	only	-	Apr	21	0:00s	1:00	S
    +Rule	Malta	1974	only	-	Sep	16	0:00s	0	-
    +Rule	Malta	1975	1979	-	Apr	Sun>=15	2:00	1:00	S
    +Rule	Malta	1975	1980	-	Sep	Sun>=15	2:00	0	-
    +Rule	Malta	1980	only	-	Mar	31	2:00	1:00	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Malta	0:58:04 -	LMT	1893 Nov  2 0:00s # Valletta
    +			1:00	Italy	CE%sT	1942 Nov  2 2:00s
    +			1:00	C-Eur	CE%sT	1945 Apr  2 2:00s
    +			1:00	Italy	CE%sT	1973 Mar 31
    +			1:00	Malta	CE%sT	1981
    +			1:00	EU	CE%sT
    +
    +# Moldova
    +
    +# From Paul Eggert (2006-03-22):
    +# A previous version of this database followed Shanks & Pottenger, who write
    +# that Tiraspol switched to Moscow time on 1992-01-19 at 02:00.
    +# However, this is most likely an error, as Moldova declared independence
    +# on 1991-08-27 (the 1992-01-19 date is that of a Russian decree).
    +# In early 1992 there was large-scale interethnic violence in the area
    +# and it's possible that some Russophones continued to observe Moscow time.
    +# But [two people] separately reported via
    +# Jesper Norgaard that as of 2001-01-24 Tiraspol was like Chisinau.
    +# The Tiraspol entry has therefore been removed for now.
    +#
    +# From Alexander Krivenyshev (2011-10-17):
    +# Pridnestrovian Moldavian Republic (PMR, also known as
    +# "Pridnestrovie") has abolished seasonal clock change (no transition
    +# to the Winter Time).
    +#
    +# News (in Russian):
    +# 
    +# http://www.kyivpost.ua/russia/news/pridnestrove-otkazalos-ot-perehoda-na-zimnee-vremya-30954.html
    +# 
    +#
    +# 
    +# http://www.allmoldova.com/moldova-news/1249064116.html
    +# 
    +#
    +# The substance of this change (reinstatement of the Tiraspol entry)
    +# is from a patch from Petr Machata (2011-10-17)
    +#
    +# From Tim Parenti (2011-10-19)
    +# In addition, being situated at +4651+2938 would give Tiraspol
    +# a pre-1880 LMT offset of 1:58:32.
    +#
    +# (which agrees with the earlier entry that had been removed)
    +#
    +# From Alexander Krivenyshev (2011-10-26)
    +# NO need to divide Moldova into two timezones at this point.
    +# As of today, Transnistria (Pridnestrovie)- Tiraspol reversed its own
    +# decision to abolish DST this winter.
    +# Following Moldova and neighboring Ukraine- Transnistria (Pridnestrovie)-
    +# Tiraspol will go back to winter time on October 30, 2011.
    +# News from Moldova (in russian):
    +# 
    +# http://ru.publika.md/link_317061.html
    +# 
    +
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Chisinau	1:55:20 -	LMT	1880
    +			1:55	-	CMT	1918 Feb 15 # Chisinau MT
    +			1:44:24	-	BMT	1931 Jul 24 # Bucharest MT
    +			2:00	Romania	EE%sT	1940 Aug 15
    +			2:00	1:00	EEST	1941 Jul 17
    +			1:00	C-Eur	CE%sT	1944 Aug 24
    +			3:00	Russia	MSK/MSD	1990
    +			3:00	-	MSK	1990 May 6
    +			2:00	-	EET	1991
    +			2:00	Russia	EE%sT	1992
    +			2:00	E-Eur	EE%sT	1997
    +# See Romania commentary for the guessed 1997 transition to EU rules.
    +			2:00	EU	EE%sT
    +
    +# Monaco
    +# Shanks & Pottenger give 0:09:20 for Paris Mean Time; go with Howse's
    +# more precise 0:09:21.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Monaco	0:29:32 -	LMT	1891 Mar 15
    +			0:09:21	-	PMT	1911 Mar 11    # Paris Mean Time
    +			0:00	France	WE%sT	1945 Sep 16 3:00
    +			1:00	France	CE%sT	1977
    +			1:00	EU	CE%sT
    +
    +# Montenegro
    +# see Serbia
    +
    +# Netherlands
    +
    +# Howse writes that the Netherlands' railways used GMT between 1892 and 1940,
    +# but for other purposes the Netherlands used Amsterdam mean time.
    +
    +# However, Robert H. van Gent writes (2001-04-01):
    +# Howse's statement is only correct up to 1909. From 1909-05-01 (00:00:00
    +# Amsterdam mean time) onwards, the whole of the Netherlands (including
    +# the Dutch railways) was required by law to observe Amsterdam mean time
    +# (19 minutes 32.13 seconds ahead of GMT). This had already been the
    +# common practice (except for the railways) for many decades but it was
    +# not until 1909 when the Dutch government finally defined this by law.
    +# On 1937-07-01 this was changed to 20 minutes (exactly) ahead of GMT and
    +# was generally known as Dutch Time ("Nederlandse Tijd").
    +#
    +# (2001-04-08):
    +# 1892-05-01 was the date when the Dutch railways were by law required to
    +# observe GMT while the remainder of the Netherlands adhered to the common
    +# practice of following Amsterdam mean time.
    +#
    +# (2001-04-09):
    +# In 1835 the authorities of the province of North Holland requested the
    +# municipal authorities of the towns and cities in the province to observe
    +# Amsterdam mean time but I do not know in how many cases this request was
    +# actually followed.
    +#
    +# From 1852 onwards the Dutch telegraph offices were by law required to
    +# observe Amsterdam mean time. As the time signals from the observatory of
    +# Leiden were also distributed by the telegraph system, I assume that most
    +# places linked up with the telegraph (and railway) system automatically
    +# adopted Amsterdam mean time.
    +#
    +# Although the early Dutch railway companies initially observed a variety
    +# of times, most of them had adopted Amsterdam mean time by 1858 but it
    +# was not until 1866 when they were all required by law to observe
    +# Amsterdam mean time.
    +
    +# The data before 1945 are taken from
    +# .
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Neth	1916	only	-	May	 1	0:00	1:00	NST	# Netherlands Summer Time
    +Rule	Neth	1916	only	-	Oct	 1	0:00	0	AMT	# Amsterdam Mean Time
    +Rule	Neth	1917	only	-	Apr	16	2:00s	1:00	NST
    +Rule	Neth	1917	only	-	Sep	17	2:00s	0	AMT
    +Rule	Neth	1918	1921	-	Apr	Mon>=1	2:00s	1:00	NST
    +Rule	Neth	1918	1921	-	Sep	lastMon	2:00s	0	AMT
    +Rule	Neth	1922	only	-	Mar	lastSun	2:00s	1:00	NST
    +Rule	Neth	1922	1936	-	Oct	Sun>=2	2:00s	0	AMT
    +Rule	Neth	1923	only	-	Jun	Fri>=1	2:00s	1:00	NST
    +Rule	Neth	1924	only	-	Mar	lastSun	2:00s	1:00	NST
    +Rule	Neth	1925	only	-	Jun	Fri>=1	2:00s	1:00	NST
    +# From 1926 through 1939 DST began 05-15, except that it was delayed by a week
    +# in years when 05-15 fell in the Pentecost weekend.
    +Rule	Neth	1926	1931	-	May	15	2:00s	1:00	NST
    +Rule	Neth	1932	only	-	May	22	2:00s	1:00	NST
    +Rule	Neth	1933	1936	-	May	15	2:00s	1:00	NST
    +Rule	Neth	1937	only	-	May	22	2:00s	1:00	NST
    +Rule	Neth	1937	only	-	Jul	 1	0:00	1:00	S
    +Rule	Neth	1937	1939	-	Oct	Sun>=2	2:00s	0	-
    +Rule	Neth	1938	1939	-	May	15	2:00s	1:00	S
    +Rule	Neth	1945	only	-	Apr	 2	2:00s	1:00	S
    +Rule	Neth	1945	only	-	Sep	16	2:00s	0	-
    +#
    +# Amsterdam Mean Time was +00:19:32.13 exactly, but the .13 is omitted
    +# below because the current format requires GMTOFF to be an integer.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Europe/Amsterdam	0:19:32 -	LMT	1835
    +			0:19:32	Neth	%s	1937 Jul  1
    +			0:20	Neth	NE%sT	1940 May 16 0:00 # Dutch Time
    +			1:00	C-Eur	CE%sT	1945 Apr  2 2:00
    +			1:00	Neth	CE%sT	1977
    +			1:00	EU	CE%sT
    +
    +# Norway
    +# http://met.no/met/met_lex/q_u/sommertid.html (2004-01) agrees with Shanks &
    +# Pottenger.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Norway	1916	only	-	May	22	1:00	1:00	S
    +Rule	Norway	1916	only	-	Sep	30	0:00	0	-
    +Rule	Norway	1945	only	-	Apr	 2	2:00s	1:00	S
    +Rule	Norway	1945	only	-	Oct	 1	2:00s	0	-
    +Rule	Norway	1959	1964	-	Mar	Sun>=15	2:00s	1:00	S
    +Rule	Norway	1959	1965	-	Sep	Sun>=15	2:00s	0	-
    +Rule	Norway	1965	only	-	Apr	25	2:00s	1:00	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Oslo	0:43:00 -	LMT	1895 Jan  1
    +			1:00	Norway	CE%sT	1940 Aug 10 23:00
    +			1:00	C-Eur	CE%sT	1945 Apr  2  2:00
    +			1:00	Norway	CE%sT	1980
    +			1:00	EU	CE%sT
    +
    +# Svalbard & Jan Mayen
    +
    +# From Steffen Thorsen (2001-05-01):
    +# Although I could not find it explicitly, it seems that Jan Mayen and
    +# Svalbard have been using the same time as Norway at least since the
    +# time they were declared as parts of Norway.  Svalbard was declared
    +# as a part of Norway by law of 1925-07-17 no 11, section 4 and Jan
    +# Mayen by law of 1930-02-27 no 2, section 2. (From
    +# http://www.lovdata.no/all/nl-19250717-011.html and
    +# http://www.lovdata.no/all/nl-19300227-002.html).  The law/regulation
    +# for normal/standard time in Norway is from 1894-06-29 no 1 (came
    +# into operation on 1895-01-01) and Svalbard/Jan Mayen seem to be a
    +# part of this law since 1925/1930. (From
    +# http://www.lovdata.no/all/nl-18940629-001.html ) I have not been
    +# able to find if Jan Mayen used a different time zone (e.g. -0100)
    +# before 1930. Jan Mayen has only been "inhabitated" since 1921 by
    +# Norwegian meteorologists and maybe used the same time as Norway ever
    +# since 1921.  Svalbard (Arctic/Longyearbyen) has been inhabited since
    +# before 1895, and therefore probably changed the local time somewhere
    +# between 1895 and 1925 (inclusive).
    +
    +# From Paul Eggert (2001-05-01):
    +#
    +# Actually, Jan Mayen was never occupied by Germany during World War II,
    +# so it must have diverged from Oslo time during the war, as Oslo was
    +# keeping Berlin time.
    +#
    +#  says that the meteorologists
    +# burned down their station in 1940 and left the island, but returned in
    +# 1941 with a small Norwegian garrison and continued operations despite
    +# frequent air ttacks from Germans.  In 1943 the Americans established a
    +# radiolocating station on the island, called "Atlantic City".  Possibly
    +# the UTC offset changed during the war, but I think it unlikely that
    +# Jan Mayen used German daylight-saving rules.
    +#
    +# Svalbard is more complicated, as it was raided in August 1941 by an
    +# Allied party that evacuated the civilian population to England (says
    +# ).  The Svalbard FAQ
    +#  says that the Germans were
    +# expelled on 1942-05-14.  However, small parties of Germans did return,
    +# and according to Wilhelm Dege's book "War North of 80" (1954)
    +# 
    +# the German armed forces at the Svalbard weather station code-named
    +# Haudegen did not surrender to the Allies until September 1945.
    +#
    +# All these events predate our cutoff date of 1970.  Unless we can
    +# come up with more definitive info about the timekeeping during the
    +# war years it's probably best just do...the following for now:
    +Link	Europe/Oslo	Arctic/Longyearbyen
    +
    +# Poland
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Poland	1918	1919	-	Sep	16	2:00s	0	-
    +Rule	Poland	1919	only	-	Apr	15	2:00s	1:00	S
    +Rule	Poland	1944	only	-	Apr	 3	2:00s	1:00	S
    +# Whitman gives 1944 Nov 30; go with Shanks & Pottenger.
    +Rule	Poland	1944	only	-	Oct	 4	2:00	0	-
    +# For 1944-1948 Whitman gives the previous day; go with Shanks & Pottenger.
    +Rule	Poland	1945	only	-	Apr	29	0:00	1:00	S
    +Rule	Poland	1945	only	-	Nov	 1	0:00	0	-
    +# For 1946 on the source is Kazimierz Borkowski,
    +# Torun Center for Astronomy, Dept. of Radio Astronomy, Nicolaus Copernicus U.,
    +# 
    +# Thanks to Przemyslaw Augustyniak (2005-05-28) for this reference.
    +# He also gives these further references:
    +# Mon Pol nr 13, poz 162 (1995) 
    +# Druk nr 2180 (2003) 
    +Rule	Poland	1946	only	-	Apr	14	0:00s	1:00	S
    +Rule	Poland	1946	only	-	Oct	 7	2:00s	0	-
    +Rule	Poland	1947	only	-	May	 4	2:00s	1:00	S
    +Rule	Poland	1947	1949	-	Oct	Sun>=1	2:00s	0	-
    +Rule	Poland	1948	only	-	Apr	18	2:00s	1:00	S
    +Rule	Poland	1949	only	-	Apr	10	2:00s	1:00	S
    +Rule	Poland	1957	only	-	Jun	 2	1:00s	1:00	S
    +Rule	Poland	1957	1958	-	Sep	lastSun	1:00s	0	-
    +Rule	Poland	1958	only	-	Mar	30	1:00s	1:00	S
    +Rule	Poland	1959	only	-	May	31	1:00s	1:00	S
    +Rule	Poland	1959	1961	-	Oct	Sun>=1	1:00s	0	-
    +Rule	Poland	1960	only	-	Apr	 3	1:00s	1:00	S
    +Rule	Poland	1961	1964	-	May	lastSun	1:00s	1:00	S
    +Rule	Poland	1962	1964	-	Sep	lastSun	1:00s	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Warsaw	1:24:00 -	LMT	1880
    +			1:24:00	-	WMT	1915 Aug  5   # Warsaw Mean Time
    +			1:00	C-Eur	CE%sT	1918 Sep 16 3:00
    +			2:00	Poland	EE%sT	1922 Jun
    +			1:00	Poland	CE%sT	1940 Jun 23 2:00
    +			1:00	C-Eur	CE%sT	1944 Oct
    +			1:00	Poland	CE%sT	1977
    +			1:00	W-Eur	CE%sT	1988
    +			1:00	EU	CE%sT
    +
    +# Portugal
    +#
    +# From Rui Pedro Salgueiro (1992-11-12):
    +# Portugal has recently (September, 27) changed timezone
    +# (from WET to MET or CET) to harmonize with EEC.
    +#
    +# Martin Bruckmann (1996-02-29) reports via Peter Ilieve
    +# that Portugal is reverting to 0:00 by not moving its clocks this spring.
    +# The new Prime Minister was fed up with getting up in the dark in the winter.
    +#
    +# From Paul Eggert (1996-11-12):
    +# IATA SSIM (1991-09) reports several 1991-09 and 1992-09 transitions
    +# at 02:00u, not 01:00u.  Assume that these are typos.
    +# IATA SSIM (1991/1992) reports that the Azores were at -1:00.
    +# IATA SSIM (1993-02) says +0:00; later issues (through 1996-09) say -1:00.
    +# Guess that the Azores changed to EU rules in 1992 (since that's when Portugal
    +# harmonized with the EU), and that they stayed +0:00 that winter.
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +# DSH writes that despite Decree 1,469 (1915), the change to the clocks was not
    +# done every year, depending on what Spain did, because of railroad schedules.
    +# Go with Shanks & Pottenger.
    +Rule	Port	1916	only	-	Jun	17	23:00	1:00	S
    +# Whitman gives 1916 Oct 31; go with Shanks & Pottenger.
    +Rule	Port	1916	only	-	Nov	 1	 1:00	0	-
    +Rule	Port	1917	only	-	Feb	28	23:00s	1:00	S
    +Rule	Port	1917	1921	-	Oct	14	23:00s	0	-
    +Rule	Port	1918	only	-	Mar	 1	23:00s	1:00	S
    +Rule	Port	1919	only	-	Feb	28	23:00s	1:00	S
    +Rule	Port	1920	only	-	Feb	29	23:00s	1:00	S
    +Rule	Port	1921	only	-	Feb	28	23:00s	1:00	S
    +Rule	Port	1924	only	-	Apr	16	23:00s	1:00	S
    +Rule	Port	1924	only	-	Oct	14	23:00s	0	-
    +Rule	Port	1926	only	-	Apr	17	23:00s	1:00	S
    +Rule	Port	1926	1929	-	Oct	Sat>=1	23:00s	0	-
    +Rule	Port	1927	only	-	Apr	 9	23:00s	1:00	S
    +Rule	Port	1928	only	-	Apr	14	23:00s	1:00	S
    +Rule	Port	1929	only	-	Apr	20	23:00s	1:00	S
    +Rule	Port	1931	only	-	Apr	18	23:00s	1:00	S
    +# Whitman gives 1931 Oct 8; go with Shanks & Pottenger.
    +Rule	Port	1931	1932	-	Oct	Sat>=1	23:00s	0	-
    +Rule	Port	1932	only	-	Apr	 2	23:00s	1:00	S
    +Rule	Port	1934	only	-	Apr	 7	23:00s	1:00	S
    +# Whitman gives 1934 Oct 5; go with Shanks & Pottenger.
    +Rule	Port	1934	1938	-	Oct	Sat>=1	23:00s	0	-
    +# Shanks & Pottenger give 1935 Apr 30; go with Whitman.
    +Rule	Port	1935	only	-	Mar	30	23:00s	1:00	S
    +Rule	Port	1936	only	-	Apr	18	23:00s	1:00	S
    +# Whitman gives 1937 Apr 2; go with Shanks & Pottenger.
    +Rule	Port	1937	only	-	Apr	 3	23:00s	1:00	S
    +Rule	Port	1938	only	-	Mar	26	23:00s	1:00	S
    +Rule	Port	1939	only	-	Apr	15	23:00s	1:00	S
    +# Whitman gives 1939 Oct 7; go with Shanks & Pottenger.
    +Rule	Port	1939	only	-	Nov	18	23:00s	0	-
    +Rule	Port	1940	only	-	Feb	24	23:00s	1:00	S
    +# Shanks & Pottenger give 1940 Oct 7; go with Whitman.
    +Rule	Port	1940	1941	-	Oct	 5	23:00s	0	-
    +Rule	Port	1941	only	-	Apr	 5	23:00s	1:00	S
    +Rule	Port	1942	1945	-	Mar	Sat>=8	23:00s	1:00	S
    +Rule	Port	1942	only	-	Apr	25	22:00s	2:00	M # Midsummer
    +Rule	Port	1942	only	-	Aug	15	22:00s	1:00	S
    +Rule	Port	1942	1945	-	Oct	Sat>=24	23:00s	0	-
    +Rule	Port	1943	only	-	Apr	17	22:00s	2:00	M
    +Rule	Port	1943	1945	-	Aug	Sat>=25	22:00s	1:00	S
    +Rule	Port	1944	1945	-	Apr	Sat>=21	22:00s	2:00	M
    +Rule	Port	1946	only	-	Apr	Sat>=1	23:00s	1:00	S
    +Rule	Port	1946	only	-	Oct	Sat>=1	23:00s	0	-
    +Rule	Port	1947	1949	-	Apr	Sun>=1	 2:00s	1:00	S
    +Rule	Port	1947	1949	-	Oct	Sun>=1	 2:00s	0	-
    +# Shanks & Pottenger say DST was observed in 1950; go with Whitman.
    +# Whitman gives Oct lastSun for 1952 on; go with Shanks & Pottenger.
    +Rule	Port	1951	1965	-	Apr	Sun>=1	 2:00s	1:00	S
    +Rule	Port	1951	1965	-	Oct	Sun>=1	 2:00s	0	-
    +Rule	Port	1977	only	-	Mar	27	 0:00s	1:00	S
    +Rule	Port	1977	only	-	Sep	25	 0:00s	0	-
    +Rule	Port	1978	1979	-	Apr	Sun>=1	 0:00s	1:00	S
    +Rule	Port	1978	only	-	Oct	 1	 0:00s	0	-
    +Rule	Port	1979	1982	-	Sep	lastSun	 1:00s	0	-
    +Rule	Port	1980	only	-	Mar	lastSun	 0:00s	1:00	S
    +Rule	Port	1981	1982	-	Mar	lastSun	 1:00s	1:00	S
    +Rule	Port	1983	only	-	Mar	lastSun	 2:00s	1:00	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +# Shanks & Pottenger say the transition from LMT to WET occurred 1911-05-24;
    +# Willett says 1912-01-01.  Go with Willett.
    +Zone	Europe/Lisbon	-0:36:32 -	LMT	1884
    +			-0:36:32 -	LMT	1912 Jan  1  # Lisbon Mean Time
    +			 0:00	Port	WE%sT	1966 Apr  3 2:00
    +			 1:00	-	CET	1976 Sep 26 1:00
    +			 0:00	Port	WE%sT	1983 Sep 25 1:00s
    +			 0:00	W-Eur	WE%sT	1992 Sep 27 1:00s
    +			 1:00	EU	CE%sT	1996 Mar 31 1:00u
    +			 0:00	EU	WE%sT
    +Zone Atlantic/Azores	-1:42:40 -	LMT	1884		# Ponta Delgada
    +			-1:54:32 -	HMT	1911 May 24  # Horta Mean Time
    +			-2:00	Port	AZO%sT	1966 Apr  3 2:00 # Azores Time
    +			-1:00	Port	AZO%sT	1983 Sep 25 1:00s
    +			-1:00	W-Eur	AZO%sT	1992 Sep 27 1:00s
    +			 0:00	EU	WE%sT	1993 Mar 28 1:00u
    +			-1:00	EU	AZO%sT
    +Zone Atlantic/Madeira	-1:07:36 -	LMT	1884		# Funchal
    +			-1:07:36 -	FMT	1911 May 24  # Funchal Mean Time
    +			-1:00	Port	MAD%sT	1966 Apr  3 2:00 # Madeira Time
    +			 0:00	Port	WE%sT	1983 Sep 25 1:00s
    +			 0:00	EU	WE%sT
    +
    +# Romania
    +#
    +# From Paul Eggert (1999-10-07):
    +# 
    +# Nine O'clock (1998-10-23) reports that the switch occurred at
    +# 04:00 local time in fall 1998.  For lack of better info,
    +# assume that Romania and Moldova switched to EU rules in 1997,
    +# the same year as Bulgaria.
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Romania	1932	only	-	May	21	 0:00s	1:00	S
    +Rule	Romania	1932	1939	-	Oct	Sun>=1	 0:00s	0	-
    +Rule	Romania	1933	1939	-	Apr	Sun>=2	 0:00s	1:00	S
    +Rule	Romania	1979	only	-	May	27	 0:00	1:00	S
    +Rule	Romania	1979	only	-	Sep	lastSun	 0:00	0	-
    +Rule	Romania	1980	only	-	Apr	 5	23:00	1:00	S
    +Rule	Romania	1980	only	-	Sep	lastSun	 1:00	0	-
    +Rule	Romania	1991	1993	-	Mar	lastSun	 0:00s	1:00	S
    +Rule	Romania	1991	1993	-	Sep	lastSun	 0:00s	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Europe/Bucharest	1:44:24 -	LMT	1891 Oct
    +			1:44:24	-	BMT	1931 Jul 24	# Bucharest MT
    +			2:00	Romania	EE%sT	1981 Mar 29 2:00s
    +			2:00	C-Eur	EE%sT	1991
    +			2:00	Romania	EE%sT	1994
    +			2:00	E-Eur	EE%sT	1997
    +			2:00	EU	EE%sT
    +
    +# Russia
    +
    +# From Paul Eggert (2006-03-22):
    +# Except for Moscow after 1919-07-01, I invented the time zone abbreviations.
    +# Moscow time zone abbreviations after 1919-07-01, and Moscow rules after 1991,
    +# are from Andrey A. Chernov.  The rest is from Shanks & Pottenger,
    +# except we follow Chernov's report that 1992 DST transitions were Sat
    +# 23:00, not Sun 02:00s.
    +#
    +# From Stanislaw A. Kuzikowski (1994-06-29):
    +# But now it is some months since Novosibirsk is 3 hours ahead of Moscow!
    +# I do not know why they have decided to make this change;
    +# as far as I remember it was done exactly during winter->summer switching
    +# so we (Novosibirsk) simply did not switch.
    +#
    +# From Andrey A. Chernov (1996-10-04):
    +# `MSK' and `MSD' were born and used initially on Moscow computers with
    +# UNIX-like OSes by several developer groups (e.g. Demos group, Kiae group)....
    +# The next step was the UUCP network, the Relcom predecessor
    +# (used mainly for mail), and MSK/MSD was actively used there.
    +#
    +# From Chris Carrier (1996-10-30):
    +# According to a friend of mine who rode the Trans-Siberian Railroad from
    +# Moscow to Irkutsk in 1995, public air and rail transport in Russia ...
    +# still follows Moscow time, no matter where in Russia it is located.
    +#
    +# For Grozny, Chechnya, we have the following story from
    +# John Daniszewski, "Scavengers in the Rubble", Los Angeles Times (2001-02-07):
    +# News--often false--is spread by word of mouth.  A rumor that it was
    +# time to move the clocks back put this whole city out of sync with
    +# the rest of Russia for two weeks--even soldiers stationed here began
    +# enforcing curfew at the wrong time.
    +#
    +# From Gwillim Law (2001-06-05):
    +# There's considerable evidence that Sakhalin Island used to be in
    +# UTC+11, and has changed to UTC+10, in this decade.  I start with the
    +# SSIM, which listed Yuzhno-Sakhalinsk in zone RU10 along with Magadan
    +# until February 1997, and then in RU9 with Khabarovsk and Vladivostok
    +# since September 1997....  Although the Kuril Islands are
    +# administratively part of Sakhalin oblast', they appear to have
    +# remained on UTC+11 along with Magadan.
    +#
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +#
    +# Kaliningradskaya oblast'.
    +Zone Europe/Kaliningrad	 1:22:00 -	LMT	1893 Apr
    +			 1:00	C-Eur	CE%sT	1945
    +			 2:00	Poland	CE%sT	1946
    +			 3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
    +			 2:00	Russia	EE%sT	2011 Mar 27 2:00s
    +			 3:00	-	FET # Further-eastern European Time
    +#
    +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    +# Respublika Adygeya, Arkhangel'skaya oblast',
    +# Belgorodskaya oblast', Bryanskaya oblast', Vladimirskaya oblast',
    +# Vologodskaya oblast', Voronezhskaya oblast',
    +# Respublika Dagestan, Ivanovskaya oblast', Respublika Ingushetiya,
    +# Kabarbino-Balkarskaya Respublika, Respublika Kalmykiya,
    +# Kalyzhskaya oblast', Respublika Karachaevo-Cherkessiya,
    +# Respublika Kareliya, Respublika Komi,
    +# Kostromskaya oblast', Krasnodarskij kraj, Kurskaya oblast',
    +# Leningradskaya oblast', Lipetskaya oblast', Respublika Marij El,
    +# Respublika Mordoviya, Moskva, Moskovskaya oblast',
    +# Murmanskaya oblast', Nenetskij avtonomnyj okrug,
    +# Nizhegorodskaya oblast', Novgorodskaya oblast', Orlovskaya oblast',
    +# Penzenskaya oblast', Pskovskaya oblast', Rostovskaya oblast',
    +# Ryazanskaya oblast', Sankt-Peterburg,
    +# Respublika Severnaya Osetiya, Smolenskaya oblast',
    +# Stavropol'skij kraj, Tambovskaya oblast', Respublika Tatarstan,
    +# Tverskaya oblast', Tyl'skaya oblast', Ul'yanovskaya oblast',
    +# Chechenskaya Respublika, Chuvashskaya oblast',
    +# Yaroslavskaya oblast'
    +Zone Europe/Moscow	 2:30:20 -	LMT	1880
    +			 2:30	-	MMT	1916 Jul  3 # Moscow Mean Time
    +			 2:30:48 Russia	%s	1919 Jul  1 2:00
    +			 3:00	Russia	MSK/MSD	1922 Oct
    +			 2:00	-	EET	1930 Jun 21
    +			 3:00	Russia	MSK/MSD	1991 Mar 31 2:00s
    +			 2:00	Russia	EE%sT	1992 Jan 19 2:00s
    +			 3:00	Russia	MSK/MSD	2011 Mar 27 2:00s
    +			 4:00	-	MSK
    +#
    +# Astrakhanskaya oblast', Kirovskaya oblast', Saratovskaya oblast',
    +# Volgogradskaya oblast'.  Shanks & Pottenger say Kirov is still at +0400
    +# but Wikipedia (2006-05-09) says +0300.  Perhaps it switched after the
    +# others?  But we have no data.
    +Zone Europe/Volgograd	 2:57:40 -	LMT	1920 Jan  3
    +			 3:00	-	TSAT	1925 Apr  6 # Tsaritsyn Time
    +			 3:00	-	STAT	1930 Jun 21 # Stalingrad Time
    +			 4:00	-	STAT	1961 Nov 11
    +			 4:00	Russia	VOL%sT	1989 Mar 26 2:00s # Volgograd T
    +			 3:00	Russia	VOL%sT	1991 Mar 31 2:00s
    +			 4:00	-	VOLT	1992 Mar 29 2:00s
    +			 3:00	Russia	VOL%sT	2011 Mar 27 2:00s
    +			 4:00	-	VOLT
    +#
    +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    +# Samarskaya oblast', Udmyrtskaya respublika
    +Zone Europe/Samara	 3:20:36 -	LMT	1919 Jul  1 2:00
    +			 3:00	-	SAMT	1930 Jun 21
    +			 4:00	-	SAMT	1935 Jan 27
    +			 4:00	Russia	KUY%sT	1989 Mar 26 2:00s # Kuybyshev
    +			 3:00	Russia	KUY%sT	1991 Mar 31 2:00s
    +			 2:00	Russia	KUY%sT	1991 Sep 29 2:00s
    +			 3:00	-	KUYT	1991 Oct 20 3:00
    +			 4:00	Russia	SAM%sT	2010 Mar 28 2:00s # Samara Time
    +			 3:00	Russia	SAM%sT	2011 Mar 27 2:00s
    +			 4:00	-	SAMT
    +
    +#
    +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    +# Respublika Bashkortostan, Komi-Permyatskij avtonomnyj okrug,
    +# Kurganskaya oblast', Orenburgskaya oblast', Permskaya oblast',
    +# Sverdlovskaya oblast', Tyumenskaya oblast',
    +# Khanty-Manskijskij avtonomnyj okrug, Chelyabinskaya oblast',
    +# Yamalo-Nenetskij avtonomnyj okrug.
    +Zone Asia/Yekaterinburg	 4:02:24 -	LMT	1919 Jul 15 4:00
    +			 4:00	-	SVET	1930 Jun 21 # Sverdlovsk Time
    +			 5:00	Russia	SVE%sT	1991 Mar 31 2:00s
    +			 4:00	Russia	SVE%sT	1992 Jan 19 2:00s
    +			 5:00	Russia	YEK%sT	2011 Mar 27 2:00s
    +			 6:00	-	YEKT	# Yekaterinburg Time
    +#
    +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    +# Respublika Altaj, Altajskij kraj, Omskaya oblast'.
    +Zone Asia/Omsk		 4:53:36 -	LMT	1919 Nov 14
    +			 5:00	-	OMST	1930 Jun 21 # Omsk TIme
    +			 6:00	Russia	OMS%sT	1991 Mar 31 2:00s
    +			 5:00	Russia	OMS%sT	1992 Jan 19 2:00s
    +			 6:00	Russia	OMS%sT	2011 Mar 27 2:00s
    +			 7:00	-	OMST
    +#
    +# From Paul Eggert (2006-08-19): I'm guessing about Tomsk here; it's
    +# not clear when it switched from +7 to +6.
    +# Novosibirskaya oblast', Tomskaya oblast'.
    +Zone Asia/Novosibirsk	 5:31:40 -	LMT	1919 Dec 14 6:00
    +			 6:00	-	NOVT	1930 Jun 21 # Novosibirsk Time
    +			 7:00	Russia	NOV%sT	1991 Mar 31 2:00s
    +			 6:00	Russia	NOV%sT	1992 Jan 19 2:00s
    +			 7:00	Russia	NOV%sT	1993 May 23 # say Shanks & P.
    +			 6:00	Russia	NOV%sT	2011 Mar 27 2:00s
    +			 7:00	-	NOVT
    +
    +# From Alexander Krivenyshev (2009-10-13):
    +# Kemerovo oblast' (Kemerovo region) in Russia will change current time zone on
    +# March 28, 2010:
    +# from current Russia Zone 6 - Krasnoyarsk Time Zone (KRA) UTC +0700
    +# to Russia Zone 5 - Novosibirsk Time Zone (NOV) UTC +0600
    +#
    +# This is according to Government of Russia decree # 740, on September
    +# 14, 2009 "Application in the territory of the Kemerovo region the Fifth
    +# time zone." ("Russia Zone 5" or old "USSR Zone 5" is GMT +0600)
    +#
    +# Russian Government web site (Russian language)
    +# 
    +# http://www.government.ru/content/governmentactivity/rfgovernmentdecisions/archive/2009/09/14/991633.htm
    +# 
    +# or Russian-English translation by WorldTimeZone.com with reference
    +# map to local region and new Russia Time Zone map after March 28, 2010
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_russia03.html
    +# 
    +#
    +# Thus, when Russia will switch to DST on the night of March 28, 2010
    +# Kemerovo region (Kemerovo oblast') will not change the clock.
    +#
    +# As a result, Kemerovo oblast' will be in the same time zone as
    +# Novosibirsk, Omsk, Tomsk, Barnaul and Altai Republic.
    +
    +Zone Asia/Novokuznetsk	 5:48:48 -	NMT	1920 Jan  6
    +			 6:00	-	KRAT	1930 Jun 21 # Krasnoyarsk Time
    +			 7:00	Russia	KRA%sT	1991 Mar 31 2:00s
    +			 6:00	Russia	KRA%sT	1992 Jan 19 2:00s
    +			 7:00	Russia	KRA%sT	2010 Mar 28 2:00s
    +			 6:00	Russia	NOV%sT	2011 Mar 27 2:00s
    +			 7:00	-	NOVT # Novosibirsk/Novokuznetsk Time
    +
    +#
    +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    +# Krasnoyarskij kraj,
    +# Tajmyrskij (Dolgano-Nenetskij) avtonomnyj okrug,
    +# Respublika Tuva, Respublika Khakasiya, Evenkijskij avtonomnyj okrug.
    +Zone Asia/Krasnoyarsk	 6:11:20 -	LMT	1920 Jan  6
    +			 6:00	-	KRAT	1930 Jun 21 # Krasnoyarsk Time
    +			 7:00	Russia	KRA%sT	1991 Mar 31 2:00s
    +			 6:00	Russia	KRA%sT	1992 Jan 19 2:00s
    +			 7:00	Russia	KRA%sT	2011 Mar 27 2:00s
    +			 8:00	-	KRAT
    +#
    +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    +# Respublika Buryatiya, Irkutskaya oblast',
    +# Ust'-Ordynskij Buryatskij avtonomnyj okrug.
    +Zone Asia/Irkutsk	 6:57:20 -	LMT	1880
    +			 6:57:20 -	IMT	1920 Jan 25 # Irkutsk Mean Time
    +			 7:00	-	IRKT	1930 Jun 21 # Irkutsk Time
    +			 8:00	Russia	IRK%sT	1991 Mar 31 2:00s
    +			 7:00	Russia	IRK%sT	1992 Jan 19 2:00s
    +			 8:00	Russia	IRK%sT	2011 Mar 27 2:00s
    +			 9:00	-	IRKT
    +#
    +# From Oscar van Vlijmen (2003-10-18): [This region consists of]
    +# Aginskij Buryatskij avtonomnyj okrug, Amurskaya oblast',
    +# [parts of] Respublika Sakha (Yakutiya), Chitinskaya oblast'.
    +
    +# From Oscar van Vlijmen (2009-11-29):
    +# ...some regions of [Russia] were merged with others since 2005...
    +# Some names were changed, no big deal, except for one instance: a new name.
    +# YAK/YAKST: UTC+9 Zabajkal'skij kraj.
    +
    +# From Oscar van Vlijmen (2009-11-29):
    +# The Sakha districts are: Aldanskij, Amginskij, Anabarskij,
    +# Verkhnevilyujskij, Vilyujskij, Gornyj,
    +# Zhiganskij, Kobyajskij, Lenskij, Megino-Kangalasskij, Mirninskij,
    +# Namskij, Nyurbinskij, Olenyokskij, Olyokminskij,
    +# Suntarskij, Tattinskij, Ust'-Aldanskij, Khangalasskij,
    +# Churapchinskij, Eveno-Bytantajskij Natsional'nij.
    +
    +Zone Asia/Yakutsk	 8:38:40 -	LMT	1919 Dec 15
    +			 8:00	-	YAKT	1930 Jun 21 # Yakutsk Time
    +			 9:00	Russia	YAK%sT	1991 Mar 31 2:00s
    +			 8:00	Russia	YAK%sT	1992 Jan 19 2:00s
    +			 9:00	Russia	YAK%sT	2011 Mar 27 2:00s
    +			 10:00	-	YAKT
    +#
    +# From Oscar van Vlijmen (2003-10-18): [This region consists of]
    +# Evrejskaya avtonomnaya oblast', Khabarovskij kraj, Primorskij kraj,
    +# [parts of] Respublika Sakha (Yakutiya).
    +
    +# From Oscar van Vlijmen (2009-11-29):
    +# The Sakha districts are: Bulunskij, Verkhoyanskij, Tomponskij, Ust'-Majskij,
    +# Ust'-Yanskij.
    +Zone Asia/Vladivostok	 8:47:44 -	LMT	1922 Nov 15
    +			 9:00	-	VLAT	1930 Jun 21 # Vladivostok Time
    +			10:00	Russia	VLA%sT	1991 Mar 31 2:00s
    +			 9:00	Russia	VLA%sST	1992 Jan 19 2:00s
    +			10:00	Russia	VLA%sT	2011 Mar 27 2:00s
    +			11:00	-	VLAT
    +#
    +# Sakhalinskaya oblast'.
    +# The Zone name should be Yuzhno-Sakhalinsk, but that's too long.
    +Zone Asia/Sakhalin	 9:30:48 -	LMT	1905 Aug 23
    +			 9:00	-	CJT	1938
    +			 9:00	-	JST	1945 Aug 25
    +			11:00	Russia	SAK%sT	1991 Mar 31 2:00s # Sakhalin T.
    +			10:00	Russia	SAK%sT	1992 Jan 19 2:00s
    +			11:00	Russia	SAK%sT	1997 Mar lastSun 2:00s
    +			10:00	Russia	SAK%sT	2011 Mar 27 2:00s
    +			11:00	-	SAKT
    +#
    +# From Oscar van Vlijmen (2003-10-18): [This region consists of]
    +# Magadanskaya oblast', Respublika Sakha (Yakutiya).
    +# Probably also: Kuril Islands.
    +
    +# From Oscar van Vlijmen (2009-11-29):
    +# The Sakha districts are: Abyjskij, Allaikhovskij, Verkhhhnekolymskij, Momskij,
    +# Nizhnekolymskij, Ojmyakonskij, Srednekolymskij.
    +Zone Asia/Magadan	10:03:12 -	LMT	1924 May  2
    +			10:00	-	MAGT	1930 Jun 21 # Magadan Time
    +			11:00	Russia	MAG%sT	1991 Mar 31 2:00s
    +			10:00	Russia	MAG%sT	1992 Jan 19 2:00s
    +			11:00	Russia	MAG%sT	2011 Mar 27 2:00s
    +			12:00	-	MAGT
    +#
    +# From Oscar van Vlijmen (2001-08-25): [This region consists of]
    +# Kamchatskaya oblast', Koryakskij avtonomnyj okrug.
    +#
    +# The Zone name should be Asia/Petropavlovsk-Kamchatski, but that's too long.
    +Zone Asia/Kamchatka	10:34:36 -	LMT	1922 Nov 10
    +			11:00	-	PETT	1930 Jun 21 # P-K Time
    +			12:00	Russia	PET%sT	1991 Mar 31 2:00s
    +			11:00	Russia	PET%sT	1992 Jan 19 2:00s
    +			12:00	Russia	PET%sT	2010 Mar 28 2:00s
    +			11:00	Russia	PET%sT	2011 Mar 27 2:00s
    +			12:00	-	PETT
    +#
    +# Chukotskij avtonomnyj okrug
    +Zone Asia/Anadyr	11:49:56 -	LMT	1924 May  2
    +			12:00	-	ANAT	1930 Jun 21 # Anadyr Time
    +			13:00	Russia	ANA%sT	1982 Apr  1 0:00s
    +			12:00	Russia	ANA%sT	1991 Mar 31 2:00s
    +			11:00	Russia	ANA%sT	1992 Jan 19 2:00s
    +			12:00	Russia	ANA%sT	2010 Mar 28 2:00s
    +			11:00	Russia	ANA%sT	2011 Mar 27 2:00s
    +			12:00	-	ANAT
    +
    +# Serbia
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Belgrade	1:22:00	-	LMT	1884
    +			1:00	-	CET	1941 Apr 18 23:00
    +			1:00	C-Eur	CE%sT	1945
    +			1:00	-	CET	1945 May 8 2:00s
    +			1:00	1:00	CEST	1945 Sep 16  2:00s
    +# Metod Kozelj reports that the legal date of
    +# transition to EU rules was 1982-11-27, for all of Yugoslavia at the time.
    +# Shanks & Pottenger don't give as much detail, so go with Kozelj.
    +			1:00	-	CET	1982 Nov 27
    +			1:00	EU	CE%sT
    +Link Europe/Belgrade Europe/Ljubljana	# Slovenia
    +Link Europe/Belgrade Europe/Podgorica	# Montenegro
    +Link Europe/Belgrade Europe/Sarajevo	# Bosnia and Herzegovina
    +Link Europe/Belgrade Europe/Skopje	# Macedonia
    +Link Europe/Belgrade Europe/Zagreb	# Croatia
    +
    +# Slovakia
    +Link Europe/Prague Europe/Bratislava
    +
    +# Slovenia
    +# see Serbia
    +
    +# Spain
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +# For 1917-1919 Whitman gives Apr Sat>=1 - Oct Sat>=1;
    +# go with Shanks & Pottenger.
    +Rule	Spain	1917	only	-	May	 5	23:00s	1:00	S
    +Rule	Spain	1917	1919	-	Oct	 6	23:00s	0	-
    +Rule	Spain	1918	only	-	Apr	15	23:00s	1:00	S
    +Rule	Spain	1919	only	-	Apr	 5	23:00s	1:00	S
    +# Whitman gives 1921 Feb 28 - Oct 14; go with Shanks & Pottenger.
    +Rule	Spain	1924	only	-	Apr	16	23:00s	1:00	S
    +# Whitman gives 1924 Oct 14; go with Shanks & Pottenger.
    +Rule	Spain	1924	only	-	Oct	 4	23:00s	0	-
    +Rule	Spain	1926	only	-	Apr	17	23:00s	1:00	S
    +# Whitman says no DST in 1929; go with Shanks & Pottenger.
    +Rule	Spain	1926	1929	-	Oct	Sat>=1	23:00s	0	-
    +Rule	Spain	1927	only	-	Apr	 9	23:00s	1:00	S
    +Rule	Spain	1928	only	-	Apr	14	23:00s	1:00	S
    +Rule	Spain	1929	only	-	Apr	20	23:00s	1:00	S
    +# Whitman gives 1937 Jun 16, 1938 Apr 16, 1940 Apr 13;
    +# go with Shanks & Pottenger.
    +Rule	Spain	1937	only	-	May	22	23:00s	1:00	S
    +Rule	Spain	1937	1939	-	Oct	Sat>=1	23:00s	0	-
    +Rule	Spain	1938	only	-	Mar	22	23:00s	1:00	S
    +Rule	Spain	1939	only	-	Apr	15	23:00s	1:00	S
    +Rule	Spain	1940	only	-	Mar	16	23:00s	1:00	S
    +# Whitman says no DST 1942-1945; go with Shanks & Pottenger.
    +Rule	Spain	1942	only	-	May	 2	22:00s	2:00	M # Midsummer
    +Rule	Spain	1942	only	-	Sep	 1	22:00s	1:00	S
    +Rule	Spain	1943	1946	-	Apr	Sat>=13	22:00s	2:00	M
    +Rule	Spain	1943	only	-	Oct	 3	22:00s	1:00	S
    +Rule	Spain	1944	only	-	Oct	10	22:00s	1:00	S
    +Rule	Spain	1945	only	-	Sep	30	 1:00	1:00	S
    +Rule	Spain	1946	only	-	Sep	30	 0:00	0	-
    +Rule	Spain	1949	only	-	Apr	30	23:00	1:00	S
    +Rule	Spain	1949	only	-	Sep	30	 1:00	0	-
    +Rule	Spain	1974	1975	-	Apr	Sat>=13	23:00	1:00	S
    +Rule	Spain	1974	1975	-	Oct	Sun>=1	 1:00	0	-
    +Rule	Spain	1976	only	-	Mar	27	23:00	1:00	S
    +Rule	Spain	1976	1977	-	Sep	lastSun	 1:00	0	-
    +Rule	Spain	1977	1978	-	Apr	 2	23:00	1:00	S
    +Rule	Spain	1978	only	-	Oct	 1	 1:00	0	-
    +# The following rules are copied from Morocco from 1967 through 1978.
    +Rule SpainAfrica 1967	only	-	Jun	 3	12:00	1:00	S
    +Rule SpainAfrica 1967	only	-	Oct	 1	 0:00	0	-
    +Rule SpainAfrica 1974	only	-	Jun	24	 0:00	1:00	S
    +Rule SpainAfrica 1974	only	-	Sep	 1	 0:00	0	-
    +Rule SpainAfrica 1976	1977	-	May	 1	 0:00	1:00	S
    +Rule SpainAfrica 1976	only	-	Aug	 1	 0:00	0	-
    +Rule SpainAfrica 1977	only	-	Sep	28	 0:00	0	-
    +Rule SpainAfrica 1978	only	-	Jun	 1	 0:00	1:00	S
    +Rule SpainAfrica 1978	only	-	Aug	 4	 0:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Madrid	-0:14:44 -	LMT	1901 Jan  1  0:00s
    +			 0:00	Spain	WE%sT	1946 Sep 30
    +			 1:00	Spain	CE%sT	1979
    +			 1:00	EU	CE%sT
    +Zone	Africa/Ceuta	-0:21:16 -	LMT	1901
    +			 0:00	-	WET	1918 May  6 23:00
    +			 0:00	1:00	WEST	1918 Oct  7 23:00
    +			 0:00	-	WET	1924
    +			 0:00	Spain	WE%sT	1929
    +			 0:00 SpainAfrica WE%sT 1984 Mar 16
    +			 1:00	-	CET	1986
    +			 1:00	EU	CE%sT
    +Zone	Atlantic/Canary	-1:01:36 -	LMT	1922 Mar # Las Palmas de Gran C.
    +			-1:00	-	CANT	1946 Sep 30 1:00 # Canaries Time
    +			 0:00	-	WET	1980 Apr  6 0:00s
    +			 0:00	1:00	WEST	1980 Sep 28 0:00s
    +			 0:00	EU	WE%sT
    +# IATA SSIM (1996-09) says the Canaries switch at 2:00u, not 1:00u.
    +# Ignore this for now, as the Canaries are part of the EU.
    +
    +# Sweden
    +
    +# From Ivan Nilsson (2001-04-13), superseding Shanks & Pottenger:
    +#
    +# The law "Svensk forfattningssamling 1878, no 14" about standard time in 1879:
    +# From the beginning of 1879 (that is 01-01 00:00) the time for all
    +# places in the country is "the mean solar time for the meridian at
    +# three degrees, or twelve minutes of time, to the west of the
    +# meridian of the Observatory of Stockholm".  The law is dated 1878-05-31.
    +#
    +# The observatory at that time had the meridian 18 degrees 03' 30"
    +# eastern longitude = 01:12:14 in time.  Less 12 minutes gives the
    +# national standard time as 01:00:14 ahead of GMT....
    +#
    +# About the beginning of CET in Sweden. The lawtext ("Svensk
    +# forfattningssamling 1899, no 44") states, that "from the beginning
    +# of 1900... ... the same as the mean solar time for the meridian at
    +# the distance of one hour of time from the meridian of the English
    +# observatory at Greenwich, or at 12 minutes 14 seconds to the west
    +# from the meridian of the Observatory of Stockholm". The law is dated
    +# 1899-06-16.  In short: At 1900-01-01 00:00:00 the new standard time
    +# in Sweden is 01:00:00 ahead of GMT.
    +#
    +# 1916: The lawtext ("Svensk forfattningssamling 1916, no 124") states
    +# that "1916-05-15 is considered to begin one hour earlier". It is
    +# pretty obvious that at 05-14 23:00 the clocks are set to 05-15 00:00....
    +# Further the law says, that "1916-09-30 is considered to end one hour later".
    +#
    +# The laws regulating [DST] are available on the site of the Swedish
    +# Parliament beginning with 1985 - the laws regulating 1980/1984 are
    +# not available on the site (to my knowledge they are only available
    +# in Swedish):  (type
    +# "sommartid" without the quotes in the field "Fritext" and then click
    +# the Sok-button).
    +#
    +# (2001-05-13):
    +#
    +# I have now found a newspaper stating that at 1916-10-01 01:00
    +# summertime the church-clocks etc were set back one hour to show
    +# 1916-10-01 00:00 standard time.  The article also reports that some
    +# people thought the switch to standard time would take place already
    +# at 1916-10-01 00:00 summer time, but they had to wait for another
    +# hour before the event took place.
    +#
    +# Source: The newspaper "Dagens Nyheter", 1916-10-01, page 7 upper left.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Europe/Stockholm	1:12:12 -	LMT	1879 Jan  1
    +			1:00:14	-	SET	1900 Jan  1	# Swedish Time
    +			1:00	-	CET	1916 May 14 23:00
    +			1:00	1:00	CEST	1916 Oct  1 01:00
    +			1:00	-	CET	1980
    +			1:00	EU	CE%sT
    +
    +# Switzerland
    +# From Howse:
    +# By the end of the 18th century clocks and watches became commonplace
    +# and their performance improved enormously.  Communities began to keep
    +# mean time in preference to apparent time -- Geneva from 1780 ....
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +# From Whitman (who writes ``Midnight?''):
    +# Rule	Swiss	1940	only	-	Nov	 2	0:00	1:00	S
    +# Rule	Swiss	1940	only	-	Dec	31	0:00	0	-
    +# From Shanks & Pottenger:
    +# Rule	Swiss	1941	1942	-	May	Sun>=1	2:00	1:00	S
    +# Rule	Swiss	1941	1942	-	Oct	Sun>=1	0:00	0	-
    +
    +# From Alois Treindl (2008-12-17):
    +# I have researched the DST usage in Switzerland during the 1940ies.
    +#
    +# As I wrote in an earlier message, I suspected the current tzdata values
    +# to be wrong. This is now verified.
    +#
    +# I have found copies of the original ruling by the Swiss Federal
    +# government, in 'Eidgen[o]ssische Gesetzessammlung 1941 and 1942' (Swiss
    +# federal law collection)...
    +#
    +# DST began on Monday 5 May 1941, 1:00 am by shifting the clocks to 2:00 am
    +# DST ended on Monday 6 Oct 1941, 2:00 am by shifting the clocks to 1:00 am.
    +#
    +# DST began on Monday, 4 May 1942 at 01:00 am
    +# DST ended on Monday, 5 Oct 1942 at 02:00 am
    +#
    +# There was no DST in 1940, I have checked the law collection carefully.
    +# It is also indicated by the fact that the 1942 entry in the law
    +# collection points back to 1941 as a reference, but no reference to any
    +# other years are made.
    +#
    +# Newspaper articles I have read in the archives on 6 May 1941 reported
    +# about the introduction of DST (Sommerzeit in German) during the previous
    +# night as an absolute novelty, because this was the first time that such
    +# a thing had happened in Switzerland.
    +#
    +# I have also checked 1916, because one book source (Gabriel, Traite de
    +# l'heure dans le monde) claims that Switzerland had DST in 1916. This is
    +# false, no official document could be found. Probably Gabriel got misled
    +# by references to Germany, which introduced DST in 1916 for the first time.
    +#
    +# The tzdata rules for Switzerland must be changed to:
    +# Rule  Swiss   1941    1942    -       May     Mon>=1  1:00    1:00    S
    +# Rule  Swiss   1941    1942    -       Oct     Mon>=1  2:00    0       -
    +#
    +# The 1940 rules must be deleted.
    +#
    +# One further detail for Switzerland, which is probably out of scope for
    +# most users of tzdata:
    +# The zone file
    +# Zone    Europe/Zurich   0:34:08 -       LMT     1848 Sep 12
    +#                          0:29:44 -       BMT     1894 Jun #Bern Mean Time
    +#                          1:00    Swiss   CE%sT   1981
    +#                          1:00    EU      CE%sT
    +# describes all of Switzerland correctly, with the exception of
    +# the Cantone Geneve (Geneva, Genf). Between 1848 and 1894 Geneve did not
    +# follow Bern Mean Time but kept its own local mean time.
    +# To represent this, an extra zone would be needed.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Swiss	1941	1942	-	May	Mon>=1	1:00	1:00	S
    +Rule	Swiss	1941	1942	-	Oct	Mon>=1	2:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Zurich	0:34:08 -	LMT	1848 Sep 12
    +			0:29:44	-	BMT	1894 Jun # Bern Mean Time
    +			1:00	Swiss	CE%sT	1981
    +			1:00	EU	CE%sT
    +
    +# Turkey
    +
    +# From Amar Devegowda (2007-01-03):
    +# The time zone rules for Istanbul, Turkey have not been changed for years now.
    +# ... The latest rules are available at -
    +# http://www.timeanddate.com/worldclock/timezone.html?n=107
    +# From Steffen Thorsen (2007-01-03):
    +# I have been able to find press records back to 1996 which all say that
    +# DST started 01:00 local time and end at 02:00 local time.  I am not sure
    +# what happened before that.  One example for each year from 1996 to 2001:
    +# http://newspot.byegm.gov.tr/arsiv/1996/21/N4.htm
    +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING97/03/97X03X25.TXT
    +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING98/03/98X03X02.HTM
    +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING99/10/99X10X26.HTM#%2016
    +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2000/03/00X03X06.HTM#%2021
    +# http://www.byegm.gov.tr/YAYINLARIMIZ/CHR/ING2001/03/23x03x01.HTM#%2027
    +# From Paul Eggert (2007-01-03):
    +# Prefer the above source to Shanks & Pottenger for time stamps after 1990.
    +
    +# From Steffen Thorsen (2007-03-09):
    +# Starting 2007 though, it seems that they are adopting EU's 1:00 UTC
    +# start/end time, according to the following page (2007-03-07):
    +# http://www.ntvmsnbc.com/news/402029.asp
    +# The official document is located here - it is in Turkish...:
    +# http://rega.basbakanlik.gov.tr/eskiler/2007/03/20070307-7.htm
    +# I was able to locate the following seemingly official document
    +# (on a non-government server though) describing dates between 2002 and 2006:
    +# http://www.alomaliye.com/bkk_2002_3769.htm
    +
    +# From Gökdeniz Karadağ (2011-03-10):
    +#
    +# According to the articles linked below, Turkey will change into summer
    +# time zone (GMT+3) on March 28, 2011 at 3:00 a.m. instead of March 27.
    +# This change is due to a nationwide exam on 27th.
    +#
    +# 
    +# http://www.worldbulletin.net/?aType=haber&ArticleID=70872
    +# 
    +# Turkish:
    +# 
    +# http://www.hurriyet.com.tr/ekonomi/17230464.asp?gid=373
    +# 
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Turkey	1916	only	-	May	 1	0:00	1:00	S
    +Rule	Turkey	1916	only	-	Oct	 1	0:00	0	-
    +Rule	Turkey	1920	only	-	Mar	28	0:00	1:00	S
    +Rule	Turkey	1920	only	-	Oct	25	0:00	0	-
    +Rule	Turkey	1921	only	-	Apr	 3	0:00	1:00	S
    +Rule	Turkey	1921	only	-	Oct	 3	0:00	0	-
    +Rule	Turkey	1922	only	-	Mar	26	0:00	1:00	S
    +Rule	Turkey	1922	only	-	Oct	 8	0:00	0	-
    +# Whitman gives 1923 Apr 28 - Sep 16 and no DST in 1924-1925;
    +# go with Shanks & Pottenger.
    +Rule	Turkey	1924	only	-	May	13	0:00	1:00	S
    +Rule	Turkey	1924	1925	-	Oct	 1	0:00	0	-
    +Rule	Turkey	1925	only	-	May	 1	0:00	1:00	S
    +Rule	Turkey	1940	only	-	Jun	30	0:00	1:00	S
    +Rule	Turkey	1940	only	-	Oct	 5	0:00	0	-
    +Rule	Turkey	1940	only	-	Dec	 1	0:00	1:00	S
    +Rule	Turkey	1941	only	-	Sep	21	0:00	0	-
    +Rule	Turkey	1942	only	-	Apr	 1	0:00	1:00	S
    +# Whitman omits the next two transition and gives 1945 Oct 1;
    +# go with Shanks & Pottenger.
    +Rule	Turkey	1942	only	-	Nov	 1	0:00	0	-
    +Rule	Turkey	1945	only	-	Apr	 2	0:00	1:00	S
    +Rule	Turkey	1945	only	-	Oct	 8	0:00	0	-
    +Rule	Turkey	1946	only	-	Jun	 1	0:00	1:00	S
    +Rule	Turkey	1946	only	-	Oct	 1	0:00	0	-
    +Rule	Turkey	1947	1948	-	Apr	Sun>=16	0:00	1:00	S
    +Rule	Turkey	1947	1950	-	Oct	Sun>=2	0:00	0	-
    +Rule	Turkey	1949	only	-	Apr	10	0:00	1:00	S
    +Rule	Turkey	1950	only	-	Apr	19	0:00	1:00	S
    +Rule	Turkey	1951	only	-	Apr	22	0:00	1:00	S
    +Rule	Turkey	1951	only	-	Oct	 8	0:00	0	-
    +Rule	Turkey	1962	only	-	Jul	15	0:00	1:00	S
    +Rule	Turkey	1962	only	-	Oct	 8	0:00	0	-
    +Rule	Turkey	1964	only	-	May	15	0:00	1:00	S
    +Rule	Turkey	1964	only	-	Oct	 1	0:00	0	-
    +Rule	Turkey	1970	1972	-	May	Sun>=2	0:00	1:00	S
    +Rule	Turkey	1970	1972	-	Oct	Sun>=2	0:00	0	-
    +Rule	Turkey	1973	only	-	Jun	 3	1:00	1:00	S
    +Rule	Turkey	1973	only	-	Nov	 4	3:00	0	-
    +Rule	Turkey	1974	only	-	Mar	31	2:00	1:00	S
    +Rule	Turkey	1974	only	-	Nov	 3	5:00	0	-
    +Rule	Turkey	1975	only	-	Mar	30	0:00	1:00	S
    +Rule	Turkey	1975	1976	-	Oct	lastSun	0:00	0	-
    +Rule	Turkey	1976	only	-	Jun	 1	0:00	1:00	S
    +Rule	Turkey	1977	1978	-	Apr	Sun>=1	0:00	1:00	S
    +Rule	Turkey	1977	only	-	Oct	16	0:00	0	-
    +Rule	Turkey	1979	1980	-	Apr	Sun>=1	3:00	1:00	S
    +Rule	Turkey	1979	1982	-	Oct	Mon>=11	0:00	0	-
    +Rule	Turkey	1981	1982	-	Mar	lastSun	3:00	1:00	S
    +Rule	Turkey	1983	only	-	Jul	31	0:00	1:00	S
    +Rule	Turkey	1983	only	-	Oct	 2	0:00	0	-
    +Rule	Turkey	1985	only	-	Apr	20	0:00	1:00	S
    +Rule	Turkey	1985	only	-	Sep	28	0:00	0	-
    +Rule	Turkey	1986	1990	-	Mar	lastSun	2:00s	1:00	S
    +Rule	Turkey	1986	1990	-	Sep	lastSun	2:00s	0	-
    +Rule	Turkey	1991	2006	-	Mar	lastSun	1:00s	1:00	S
    +Rule	Turkey	1991	1995	-	Sep	lastSun	1:00s	0	-
    +Rule	Turkey	1996	2006	-	Oct	lastSun	1:00s	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	Europe/Istanbul	1:55:52 -	LMT	1880
    +			1:56:56	-	IMT	1910 Oct # Istanbul Mean Time?
    +			2:00	Turkey	EE%sT	1978 Oct 15
    +			3:00	Turkey	TR%sT	1985 Apr 20 # Turkey Time
    +			2:00	Turkey	EE%sT	2007
    +			2:00	EU	EE%sT	2011 Mar 27 1:00u
    +			2:00	-	EET	2011 Mar 28 1:00u
    +			2:00	EU	EE%sT
    +Link	Europe/Istanbul	Asia/Istanbul	# Istanbul is in both continents.
    +
    +# Ukraine
    +#
    +# From Igor Karpov, who works for the Ukranian Ministry of Justice,
    +# via Garrett Wollman (2003-01-27):
    +# BTW, I've found the official document on this matter. It's goverment
    +# regulations number 509, May 13, 1996. In my poor translation it says:
    +# "Time in Ukraine is set to second timezone (Kiev time). Each last Sunday
    +# of March at 3am the time is changing to 4am and each last Sunday of
    +# October the time at 4am is changing to 3am"
    +
    +# From Alexander Krivenyshev (2011-09-20):
    +# On September 20, 2011 the deputies of the Verkhovna Rada agreed to
    +# abolish the transfer clock to winter time.
    +#
    +# Bill number 8330 of MP from the Party of Regions Oleg Nadoshi got
    +# approval from 266 deputies.
    +#
    +# Ukraine abolishes transter back to the winter time (in Russian)
    +# 
    +# http://news.mail.ru/politics/6861560/
    +# 
    +#
    +# The Ukrainians will no longer change the clock (in Russian)
    +# 
    +# http://www.segodnya.ua/news/14290482.html
    +# 
    +#
    +# Deputies cancelled the winter time (in Russian)
    +# 
    +# http://www.pravda.com.ua/rus/news/2011/09/20/6600616/
    +# 
    +#
    +# From Philip Pizzey (2011-10-18):
    +# Today my Ukrainian colleagues have informed me that the
    +# Ukrainian parliament have decided that they will go to winter
    +# time this year after all.
    +#
    +# From Udo Schwedt (2011-10-18):
    +# As far as I understand, the recent change to the Ukranian time zone
    +# (Europe/Kiev) to introduce permanent daylight saving time (similar
    +# to Russia) was reverted today:
    +#
    +# 
    +# http://portal.rada.gov.ua/rada/control/en/publish/article/info_left?art_id=287324&cat_id=105995
    +# 
    +#
    +# Also reported by Alexander Bokovoy (2011-10-18) who also noted:
    +# The law documents themselves are at
    +#
    +# 
    +# http://w1.c1.rada.gov.ua/pls/zweb_n/webproc4_1?id=&pf3511=41484
    +# 
    +
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +# Most of Ukraine since 1970 has been like Kiev.
    +# "Kyiv" is the transliteration of the Ukrainian name, but
    +# "Kiev" is more common in English.
    +Zone Europe/Kiev	2:02:04 -	LMT	1880
    +			2:02:04	-	KMT	1924 May  2 # Kiev Mean Time
    +			2:00	-	EET	1930 Jun 21
    +			3:00	-	MSK	1941 Sep 20
    +			1:00	C-Eur	CE%sT	1943 Nov  6
    +			3:00	Russia	MSK/MSD	1990
    +			3:00	-	MSK	1990 Jul  1 2:00
    +			2:00	-	EET	1992
    +			2:00	E-Eur	EE%sT	1995
    +			2:00	EU	EE%sT
    +# Ruthenia used CET 1990/1991.
    +# "Uzhhorod" is the transliteration of the Ukrainian name, but
    +# "Uzhgorod" is more common in English.
    +Zone Europe/Uzhgorod	1:29:12 -	LMT	1890 Oct
    +			1:00	-	CET	1940
    +			1:00	C-Eur	CE%sT	1944 Oct
    +			1:00	1:00	CEST	1944 Oct 26
    +			1:00	-	CET	1945 Jun 29
    +			3:00	Russia	MSK/MSD	1990
    +			3:00	-	MSK	1990 Jul  1 2:00
    +			1:00	-	CET	1991 Mar 31 3:00
    +			2:00	-	EET	1992
    +			2:00	E-Eur	EE%sT	1995
    +			2:00	EU	EE%sT
    +# Zaporozh'ye and eastern Lugansk oblasts observed DST 1990/1991.
    +# "Zaporizhia" is the transliteration of the Ukrainian name, but
    +# "Zaporozh'ye" is more common in English.  Use the common English
    +# spelling, except omit the apostrophe as it is not allowed in
    +# portable Posix file names.
    +Zone Europe/Zaporozhye	2:20:40 -	LMT	1880
    +			2:20	-	CUT	1924 May  2 # Central Ukraine T
    +			2:00	-	EET	1930 Jun 21
    +			3:00	-	MSK	1941 Aug 25
    +			1:00	C-Eur	CE%sT	1943 Oct 25
    +			3:00	Russia	MSK/MSD	1991 Mar 31 2:00
    +			2:00	E-Eur	EE%sT	1995
    +			2:00	EU	EE%sT
    +# Central Crimea used Moscow time 1994/1997.
    +Zone Europe/Simferopol	2:16:24 -	LMT	1880
    +			2:16	-	SMT	1924 May  2 # Simferopol Mean T
    +			2:00	-	EET	1930 Jun 21
    +			3:00	-	MSK	1941 Nov
    +			1:00	C-Eur	CE%sT	1944 Apr 13
    +			3:00	Russia	MSK/MSD	1990
    +			3:00	-	MSK	1990 Jul  1 2:00
    +			2:00	-	EET	1992
    +# From Paul Eggert (2006-03-22):
    +# The _Economist_ (1994-05-28, p 45) reports that central Crimea switched
    +# from Kiev to Moscow time sometime after the January 1994 elections.
    +# Shanks (1999) says ``date of change uncertain'', but implies that it happened
    +# sometime between the 1994 DST switches.  Shanks & Pottenger simply say
    +# 1994-09-25 03:00, but that can't be right.  For now, guess it
    +# changed in May.
    +			2:00	E-Eur	EE%sT	1994 May
    +# From IATA SSIM (1994/1997), which also says that Kerch is still like Kiev.
    +			3:00	E-Eur	MSK/MSD	1996 Mar 31 3:00s
    +			3:00	1:00	MSD	1996 Oct 27 3:00s
    +# IATA SSIM (1997-09) says Crimea switched to EET/EEST.
    +# Assume it happened in March by not changing the clocks.
    +			3:00	Russia	MSK/MSD	1997
    +			3:00	-	MSK	1997 Mar lastSun 1:00u
    +			2:00	EU	EE%sT
    +
    +###############################################################################
    +
    +# One source shows that Bulgaria, Cyprus, Finland, and Greece observe DST from
    +# the last Sunday in March to the last Sunday in September in 1986.
    +# The source shows Romania changing a day later than everybody else.
    +#
    +# According to Bernard Sieloff's source, Poland is in the MET time zone but
    +# uses the WE DST rules.  The Western USSR uses EET+1 and ME DST rules.
    +# Bernard Sieloff's source claims Romania switches on the same day, but at
    +# 00:00 standard time (i.e., 01:00 DST).  It also claims that Turkey
    +# switches on the same day, but switches on at 01:00 standard time
    +# and off at 00:00 standard time (i.e., 01:00 DST)
    +
    +# ...
    +# Date: Wed, 28 Jan 87 16:56:27 -0100
    +# From: Tom Hofmann
    +# ...
    +#
    +# ...the European time rules are...standardized since 1981, when
    +# most European coun[tr]ies started DST.  Before that year, only
    +# a few countries (UK, France, Italy) had DST, each according
    +# to own national rules.  In 1981, however, DST started on
    +# 'Apr firstSun', and not on 'Mar lastSun' as in the following
    +# years...
    +# But also since 1981 there are some more national exceptions
    +# than listed in 'europe': Switzerland, for example, joined DST
    +# one year later, Denmark ended DST on 'Oct 1' instead of 'Sep
    +# lastSun' in 1981---I don't know how they handle now.
    +#
    +# Finally, DST ist always from 'Apr 1' to 'Oct 1' in the
    +# Soviet Union (as far as I know).
    +#
    +# Tom Hofmann, Scientific Computer Center, CIBA-GEIGY AG,
    +# 4002 Basle, Switzerland
    +# ...
    +
    +# ...
    +# Date: Wed, 4 Feb 87 22:35:22 +0100
    +# From: Dik T. Winter
    +# ...
    +#
    +# The information from Tom Hofmann is (as far as I know) not entirely correct.
    +# After a request from chongo at amdahl I tried to retrieve all information
    +# about DST in Europe.  I was able to find all from about 1969.
    +#
    +# ...standardization on DST in Europe started in about 1977 with switches on
    +# first Sunday in April and last Sunday in September...
    +# In 1981 UK joined Europe insofar that
    +# the starting day for both shifted to last Sunday in March.  And from 1982
    +# the whole of Europe used DST, with switch dates April 1 and October 1 in
    +# the Sov[i]et Union.  In 1985 the SU reverted to standard Europe[a]n switch
    +# dates...
    +#
    +# It should also be remembered that time-zones are not constants; e.g.
    +# Portugal switched in 1976 from MET (or CET) to WET with DST...
    +# Note also that though there were rules for switch dates not
    +# all countries abided to these dates, and many individual deviations
    +# occurred, though not since 1982 I believe.  Another note: it is always
    +# assumed that DST is 1 hour ahead of normal time, this need not be the
    +# case; at least in the Netherlands there have been times when DST was 2 hours
    +# in advance of normal time.
    +#
    +# ...
    +# dik t. winter, cwi, amsterdam, nederland
    +# ...
    +
    +# From Bob Devine (1988-01-28):
    +# ...
    +# Greece: Last Sunday in April to last Sunday in September (iffy on dates).
    +# Since 1978.  Change at midnight.
    +# ...
    +# Monaco: has same DST as France.
    +# ...
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/factory b/jdk/test/sun/util/calendar/zi/tzdata/factory
    new file mode 100644
    index 00000000000..53ca3aa5d31
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/factory
    @@ -0,0 +1,33 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# For companies who don't want to put time zone specification in
    +# their installation procedures.  When users run date, they'll get the message.
    +# Also useful for the "comp.sources" version.
    +
    +# Zone	NAME	GMTOFF	RULES	FORMAT
    +Zone	Factory	0	- "Local time zone must be set--see zic manual page"
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/gmt b/jdk/test/sun/util/calendar/zi/tzdata/gmt
    new file mode 100644
    index 00000000000..0be31797d7f
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/gmt
    @@ -0,0 +1,27 @@
    +#
    +# Copyright (c) 2000, 2005, 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#
    +# 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.
    +#
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	GMT		0:00	-	GMT
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/iso3166.tab b/jdk/test/sun/util/calendar/zi/tzdata/iso3166.tab
    new file mode 100644
    index 00000000000..fee3f33911a
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/iso3166.tab
    @@ -0,0 +1,299 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +# ISO 3166 alpha-2 country codes
    +#
    +# From Paul Eggert (2006-09-27):
    +#
    +# This file contains a table with the following columns:
    +# 1.  ISO 3166-1 alpha-2 country code, current as of
    +#     ISO 3166-1 Newsletter VI-1 (2007-09-21).  See:
    +#     
    +#     ISO 3166 Maintenance agency (ISO 3166/MA)
    +#     .
    +# 2.  The usual English name for the country,
    +#     chosen so that alphabetic sorting of subsets produces helpful lists.
    +#     This is not the same as the English name in the ISO 3166 tables.
    +#
    +# Columns are separated by a single tab.
    +# The table is sorted by country code.
    +#
    +# Lines beginning with `#' are comments.
    +#
    +# From Arthur David Olson (2011-08-17):
    +# Resynchronized today with the ISO 3166 site (adding SS for South Sudan).
    +#
    +#country-
    +#code	country name
    +AD	Andorra
    +AE	United Arab Emirates
    +AF	Afghanistan
    +AG	Antigua & Barbuda
    +AI	Anguilla
    +AL	Albania
    +AM	Armenia
    +AO	Angola
    +AQ	Antarctica
    +AR	Argentina
    +AS	Samoa (American)
    +AT	Austria
    +AU	Australia
    +AW	Aruba
    +AX	Aaland Islands
    +AZ	Azerbaijan
    +BA	Bosnia & Herzegovina
    +BB	Barbados
    +BD	Bangladesh
    +BE	Belgium
    +BF	Burkina Faso
    +BG	Bulgaria
    +BH	Bahrain
    +BI	Burundi
    +BJ	Benin
    +BL	St Barthelemy
    +BM	Bermuda
    +BN	Brunei
    +BO	Bolivia
    +BQ	Bonaire Sint Eustatius & Saba
    +BR	Brazil
    +BS	Bahamas
    +BT	Bhutan
    +BV	Bouvet Island
    +BW	Botswana
    +BY	Belarus
    +BZ	Belize
    +CA	Canada
    +CC	Cocos (Keeling) Islands
    +CD	Congo (Dem. Rep.)
    +CF	Central African Rep.
    +CG	Congo (Rep.)
    +CH	Switzerland
    +CI	Cote d'Ivoire
    +CK	Cook Islands
    +CL	Chile
    +CM	Cameroon
    +CN	China
    +CO	Colombia
    +CR	Costa Rica
    +CU	Cuba
    +CV	Cape Verde
    +CW	Curacao
    +CX	Christmas Island
    +CY	Cyprus
    +CZ	Czech Republic
    +DE	Germany
    +DJ	Djibouti
    +DK	Denmark
    +DM	Dominica
    +DO	Dominican Republic
    +DZ	Algeria
    +EC	Ecuador
    +EE	Estonia
    +EG	Egypt
    +EH	Western Sahara
    +ER	Eritrea
    +ES	Spain
    +ET	Ethiopia
    +FI	Finland
    +FJ	Fiji
    +FK	Falkland Islands
    +FM	Micronesia
    +FO	Faroe Islands
    +FR	France
    +GA	Gabon
    +GB	Britain (UK)
    +GD	Grenada
    +GE	Georgia
    +GF	French Guiana
    +GG	Guernsey
    +GH	Ghana
    +GI	Gibraltar
    +GL	Greenland
    +GM	Gambia
    +GN	Guinea
    +GP	Guadeloupe
    +GQ	Equatorial Guinea
    +GR	Greece
    +GS	South Georgia & the South Sandwich Islands
    +GT	Guatemala
    +GU	Guam
    +GW	Guinea-Bissau
    +GY	Guyana
    +HK	Hong Kong
    +HM	Heard Island & McDonald Islands
    +HN	Honduras
    +HR	Croatia
    +HT	Haiti
    +HU	Hungary
    +ID	Indonesia
    +IE	Ireland
    +IL	Israel
    +IM	Isle of Man
    +IN	India
    +IO	British Indian Ocean Territory
    +IQ	Iraq
    +IR	Iran
    +IS	Iceland
    +IT	Italy
    +JE	Jersey
    +JM	Jamaica
    +JO	Jordan
    +JP	Japan
    +KE	Kenya
    +KG	Kyrgyzstan
    +KH	Cambodia
    +KI	Kiribati
    +KM	Comoros
    +KN	St Kitts & Nevis
    +KP	Korea (North)
    +KR	Korea (South)
    +KW	Kuwait
    +KY	Cayman Islands
    +KZ	Kazakhstan
    +LA	Laos
    +LB	Lebanon
    +LC	St Lucia
    +LI	Liechtenstein
    +LK	Sri Lanka
    +LR	Liberia
    +LS	Lesotho
    +LT	Lithuania
    +LU	Luxembourg
    +LV	Latvia
    +LY	Libya
    +MA	Morocco
    +MC	Monaco
    +MD	Moldova
    +ME	Montenegro
    +MF	St Martin (French part)
    +MG	Madagascar
    +MH	Marshall Islands
    +MK	Macedonia
    +ML	Mali
    +MM	Myanmar (Burma)
    +MN	Mongolia
    +MO	Macau
    +MP	Northern Mariana Islands
    +MQ	Martinique
    +MR	Mauritania
    +MS	Montserrat
    +MT	Malta
    +MU	Mauritius
    +MV	Maldives
    +MW	Malawi
    +MX	Mexico
    +MY	Malaysia
    +MZ	Mozambique
    +NA	Namibia
    +NC	New Caledonia
    +NE	Niger
    +NF	Norfolk Island
    +NG	Nigeria
    +NI	Nicaragua
    +NL	Netherlands
    +NO	Norway
    +NP	Nepal
    +NR	Nauru
    +NU	Niue
    +NZ	New Zealand
    +OM	Oman
    +PA	Panama
    +PE	Peru
    +PF	French Polynesia
    +PG	Papua New Guinea
    +PH	Philippines
    +PK	Pakistan
    +PL	Poland
    +PM	St Pierre & Miquelon
    +PN	Pitcairn
    +PR	Puerto Rico
    +PS	Palestine
    +PT	Portugal
    +PW	Palau
    +PY	Paraguay
    +QA	Qatar
    +RE	Reunion
    +RO	Romania
    +RS	Serbia
    +RU	Russia
    +RW	Rwanda
    +SA	Saudi Arabia
    +SB	Solomon Islands
    +SC	Seychelles
    +SD	Sudan
    +SE	Sweden
    +SG	Singapore
    +SH	St Helena
    +SI	Slovenia
    +SJ	Svalbard & Jan Mayen
    +SK	Slovakia
    +SL	Sierra Leone
    +SM	San Marino
    +SN	Senegal
    +SO	Somalia
    +SR	Suriname
    +SS	South Sudan
    +ST	Sao Tome & Principe
    +SV	El Salvador
    +SX	Sint Maarten
    +SY	Syria
    +SZ	Swaziland
    +TC	Turks & Caicos Is
    +TD	Chad
    +TF	French Southern & Antarctic Lands
    +TG	Togo
    +TH	Thailand
    +TJ	Tajikistan
    +TK	Tokelau
    +TL	East Timor
    +TM	Turkmenistan
    +TN	Tunisia
    +TO	Tonga
    +TR	Turkey
    +TT	Trinidad & Tobago
    +TV	Tuvalu
    +TW	Taiwan
    +TZ	Tanzania
    +UA	Ukraine
    +UG	Uganda
    +UM	US minor outlying islands
    +US	United States
    +UY	Uruguay
    +UZ	Uzbekistan
    +VA	Vatican City
    +VC	St Vincent
    +VE	Venezuela
    +VG	Virgin Islands (UK)
    +VI	Virgin Islands (US)
    +VN	Vietnam
    +VU	Vanuatu
    +WF	Wallis & Futuna
    +WS	Samoa (western)
    +YE	Yemen
    +YT	Mayotte
    +ZA	South Africa
    +ZM	Zambia
    +ZW	Zimbabwe
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/jdk11_backward b/jdk/test/sun/util/calendar/zi/tzdata/jdk11_backward
    new file mode 100644
    index 00000000000..5404ceaae4c
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/jdk11_backward
    @@ -0,0 +1,51 @@
    +#
    +# Copyright (c) 2000, 2006, 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#
    +# 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.
    +#
    +# JDK 1.1.x compatible time zone IDs
    +#
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	SystemV	min	1973	-	Apr	lastSun	2:00	1:00	D
    +Rule	SystemV	min	1973	-	Oct	lastSun	2:00	0	S
    +Rule	SystemV	1974	only	-	Jan	6	2:00	1:00	D
    +Rule	SystemV	1974	only	-	Nov	lastSun	2:00	0	S
    +Rule	SystemV	1975	only	-	Feb	23	2:00	1:00	D
    +Rule	SystemV	1975	only	-	Oct	lastSun	2:00	0	S
    +Rule	SystemV	1976	max	-	Apr	lastSun	2:00	1:00	D
    +Rule	SystemV	1976	max	-	Oct	lastSun	2:00	0	S
    +
    +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
    +Zone	SystemV/AST4ADT	-4:00	SystemV		A%sT
    +Zone	SystemV/EST5EDT	-5:00	SystemV		E%sT
    +Zone	SystemV/CST6CDT	-6:00	SystemV		C%sT
    +Zone	SystemV/MST7MDT	-7:00	SystemV		M%sT
    +Zone	SystemV/PST8PDT	-8:00	SystemV		P%sT
    +Zone	SystemV/YST9YDT	-9:00	SystemV		Y%sT
    +Zone	SystemV/AST4	-4:00	-		AST
    +Zone	SystemV/EST5	-5:00	-		EST
    +Zone	SystemV/CST6	-6:00	-		CST
    +Zone	SystemV/MST7	-7:00	-		MST
    +Zone	SystemV/PST8	-8:00	-		PST
    +Zone	SystemV/YST9	-9:00	-		YST
    +Zone	SystemV/HST10	-10:00	-		HST
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/leapseconds b/jdk/test/sun/util/calendar/zi/tzdata/leapseconds
    new file mode 100644
    index 00000000000..ab6720ded58
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/leapseconds
    @@ -0,0 +1,123 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# Allowance for leapseconds added to each timezone file.
    +
    +# The International Earth Rotation Service periodically uses leap seconds
    +# to keep UTC to within 0.9 s of UT1
    +# (which measures the true angular orientation of the earth in space); see
    +# Terry J Quinn, The BIPM and the accurate measure of time,
    +# Proc IEEE 79, 7 (July 1991), 894-905.
    +# There were no leap seconds before 1972, because the official mechanism
    +# accounting for the discrepancy between atomic time and the earth's rotation
    +# did not exist until the early 1970s.
    +
    +# The correction (+ or -) is made at the given time, so lines
    +# will typically look like:
    +#	Leap	YEAR	MON	DAY	23:59:60	+	R/S
    +# or
    +#	Leap	YEAR	MON	DAY	23:59:59	-	R/S
    +
    +# If the leapsecond is Rolling (R) the given time is local time
    +# If the leapsecond is Stationary (S) the given time is UTC
    +
    +# Leap	YEAR	MONTH	DAY	HH:MM:SS	CORR	R/S
    +Leap	1972	Jun	30	23:59:60	+	S
    +Leap	1972	Dec	31	23:59:60	+	S
    +Leap	1973	Dec	31	23:59:60	+	S
    +Leap	1974	Dec	31	23:59:60	+	S
    +Leap	1975	Dec	31	23:59:60	+	S
    +Leap	1976	Dec	31	23:59:60	+	S
    +Leap	1977	Dec	31	23:59:60	+	S
    +Leap	1978	Dec	31	23:59:60	+	S
    +Leap	1979	Dec	31	23:59:60	+	S
    +Leap	1981	Jun	30	23:59:60	+	S
    +Leap	1982	Jun	30	23:59:60	+	S
    +Leap	1983	Jun	30	23:59:60	+	S
    +Leap	1985	Jun	30	23:59:60	+	S
    +Leap	1987	Dec	31	23:59:60	+	S
    +Leap	1989	Dec	31	23:59:60	+	S
    +Leap	1990	Dec	31	23:59:60	+	S
    +Leap	1992	Jun	30	23:59:60	+	S
    +Leap	1993	Jun	30	23:59:60	+	S
    +Leap	1994	Jun	30	23:59:60	+	S
    +Leap	1995	Dec	31	23:59:60	+	S
    +Leap	1997	Jun	30	23:59:60	+	S
    +Leap	1998	Dec	31	23:59:60	+	S
    +Leap	2005	Dec	31	23:59:60	+	S
    +Leap	2008	Dec	31	23:59:60	+	S
    +Leap	2012	Jun	30	23:59:60	+	S
    +
    +# INTERNATIONAL EARTH ROTATION AND REFERENCE SYSTEMS SERVICE (IERS)
    +#
    +# SERVICE INTERNATIONAL DE LA ROTATION TERRESTRE ET DES SYSTEMES DE REFERENCE
    +#
    +#
    +# SERVICE DE LA ROTATION TERRESTRE
    +# OBSERVATOIRE DE PARIS
    +# 61, Av. de l'Observatoire 75014 PARIS (France)
    +# Tel.      : 33 (0) 1 40 51 22 26
    +# FAX       : 33 (0) 1 40 51 22 91
    +# e-mail    : (E-Mail Removed)
    +# http://hpiers.obspm.fr/eop-pc
    +#
    +# Paris, 5 January 2012
    +#
    +#
    +# Bulletin C 43
    +#
    +# To authorities responsible
    +# for the measurement and
    +# distribution of time
    +#
    +#
    +# UTC TIME STEP
    +# on the 1st of July 2012
    +#
    +#
    +# A positive leap second will be introduced at the end of June 2012.
    +# The sequence of dates of the UTC second markers will be:
    +#
    +#                          2012 June 30,     23h 59m 59s
    +#                          2012 June 30,     23h 59m 60s
    +#                          2012 July  1,      0h  0m  0s
    +#
    +# The difference between UTC and the International Atomic Time TAI is:
    +#
    +# from 2009 January 1, 0h UTC, to 2012 July 1  0h UTC  : UTC-TAI = - 34s
    +# from 2012 July 1,    0h UTC, until further notice    : UTC-TAI = - 35s
    +#
    +# Leap seconds can be introduced in UTC at the end of the months of December
    +# or June, depending on the evolution of UT1-TAI. Bulletin C is mailed every
    +# six months, either to announce a time step in UTC or to confirm that there
    +# will be no time step at the next possible date.
    +#
    +#
    +# Daniel GAMBIS
    +# Head
    +# Earth Orientation Center of IERS
    +# Observatoire de Paris, France
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/northamerica b/jdk/test/sun/util/calendar/zi/tzdata/northamerica
    new file mode 100644
    index 00000000000..c3033267404
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/northamerica
    @@ -0,0 +1,3258 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# also includes Central America and the Caribbean
    +
    +# This data is by no means authoritative; if you think you know better,
    +# go ahead and edit the file (and please send any changes to
    +# tz@elsie.nci.nih.gov for general use in the future).
    +
    +# From Paul Eggert (1999-03-22):
    +# A reliable and entertaining source about time zones is
    +# Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997).
    +
    +###############################################################################
    +
    +# United States
    +
    +# From Paul Eggert (1999-03-31):
    +# Howse writes (pp 121-125) that time zones were invented by
    +# Professor Charles Ferdinand Dowd (1825-1904),
    +# Principal of Temple Grove Ladies' Seminary (Saratoga Springs, NY).
    +# His pamphlet ``A System of National Time for Railroads'' (1870)
    +# was the result of his proposals at the Convention of Railroad Trunk Lines
    +# in New York City (1869-10).  His 1870 proposal was based on Washington, DC,
    +# but in 1872-05 he moved the proposed origin to Greenwich.
    +# His proposal was adopted by the railroads on 1883-11-18 at 12:00,
    +# and the most of the country soon followed suit.
    +
    +# From Paul Eggert (2005-04-16):
    +# That 1883 transition occurred at 12:00 new time, not at 12:00 old time.
    +# See p 46 of David Prerau, Seize the daylight, Thunder's Mouth Press (2005).
    +
    +# From Paul Eggert (2006-03-22):
    +# A good source for time zone historical data in the US is
    +# Thomas G. Shanks, The American Atlas (5th edition),
    +# San Diego: ACS Publications, Inc. (1991).
    +# Make sure you have the errata sheet; the book is somewhat useless without it.
    +# It is the source for most of the pre-1991 US entries below.
    +
    +# From Paul Eggert (2001-03-06):
    +# Daylight Saving Time was first suggested as a joke by Benjamin Franklin
    +# in his whimsical essay ``An Economical Project for Diminishing the Cost
    +# of Light'' published in the Journal de Paris (1784-04-26).
    +# Not everyone is happy with the results:
    +#
    +#	I don't really care how time is reckoned so long as there is some
    +#	agreement about it, but I object to being told that I am saving
    +#	daylight when my reason tells me that I am doing nothing of the kind.
    +#	I even object to the implication that I am wasting something
    +#	valuable if I stay in bed after the sun has risen.  As an admirer
    +#	of moonlight I resent the bossy insistence of those who want to
    +#	reduce my time for enjoying it.  At the back of the Daylight Saving
    +#	scheme I detect the bony, blue-fingered hand of Puritanism, eager
    +#	to push people into bed earlier, and get them up earlier, to make
    +#	them healthy, wealthy and wise in spite of themselves.
    +#
    +#	-- Robertson Davies, The diary of Samuel Marchbanks,
    +#	   Clarke, Irwin (1947), XIX, Sunday
    +#
    +# For more about the first ten years of DST in the United States, see
    +# Robert Garland's 
    +# Ten years of daylight saving from the Pittsburgh standpoint
    +# (Carnegie Library of Pittsburgh, 1927).
    +#
    +# Shanks says that DST was called "War Time" in the US in 1918 and 1919.
    +# However, DST was imposed by the Standard Time Act of 1918, which
    +# was the first nationwide legal time standard, and apparently
    +# time was just called "Standard Time" or "Daylight Saving Time".
    +
    +# From Arthur David Olson:
    +# US Daylight Saving Time ended on the last Sunday of *October* in 1974.
    +# See, for example, the front page of the Saturday, 1974-10-26
    +# and Sunday, 1974-10-27 editions of the Washington Post.
    +
    +# From Arthur David Olson:
    +# Before the Uniform Time Act of 1966 took effect in 1967, observance of
    +# Daylight Saving Time in the US was by local option, except during wartime.
    +
    +# From Arthur David Olson (2000-09-25):
    +# Last night I heard part of a rebroadcast of a 1945 Arch Oboler radio drama.
    +# In the introduction, Oboler spoke of "Eastern Peace Time."
    +# An AltaVista search turned up
    +# :
    +# "When the time is announced over the radio now, it is 'Eastern Peace
    +# Time' instead of the old familiar 'Eastern War Time.'  Peace is wonderful."
    +#  (August 1945) by way of confirmation.
    +
    +# From Joseph Gallant citing
    +# George H. Douglas, _The Early Days of Radio Broadcasting_ (1987):
    +# At 7 P.M. (Eastern War Time) [on 1945-08-14], the networks were set
    +# to switch to London for Attlee's address, but the American people
    +# never got to hear his speech live. According to one press account,
    +# CBS' Bob Trout was first to announce the word of Japan's surrender,
    +# but a few seconds later, NBC, ABC and Mutual also flashed the word
    +# of surrender, all of whom interrupting the bells of Big Ben in
    +# London which were to precede Mr. Attlee's speech.
    +
    +# From Paul Eggert (2003-02-09): It was Robert St John, not Bob Trout.  From
    +# Myrna Oliver's obituary of St John on page B16 of today's Los Angeles Times:
    +#
    +# ... a war-weary U.S. clung to radios, awaiting word of Japan's surrender.
    +# Any announcement from Asia would reach St. John's New York newsroom on a
    +# wire service teletype machine, which had prescribed signals for major news.
    +# Associated Press, for example, would ring five bells before spewing out
    +# typed copy of an important story, and 10 bells for news "of transcendental
    +# importance."
    +#
    +# On Aug. 14, stalling while talking steadily into the NBC networks' open
    +# microphone, St. John heard five bells and waited only to hear a sixth bell,
    +# before announcing confidently: "Ladies and gentlemen, World War II is over.
    +# The Japanese have agreed to our surrender terms."
    +#
    +# He had scored a 20-second scoop on other broadcasters.
    +
    +# From Arthur David Olson (2005-08-22):
    +# Paul has been careful to use the "US" rules only in those locations
    +# that are part of the United States; this reflects the real scope of
    +# U.S. government action.  So even though the "US" rules have changed
    +# in the latest release, other countries won't be affected.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	US	1918	1919	-	Mar	lastSun	2:00	1:00	D
    +Rule	US	1918	1919	-	Oct	lastSun	2:00	0	S
    +Rule	US	1942	only	-	Feb	9	2:00	1:00	W # War
    +Rule	US	1945	only	-	Aug	14	23:00u	1:00	P # Peace
    +Rule	US	1945	only	-	Sep	30	2:00	0	S
    +Rule	US	1967	2006	-	Oct	lastSun	2:00	0	S
    +Rule	US	1967	1973	-	Apr	lastSun	2:00	1:00	D
    +Rule	US	1974	only	-	Jan	6	2:00	1:00	D
    +Rule	US	1975	only	-	Feb	23	2:00	1:00	D
    +Rule	US	1976	1986	-	Apr	lastSun	2:00	1:00	D
    +Rule	US	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
    +Rule	US	2007	max	-	Mar	Sun>=8	2:00	1:00	D
    +Rule	US	2007	max	-	Nov	Sun>=1	2:00	0	S
    +
    +# From Arthur David Olson, 2005-12-19
    +# We generate the files specified below to guard against old files with
    +# obsolete information being left in the time zone binary directory.
    +# We limit the list to names that have appeared in previous versions of
    +# this time zone package.
    +# We do these as separate Zones rather than as Links to avoid problems if
    +# a particular place changes whether it observes DST.
    +# We put these specifications here in the northamerica file both to
    +# increase the chances that they'll actually get compiled and to
    +# avoid the need to duplicate the US rules in another file.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	EST		 -5:00	-	EST
    +Zone	MST		 -7:00	-	MST
    +Zone	HST		-10:00	-	HST
    +Zone	EST5EDT		 -5:00	US	E%sT
    +Zone	CST6CDT		 -6:00	US	C%sT
    +Zone	MST7MDT		 -7:00	US	M%sT
    +Zone	PST8PDT		 -8:00	US	P%sT
    +
    +# From Bob Devine (1988-01-28):
    +# ...Alaska (and Hawaii) had the timezone names changed in 1967.
    +#    old			 new
    +#    Pacific Standard Time(PST)  -same-
    +#    Yukon Standard Time(YST)    -same-
    +#    Central Alaska S.T. (CAT)   Alaska-Hawaii St[an]dard Time (AHST)
    +#    Nome Standard Time (NT)     Bering Standard Time (BST)
    +#
    +# ...Alaska's timezone lines were redrawn in 1983 to give only 2 tz.
    +#    The YST zone now covers nearly all of the state, AHST just part
    +#    of the Aleutian islands.   No DST.
    +
    +# From Paul Eggert (1995-12-19):
    +# The tables below use `NST', not `NT', for Nome Standard Time.
    +# I invented `CAWT' for Central Alaska War Time.
    +
    +# From U. S. Naval Observatory (1989-01-19):
    +# USA  EASTERN       5 H  BEHIND UTC    NEW YORK, WASHINGTON
    +# USA  EASTERN       4 H  BEHIND UTC    APR 3 - OCT 30
    +# USA  CENTRAL       6 H  BEHIND UTC    CHICAGO, HOUSTON
    +# USA  CENTRAL       5 H  BEHIND UTC    APR 3 - OCT 30
    +# USA  MOUNTAIN      7 H  BEHIND UTC    DENVER
    +# USA  MOUNTAIN      6 H  BEHIND UTC    APR 3 - OCT 30
    +# USA  PACIFIC       8 H  BEHIND UTC    L.A., SAN FRANCISCO
    +# USA  PACIFIC       7 H  BEHIND UTC    APR 3 - OCT 30
    +# USA  ALASKA STD    9 H  BEHIND UTC    MOST OF ALASKA     (AKST)
    +# USA  ALASKA STD    8 H  BEHIND UTC    APR 3 - OCT 30 (AKDT)
    +# USA  ALEUTIAN     10 H  BEHIND UTC    ISLANDS WEST OF 170W
    +# USA  - " -         9 H  BEHIND UTC    APR 3 - OCT 30
    +# USA  HAWAII       10 H  BEHIND UTC
    +# USA  BERING       11 H  BEHIND UTC    SAMOA, MIDWAY
    +
    +# From Arthur David Olson (1989-01-21):
    +# The above dates are for 1988.
    +# Note the "AKST" and "AKDT" abbreviations, the claim that there's
    +# no DST in Samoa, and the claim that there is DST in Alaska and the
    +# Aleutians.
    +
    +# From Arthur David Olson (1988-02-13):
    +# Legal standard time zone names, from United States Code (1982 Edition and
    +# Supplement III), Title 15, Chapter 6, Section 260 and forward.  First, names
    +# up to 1967-04-01 (when most provisions of the Uniform Time Act of 1966
    +# took effect), as explained in sections 263 and 261:
    +#	(none)
    +#	United States standard eastern time
    +#	United States standard mountain time
    +#	United States standard central time
    +#	United States standard Pacific time
    +#	(none)
    +#	United States standard Alaska time
    +#	(none)
    +# Next, names from 1967-04-01 until 1983-11-30 (the date for
    +# public law 98-181):
    +#	Atlantic standard time
    +#	eastern standard time
    +#	central standard time
    +#	mountain standard time
    +#	Pacific standard time
    +#	Yukon standard time
    +#	Alaska-Hawaii standard time
    +#	Bering standard time
    +# And after 1983-11-30:
    +#	Atlantic standard time
    +#	eastern standard time
    +#	central standard time
    +#	mountain standard time
    +#	Pacific standard time
    +#	Alaska standard time
    +#	Hawaii-Aleutian standard time
    +#	Samoa standard time
    +# The law doesn't give abbreviations.
    +#
    +# From Paul Eggert (2000-01-08), following a heads-up from Rives McDow:
    +# Public law 106-564 (2000-12-23) introduced the abbreviation
    +# "Chamorro Standard Time" for time in Guam and the Northern Marianas.
    +# See the file "australasia".
    +
    +# From Arthur David Olson, 2005-08-09
    +# The following was signed into law on 2005-08-08.
    +#
    +# H.R. 6, Energy Policy Act of 2005, SEC. 110. DAYLIGHT SAVINGS.
    +#   (a) Amendment- Section 3(a) of the Uniform Time Act of 1966 (15
    +#   U.S.C. 260a(a)) is amended--
    +#     (1) by striking `first Sunday of April' and inserting `second
    +#     Sunday of March'; and
    +#     (2) by striking `last Sunday of October' and inserting `first
    +#     Sunday of November'.
    +#   (b) Effective Date- Subsection (a) shall take effect 1 year after the
    +#   date of enactment of this Act or March 1, 2007, whichever is later.
    +#   (c) Report to Congress- Not later than 9 months after the effective
    +#   date stated in subsection (b), the Secretary shall report to Congress
    +#   on the impact of this section on energy consumption in the United
    +#   States.
    +#   (d) Right to Revert- Congress retains the right to revert the
    +#   Daylight Saving Time back to the 2005 time schedules once the
    +#   Department study is complete.
    +
    +# US eastern time, represented by New York
    +
    +# Connecticut, Delaware, District of Columbia, most of Florida,
    +# Georgia, southeast Indiana (Dearborn and Ohio counties), eastern Kentucky
    +# (except America/Kentucky/Louisville below), Maine, Maryland, Massachusetts,
    +# New Hampshire, New Jersey, New York, North Carolina, Ohio,
    +# Pennsylvania, Rhode Island, South Carolina, eastern Tennessee,
    +# Vermont, Virginia, West Virginia
    +
    +# From Dave Cantor (2004-11-02):
    +# Early this summer I had the occasion to visit the Mount Washington
    +# Observatory weather station atop (of course!) Mount Washington [, NH]....
    +# One of the staff members said that the station was on Eastern Standard Time
    +# and didn't change their clocks for Daylight Saving ... so that their
    +# reports will always have times which are 5 hours behind UTC.
    +
    +# From Paul Eggert (2005-08-26):
    +# According to today's Huntsville Times
    +# 
    +# a few towns on Alabama's "eastern border with Georgia, such as Phenix City
    +# in Russell County, Lanett in Chambers County and some towns in Lee County,
    +# set their watches and clocks on Eastern time."  It quotes H.H. "Bubba"
    +# Roberts, city administrator in Phenix City. as saying "We are in the Central
    +# time zone, but we do go by the Eastern time zone because so many people work
    +# in Columbus."
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule	NYC	1920	only	-	Mar	lastSun	2:00	1:00	D
    +Rule	NYC	1920	only	-	Oct	lastSun	2:00	0	S
    +Rule	NYC	1921	1966	-	Apr	lastSun	2:00	1:00	D
    +Rule	NYC	1921	1954	-	Sep	lastSun	2:00	0	S
    +Rule	NYC	1955	1966	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/New_York	-4:56:02 -	LMT	1883 Nov 18 12:03:58
    +			-5:00	US	E%sT	1920
    +			-5:00	NYC	E%sT	1942
    +			-5:00	US	E%sT	1946
    +			-5:00	NYC	E%sT	1967
    +			-5:00	US	E%sT
    +
    +# US central time, represented by Chicago
    +
    +# Alabama, Arkansas, Florida panhandle (Bay, Calhoun, Escambia,
    +# Gulf, Holmes, Jackson, Okaloosa, Santa Rosa, Walton, and
    +# Washington counties), Illinois, western Indiana
    +# (Gibson, Jasper, Lake, LaPorte, Newton, Porter, Posey, Spencer,
    +# Vanderburgh, and Warrick counties), Iowa, most of Kansas, western
    +# Kentucky, Louisiana, Minnesota, Mississippi, Missouri, eastern
    +# Nebraska, eastern North Dakota, Oklahoma, eastern South Dakota,
    +# western Tennessee, most of Texas, Wisconsin
    +
    +# From Larry M. Smith (2006-04-26) re Wisconsin:
    +# http://www.legis.state.wi.us/statutes/Stat0175.pdf ...
    +# is currently enforced at the 01:00 time of change.  Because the local
    +# "bar time" in the state corresponds to 02:00, a number of citations
    +# are issued for the "sale of class 'B' alcohol after prohibited
    +# hours" within the deviated hour of this change every year....
    +#
    +# From Douglas R. Bomberg (2007-03-12):
    +# Wisconsin has enacted (nearly eleventh-hour) legislation to get WI
    +# Statue 175 closer in synch with the US Congress' intent....
    +# http://www.legis.state.wi.us/2007/data/acts/07Act3.pdf
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule	Chicago	1920	only	-	Jun	13	2:00	1:00	D
    +Rule	Chicago	1920	1921	-	Oct	lastSun	2:00	0	S
    +Rule	Chicago	1921	only	-	Mar	lastSun	2:00	1:00	D
    +Rule	Chicago	1922	1966	-	Apr	lastSun	2:00	1:00	D
    +Rule	Chicago	1922	1954	-	Sep	lastSun	2:00	0	S
    +Rule	Chicago	1955	1966	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Chicago	-5:50:36 -	LMT	1883 Nov 18 12:09:24
    +			-6:00	US	C%sT	1920
    +			-6:00	Chicago	C%sT	1936 Mar  1 2:00
    +			-5:00	-	EST	1936 Nov 15 2:00
    +			-6:00	Chicago	C%sT	1942
    +			-6:00	US	C%sT	1946
    +			-6:00	Chicago	C%sT	1967
    +			-6:00	US	C%sT
    +# Oliver County, ND switched from mountain to central time on 1992-10-25.
    +Zone America/North_Dakota/Center -6:45:12 - LMT	1883 Nov 18 12:14:48
    +			-7:00	US	M%sT	1992 Oct 25 02:00
    +			-6:00	US	C%sT
    +# Morton County, ND, switched from mountain to central time on
    +# 2003-10-26, except for the area around Mandan which was already central time.
    +# See .
    +# Officially this switch also included part of Sioux County, and
    +# Jones, Mellette, and Todd Counties in South Dakota;
    +# but in practice these other counties were already observing central time.
    +# See .
    +Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 12:14:21
    +			-7:00	US	M%sT	2003 Oct 26 02:00
    +			-6:00	US	C%sT
    +
    +# From Josh Findley (2011-01-21):
    +# ...it appears that Mercer County, North Dakota, changed from the
    +# mountain time zone to the central time zone at the last transition from
    +# daylight-saving to standard time (on Nov. 7, 2010):
    +# 
    +# http://www.gpo.gov/fdsys/pkg/FR-2010-09-29/html/2010-24376.htm
    +# 
    +# 
    +# http://www.bismarcktribune.com/news/local/article_1eb1b588-c758-11df-b472-001cc4c03286.html
    +# 
    +
    +# From Andy Lipscomb (2011-01-24):
    +# ...according to the Census Bureau, the largest city is Beulah (although
    +# it's commonly referred to as Beulah-Hazen, with Hazen being the next
    +# largest city in Mercer County).  Google Maps places Beulah's city hall
    +# at 4715'51" north, 10146'40" west, which yields an offset of 6h47'07".
    +
    +Zone America/North_Dakota/Beulah -6:47:07 - LMT 1883 Nov 18 12:12:53
    +			-7:00	US	M%sT	2010 Nov  7 2:00
    +			-6:00	US	C%sT
    +
    +# US mountain time, represented by Denver
    +#
    +# Colorado, far western Kansas, Montana, western
    +# Nebraska, Nevada border (Jackpot, Owyhee, and Mountain City),
    +# New Mexico, southwestern North Dakota,
    +# western South Dakota, far western Texas (El Paso County, Hudspeth County,
    +# and Pine Springs and Nickel Creek in Culberson County), Utah, Wyoming
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule	Denver	1920	1921	-	Mar	lastSun	2:00	1:00	D
    +Rule	Denver	1920	only	-	Oct	lastSun	2:00	0	S
    +Rule	Denver	1921	only	-	May	22	2:00	0	S
    +Rule	Denver	1965	1966	-	Apr	lastSun	2:00	1:00	D
    +Rule	Denver	1965	1966	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Denver	-6:59:56 -	LMT	1883 Nov 18 12:00:04
    +			-7:00	US	M%sT	1920
    +			-7:00	Denver	M%sT	1942
    +			-7:00	US	M%sT	1946
    +			-7:00	Denver	M%sT	1967
    +			-7:00	US	M%sT
    +
    +# US Pacific time, represented by Los Angeles
    +#
    +# California, northern Idaho (Benewah, Bonner, Boundary, Clearwater,
    +# Idaho, Kootenai, Latah, Lewis, Nez Perce, and Shoshone counties,
    +# and the northern three-quarters of Idaho county),
    +# most of Nevada, most of Oregon, and Washington
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule	CA	1948	only	-	Mar	14	2:00	1:00	D
    +Rule	CA	1949	only	-	Jan	 1	2:00	0	S
    +Rule	CA	1950	1966	-	Apr	lastSun	2:00	1:00	D
    +Rule	CA	1950	1961	-	Sep	lastSun	2:00	0	S
    +Rule	CA	1962	1966	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Los_Angeles -7:52:58 -	LMT	1883 Nov 18 12:07:02
    +			-8:00	US	P%sT	1946
    +			-8:00	CA	P%sT	1967
    +			-8:00	US	P%sT
    +
    +# Alaska
    +# AK%sT is the modern abbreviation for -9:00 per USNO.
    +#
    +# From Paul Eggert (2001-05-30):
    +# Howse writes that Alaska switched from the Julian to the Gregorian calendar,
    +# and from east-of-GMT to west-of-GMT days, when the US bought it from Russia.
    +# This was on 1867-10-18, a Friday; the previous day was 1867-10-06 Julian,
    +# also a Friday.  Include only the time zone part of this transition,
    +# ignoring the switch from Julian to Gregorian, since we can't represent
    +# the Julian calendar.
    +#
    +# As far as we know, none of the exact locations mentioned below were
    +# permanently inhabited in 1867 by anyone using either calendar.
    +# (Yakutat was colonized by the Russians in 1799, but the settlement
    +# was destroyed in 1805 by a Yakutat-kon war party.)  However, there
    +# were nearby inhabitants in some cases and for our purposes perhaps
    +# it's best to simply use the official transition.
    +#
    +
    +# From Steve Ferguson (2011-01-31):
    +# The author lives in Alaska and many of the references listed are only
    +# available to Alaskan residents.
    +#
    +# 
    +# http://www.alaskahistoricalsociety.org/index.cfm?section=discover%20alaska&page=Glimpses%20of%20the%20Past&viewpost=2&ContentId=98
    +# 
    +
    +# From Arthur David Olson (2011-02-01):
    +# Here's database-relevant material from the 2001 "Alaska History" article:
    +#
    +# On September 20 [1979]...DOT...officials decreed that on April 27,
    +# 1980, Juneau and other nearby communities would move to Yukon Time.
    +# Sitka, Petersburg, Wrangell, and Ketchikan, however, would remain on
    +# Pacific Time.
    +#
    +# ...on September 22, 1980, DOT Secretary Neil E. Goldschmidt rescinded the
    +# Department's September 1979 decision. Juneau and other communities in
    +# northern Southeast reverted to Pacific Time on October 26.
    +#
    +# On October 28 [1983]...the Metlakatla Indian Community Council voted
    +# unanimously to keep the reservation on Pacific Time.
    +#
    +# According to DOT official Joanne Petrie, Indian reservations are not
    +# bound to follow time zones imposed by neighboring jurisdictions.
    +#
    +# (The last is consistent with how the database now handles the Navajo
    +# Nation.)
    +
    +# From Arthur David Olson (2011-02-09):
    +# I just spoke by phone with a staff member at the Metlakatla Indian
    +# Community office (using contact information available at
    +# 
    +# http://www.commerce.state.ak.us/dca/commdb/CIS.cfm?Comm_Boro_name=Metlakatla
    +# ).
    +# It's shortly after 1:00 here on the east coast of the United States;
    +# the staffer said it was shortly after 10:00 there. When I asked whether
    +# that meant they were on Pacific time, they said no--they were on their
    +# own time. I asked about daylight saving; they said it wasn't used. I
    +# did not inquire about practices in the past.
    +
    +# From Arthur David Olson (2011-08-17):
    +# For lack of better information, assume that Metlakatla's
    +# abandonment of use of daylight saving resulted from the 1983 vote.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Juneau	 15:02:19 -	LMT	1867 Oct 18
    +			 -8:57:41 -	LMT	1900 Aug 20 12:00
    +			 -8:00	-	PST	1942
    +			 -8:00	US	P%sT	1946
    +			 -8:00	-	PST	1969
    +			 -8:00	US	P%sT	1980 Apr 27 2:00
    +			 -9:00	US	Y%sT	1980 Oct 26 2:00
    +			 -8:00	US	P%sT	1983 Oct 30 2:00
    +			 -9:00	US	Y%sT	1983 Nov 30
    +			 -9:00	US	AK%sT
    +Zone America/Sitka	 14:58:47 -	LMT	1867 Oct 18
    +			 -9:01:13 -	LMT	1900 Aug 20 12:00
    +			 -8:00	-	PST	1942
    +			 -8:00	US	P%sT	1946
    +			 -8:00	-	PST	1969
    +			 -8:00	US	P%sT	1983 Oct 30 2:00
    +			 -9:00	US	Y%sT	1983 Nov 30
    +			 -9:00	US	AK%sT
    +Zone America/Metlakatla	 15:13:42 -	LMT	1867 Oct 18
    +			 -8:46:18 -	LMT	1900 Aug 20 12:00
    +			 -8:00	-	PST	1942
    +			 -8:00	US	P%sT	1946
    +			 -8:00	-	PST	1969
    +			 -8:00	US	P%sT	1983 Oct 30 2:00
    +			 -8:00	-	MeST
    +Zone America/Yakutat	 14:41:05 -	LMT	1867 Oct 18
    +			 -9:18:55 -	LMT	1900 Aug 20 12:00
    +			 -9:00	-	YST	1942
    +			 -9:00	US	Y%sT	1946
    +			 -9:00	-	YST	1969
    +			 -9:00	US	Y%sT	1983 Nov 30
    +			 -9:00	US	AK%sT
    +Zone America/Anchorage	 14:00:24 -	LMT	1867 Oct 18
    +			 -9:59:36 -	LMT	1900 Aug 20 12:00
    +			-10:00	-	CAT	1942
    +			-10:00	US	CAT/CAWT 1945 Aug 14 23:00u
    +			-10:00	US	CAT/CAPT 1946 # Peace
    +			-10:00	-	CAT	1967 Apr
    +			-10:00	-	AHST	1969
    +			-10:00	US	AH%sT	1983 Oct 30 2:00
    +			 -9:00	US	Y%sT	1983 Nov 30
    +			 -9:00	US	AK%sT
    +Zone America/Nome	 12:58:21 -	LMT	1867 Oct 18
    +			-11:01:38 -	LMT	1900 Aug 20 12:00
    +			-11:00	-	NST	1942
    +			-11:00	US	N%sT	1946
    +			-11:00	-	NST	1967 Apr
    +			-11:00	-	BST	1969
    +			-11:00	US	B%sT	1983 Oct 30 2:00
    +			 -9:00	US	Y%sT	1983 Nov 30
    +			 -9:00	US	AK%sT
    +Zone America/Adak	 12:13:21 -	LMT	1867 Oct 18
    +			-11:46:38 -	LMT	1900 Aug 20 12:00
    +			-11:00	-	NST	1942
    +			-11:00	US	N%sT	1946
    +			-11:00	-	NST	1967 Apr
    +			-11:00	-	BST	1969
    +			-11:00	US	B%sT	1983 Oct 30 2:00
    +			-10:00	US	AH%sT	1983 Nov 30
    +			-10:00	US	HA%sT
    +# The following switches don't quite make our 1970 cutoff.
    +#
    +# Shanks writes that part of southwest Alaska (e.g. Aniak)
    +# switched from -11:00 to -10:00 on 1968-09-22 at 02:00,
    +# and another part (e.g. Akiak) made the same switch five weeks later.
    +#
    +# From David Flater (2004-11-09):
    +# In e-mail, 2004-11-02, Ray Hudson, historian/liaison to the Unalaska
    +# Historic Preservation Commission, provided this information, which
    +# suggests that Unalaska deviated from statutory time from early 1967
    +# possibly until 1983:
    +#
    +#  Minutes of the Unalaska City Council Meeting, January 10, 1967:
    +#  "Except for St. Paul and Akutan, Unalaska is the only important
    +#  location not on Alaska Standard Time.  The following resolution was
    +#  made by William Robinson and seconded by Henry Swanson:  Be it
    +#  resolved that the City of Unalaska hereby goes to Alaska Standard
    +#  Time as of midnight Friday, January 13, 1967 (1 A.M. Saturday,
    +#  January 14, Alaska Standard Time.)  This resolution was passed with
    +#  three votes for and one against."
    +
    +# Hawaii
    +
    +# From Arthur David Olson (2010-12-09):
    +# "Hawaiian Time" by Robert C. Schmitt and Doak C. Cox appears on pages 207-225
    +# of volume 26 of The Hawaiian Journal of History (1992). As of 2010-12-09,
    +# the article is available at
    +# 
    +# http://evols.library.manoa.hawaii.edu/bitstream/10524/239/2/JL26215.pdf
    +# 
    +# and indicates that standard time was adopted effective noon, January
    +# 13, 1896 (page 218), that in "1933, the Legislature decreed daylight
    +# saving for the period between the last Sunday of each April and the
    +# last Sunday of each September, but less than a month later repealed the
    +# act," (page 220), that year-round daylight saving time was in effect
    +# from 1942-02-09 to 1945-09-30 (page 221, with no time of day given for
    +# when clocks changed) and that clocks were changed by 30 minutes
    +# effective the second Sunday of June, 1947 (page 219, with no time of
    +# day given for when clocks changed). A footnote for the 1933 changes
    +# cites Session Laws of Hawaii 1933, "Act. 90 (approved 26 Apr. 1933)
    +# and Act 163 (approved 21 May 1933)."
    +
    +# From Arthur David Olson (2011-01-19):
    +# The following is from "Laws of the Territory of Hawaii Passed by the
    +# Seventeenth Legislature: Regular Session 1933," available (as of
    +# 2011-01-19) at American University's Pence Law Library. Page 85: "Act
    +# 90...At 2 o'clock ante meridian of the last Sunday in April of each
    +# year, the standard time of this Territory shall be advanced one
    +# hour...This Act shall take effect upon its approval. Approved this 26th
    +# day of April, A. D. 1933. LAWRENCE M JUDD, Governor of the Territory of
    +# Hawaii." Page 172:  "Act 163...Act 90 of the Session Laws of 1933 is
    +# hereby repealed...This Act shall take effect upon its approval, upon
    +# which date the standard time of this Territory shall be restored to
    +# that existing immediately prior to the taking effect of said Act 90.
    +# Approved this 21st day of May, A. D. 1933. LAWRENCE M. JUDD, Governor
    +# of the Territory of Hawaii."
    +#
    +# Note that 1933-05-21 was a Sunday.
    +# We're left to guess the time of day when Act 163 was approved; guess noon.
    +
    +Zone Pacific/Honolulu	-10:31:26 -	LMT	1896 Jan 13 12:00 #Schmitt&Cox
    +			-10:30	-	HST	1933 Apr 30 2:00 #Laws 1933
    +			-10:30	1:00	HDT	1933 May 21 12:00 #Laws 1933+12
    +			-10:30	-	HST	1942 Feb 09 2:00 #Schmitt&Cox+2
    +			-10:30	1:00	HDT	1945 Sep 30 2:00 #Schmitt&Cox+2
    +			-10:30	-	HST	1947 Jun  8 2:00 #Schmitt&Cox+2
    +			-10:00	-	HST
    +
    +# Now we turn to US areas that have diverged from the consensus since 1970.
    +
    +# Arizona mostly uses MST.
    +
    +# From Paul Eggert (2002-10-20):
    +#
    +# The information in the rest of this paragraph is derived from the
    +# 
    +# Daylight Saving Time web page (2002-01-23) maintained by the
    +# Arizona State Library, Archives and Public Records.
    +# Between 1944-01-01 and 1944-04-01 the State of Arizona used standard
    +# time, but by federal law railroads, airlines, bus lines, military
    +# personnel, and some engaged in interstate commerce continued to
    +# observe war (i.e., daylight saving) time.  The 1944-03-17 Phoenix
    +# Gazette says that was the date the law changed, and that 04-01 was
    +# the date the state's clocks would change.  In 1945 the State of
    +# Arizona used standard time all year, again with exceptions only as
    +# mandated by federal law.  Arizona observed DST in 1967, but Arizona
    +# Laws 1968, ch. 183 (effective 1968-03-21) repealed DST.
    +#
    +# Shanks says the 1944 experiment came to an end on 1944-03-17.
    +# Go with the Arizona State Library instead.
    +
    +Zone America/Phoenix	-7:28:18 -	LMT	1883 Nov 18 11:31:42
    +			-7:00	US	M%sT	1944 Jan  1 00:01
    +			-7:00	-	MST	1944 Apr  1 00:01
    +			-7:00	US	M%sT	1944 Oct  1 00:01
    +			-7:00	-	MST	1967
    +			-7:00	US	M%sT	1968 Mar 21
    +			-7:00	-	MST
    +# From Arthur David Olson (1988-02-13):
    +# A writer from the Inter Tribal Council of Arizona, Inc.,
    +# notes in private correspondence dated 1987-12-28 that "Presently, only the
    +# Navajo Nation participates in the Daylight Saving Time policy, due to its
    +# large size and location in three states."  (The "only" means that other
    +# tribal nations don't use DST.)
    +
    +Link America/Denver America/Shiprock
    +
    +# Southern Idaho (Ada, Adams, Bannock, Bear Lake, Bingham, Blaine,
    +# Boise, Bonneville, Butte, Camas, Canyon, Caribou, Cassia, Clark,
    +# Custer, Elmore, Franklin, Fremont, Gem, Gooding, Jefferson, Jerome,
    +# Lemhi, Lincoln, Madison, Minidoka, Oneida, Owyhee, Payette, Power,
    +# Teton, Twin Falls, Valley, Washington counties, and the southern
    +# quarter of Idaho county) and eastern Oregon (most of Malheur County)
    +# switched four weeks late in 1974.
    +#
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Boise	-7:44:49 -	LMT	1883 Nov 18 12:15:11
    +			-8:00	US	P%sT	1923 May 13 2:00
    +			-7:00	US	M%sT	1974
    +			-7:00	-	MST	1974 Feb  3 2:00
    +			-7:00	US	M%sT
    +
    +# Indiana
    +#
    +# For a map of Indiana's time zone regions, see:
    +# 
    +# What time is it in Indiana?
    +#  (2006-03-01)
    +#
    +# From Paul Eggert (2007-08-17):
    +# Since 1970, most of Indiana has been like America/Indiana/Indianapolis,
    +# with the following exceptions:
    +#
    +# - Gibson, Jasper, Lake, LaPorte, Newton, Porter, Posey, Spencer,
    +#   Vandenburgh, and Warrick counties have been like America/Chicago.
    +#
    +# - Dearborn and Ohio counties have been like America/New_York.
    +#
    +# - Clark, Floyd, and Harrison counties have been like
    +#   America/Kentucky/Louisville.
    +#
    +# - Crawford, Daviess, Dubois, Knox, Martin, Perry, Pike, Pulaski, Starke,
    +#   and Switzerland counties have their own time zone histories as noted below.
    +#
    +# Shanks partitioned Indiana into 345 regions, each with its own time history,
    +# and wrote ``Even newspaper reports present contradictory information.''
    +# Those Hoosiers!  Such a flighty and changeable people!
    +# Fortunately, most of the complexity occurred before our cutoff date of 1970.
    +#
    +# Other than Indianapolis, the Indiana place names are so nondescript
    +# that they would be ambiguous if we left them at the `America' level.
    +# So we reluctantly put them all in a subdirectory `America/Indiana'.
    +
    +# From Paul Eggert (2005-08-16):
    +# http://www.mccsc.edu/time.html says that Indiana will use DST starting 2006.
    +
    +# From Nathan Stratton Treadway (2006-03-30):
    +# http://www.dot.gov/affairs/dot0406.htm [3705 B]
    +# From Deborah Goldsmith (2006-01-18):
    +# http://dmses.dot.gov/docimages/pdf95/382329_web.pdf [2.9 MB]
    +# From Paul Eggert (2006-01-20):
    +# It says "DOT is relocating the time zone boundary in Indiana to move Starke,
    +# Pulaski, Knox, Daviess, Martin, Pike, Dubois, and Perry Counties from the
    +# Eastern Time Zone to the Central Time Zone.... The effective date of
    +# this rule is 2:OO a.m. EST Sunday, April 2, 2006, which is the
    +# changeover date from standard time to Daylight Saving Time."
    +# Strictly speaking, this means the affected counties will change their
    +# clocks twice that night, but this obviously is in error.  The intent
    +# is that 01:59:59 EST be followed by 02:00:00 CDT.
    +
    +# From Gwillim Law (2007-02-10):
    +# The Associated Press has been reporting that Pulaski County, Indiana is
    +# going to switch from Central to Eastern Time on March 11, 2007....
    +# http://www.indystar.com/apps/pbcs.dll/article?AID=/20070207/LOCAL190108/702070524/0/LOCAL
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule Indianapolis 1941	only	-	Jun	22	2:00	1:00	D
    +Rule Indianapolis 1941	1954	-	Sep	lastSun	2:00	0	S
    +Rule Indianapolis 1946	1954	-	Apr	lastSun	2:00	1:00	D
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Indiana/Indianapolis -5:44:38 - LMT 1883 Nov 18 12:15:22
    +			-6:00	US	C%sT	1920
    +			-6:00 Indianapolis C%sT	1942
    +			-6:00	US	C%sT	1946
    +			-6:00 Indianapolis C%sT	1955 Apr 24 2:00
    +			-5:00	-	EST	1957 Sep 29 2:00
    +			-6:00	-	CST	1958 Apr 27 2:00
    +			-5:00	-	EST	1969
    +			-5:00	US	E%sT	1971
    +			-5:00	-	EST	2006
    +			-5:00	US	E%sT
    +#
    +# Eastern Crawford County, Indiana, left its clocks alone in 1974,
    +# as well as from 1976 through 2005.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule	Marengo	1951	only	-	Apr	lastSun	2:00	1:00	D
    +Rule	Marengo	1951	only	-	Sep	lastSun	2:00	0	S
    +Rule	Marengo	1954	1960	-	Apr	lastSun	2:00	1:00	D
    +Rule	Marengo	1954	1960	-	Sep	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Indiana/Marengo -5:45:23 -	LMT	1883 Nov 18 12:14:37
    +			-6:00	US	C%sT	1951
    +			-6:00	Marengo	C%sT	1961 Apr 30 2:00
    +			-5:00	-	EST	1969
    +			-5:00	US	E%sT	1974 Jan  6 2:00
    +			-6:00	1:00	CDT	1974 Oct 27 2:00
    +			-5:00	US	E%sT	1976
    +			-5:00	-	EST	2006
    +			-5:00	US	E%sT
    +#
    +# Daviess, Dubois, Knox, and Martin Counties, Indiana,
    +# switched from eastern to central time in April 2006, then switched back
    +# in November 2007.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule Vincennes	1946	only	-	Apr	lastSun	2:00	1:00	D
    +Rule Vincennes	1946	only	-	Sep	lastSun	2:00	0	S
    +Rule Vincennes	1953	1954	-	Apr	lastSun	2:00	1:00	D
    +Rule Vincennes	1953	1959	-	Sep	lastSun	2:00	0	S
    +Rule Vincennes	1955	only	-	May	 1	0:00	1:00	D
    +Rule Vincennes	1956	1963	-	Apr	lastSun	2:00	1:00	D
    +Rule Vincennes	1960	only	-	Oct	lastSun	2:00	0	S
    +Rule Vincennes	1961	only	-	Sep	lastSun	2:00	0	S
    +Rule Vincennes	1962	1963	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Indiana/Vincennes -5:50:07 - LMT	1883 Nov 18 12:09:53
    +			-6:00	US	C%sT	1946
    +			-6:00 Vincennes	C%sT	1964 Apr 26 2:00
    +			-5:00	-	EST	1969
    +			-5:00	US	E%sT	1971
    +			-5:00	-	EST	2006 Apr  2 2:00
    +			-6:00	US	C%sT	2007 Nov  4 2:00
    +			-5:00	US	E%sT
    +#
    +# Perry County, Indiana, switched from eastern to central time in April 2006.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule Perry	1946	only	-	Apr	lastSun	2:00	1:00	D
    +Rule Perry	1946	only	-	Sep	lastSun	2:00	0	S
    +Rule Perry	1953	1954	-	Apr	lastSun	2:00	1:00	D
    +Rule Perry	1953	1959	-	Sep	lastSun	2:00	0	S
    +Rule Perry	1955	only	-	May	 1	0:00	1:00	D
    +Rule Perry	1956	1963	-	Apr	lastSun	2:00	1:00	D
    +Rule Perry	1960	only	-	Oct	lastSun	2:00	0	S
    +Rule Perry	1961	only	-	Sep	lastSun	2:00	0	S
    +Rule Perry	1962	1963	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Indiana/Tell_City -5:47:03 - LMT	1883 Nov 18 12:12:57
    +			-6:00	US	C%sT	1946
    +			-6:00 Perry	C%sT	1964 Apr 26 2:00
    +			-5:00	-	EST	1969
    +			-5:00	US	E%sT	1971
    +			-5:00	-	EST	2006 Apr  2 2:00
    +			-6:00	US	C%sT
    +#
    +# Pike County, Indiana moved from central to eastern time in 1977,
    +# then switched back in 2006, then switched back again in 2007.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule	Pike	1955	only	-	May	 1	0:00	1:00	D
    +Rule	Pike	1955	1960	-	Sep	lastSun	2:00	0	S
    +Rule	Pike	1956	1964	-	Apr	lastSun	2:00	1:00	D
    +Rule	Pike	1961	1964	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Indiana/Petersburg -5:49:07 - LMT	1883 Nov 18 12:10:53
    +			-6:00	US	C%sT	1955
    +			-6:00	Pike	C%sT	1965 Apr 25 2:00
    +			-5:00	-	EST	1966 Oct 30 2:00
    +			-6:00	US	C%sT	1977 Oct 30 2:00
    +			-5:00	-	EST	2006 Apr  2 2:00
    +			-6:00	US	C%sT	2007 Nov  4 2:00
    +			-5:00	US	E%sT
    +#
    +# Starke County, Indiana moved from central to eastern time in 1991,
    +# then switched back in 2006.
    +# From Arthur David Olson (1991-10-28):
    +# An article on page A3 of the Sunday, 1991-10-27 Washington Post
    +# notes that Starke County switched from Central time to Eastern time as of
    +# 1991-10-27.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule	Starke	1947	1961	-	Apr	lastSun	2:00	1:00	D
    +Rule	Starke	1947	1954	-	Sep	lastSun	2:00	0	S
    +Rule	Starke	1955	1956	-	Oct	lastSun	2:00	0	S
    +Rule	Starke	1957	1958	-	Sep	lastSun	2:00	0	S
    +Rule	Starke	1959	1961	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Indiana/Knox -5:46:30 -	LMT	1883 Nov 18 12:13:30
    +			-6:00	US	C%sT	1947
    +			-6:00	Starke	C%sT	1962 Apr 29 2:00
    +			-5:00	-	EST	1963 Oct 27 2:00
    +			-6:00	US	C%sT	1991 Oct 27 2:00
    +			-5:00	-	EST	2006 Apr  2 2:00
    +			-6:00	US	C%sT
    +#
    +# Pulaski County, Indiana, switched from eastern to central time in
    +# April 2006 and then switched back in March 2007.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule	Pulaski	1946	1960	-	Apr	lastSun	2:00	1:00	D
    +Rule	Pulaski	1946	1954	-	Sep	lastSun	2:00	0	S
    +Rule	Pulaski	1955	1956	-	Oct	lastSun	2:00	0	S
    +Rule	Pulaski	1957	1960	-	Sep	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Indiana/Winamac -5:46:25 - LMT	1883 Nov 18 12:13:35
    +			-6:00	US	C%sT	1946
    +			-6:00	Pulaski	C%sT	1961 Apr 30 2:00
    +			-5:00	-	EST	1969
    +			-5:00	US	E%sT	1971
    +			-5:00	-	EST	2006 Apr  2 2:00
    +			-6:00	US	C%sT	2007 Mar 11 2:00
    +			-5:00	US	E%sT
    +#
    +# Switzerland County, Indiana, did not observe DST from 1973 through 2005.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Indiana/Vevay -5:40:16 -	LMT	1883 Nov 18 12:19:44
    +			-6:00	US	C%sT	1954 Apr 25 2:00
    +			-5:00	-	EST	1969
    +			-5:00	US	E%sT	1973
    +			-5:00	-	EST	2006
    +			-5:00	US	E%sT
    +
    +# Part of Kentucky left its clocks alone in 1974.
    +# This also includes Clark, Floyd, and Harrison counties in Indiana.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule Louisville	1921	only	-	May	1	2:00	1:00	D
    +Rule Louisville	1921	only	-	Sep	1	2:00	0	S
    +Rule Louisville	1941	1961	-	Apr	lastSun	2:00	1:00	D
    +Rule Louisville	1941	only	-	Sep	lastSun	2:00	0	S
    +Rule Louisville	1946	only	-	Jun	2	2:00	0	S
    +Rule Louisville	1950	1955	-	Sep	lastSun	2:00	0	S
    +Rule Louisville	1956	1960	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Kentucky/Louisville -5:43:02 -	LMT	1883 Nov 18 12:16:58
    +			-6:00	US	C%sT	1921
    +			-6:00 Louisville C%sT	1942
    +			-6:00	US	C%sT	1946
    +			-6:00 Louisville C%sT	1961 Jul 23 2:00
    +			-5:00	-	EST	1968
    +			-5:00	US	E%sT	1974 Jan  6 2:00
    +			-6:00	1:00	CDT	1974 Oct 27 2:00
    +			-5:00	US	E%sT
    +#
    +# Wayne County, Kentucky
    +#
    +# From
    +# 
    +# Lake Cumberland LIFE
    +#  (1999-01-29) via WKYM-101.7:
    +# Clinton County has joined Wayne County in asking the DoT to change from
    +# the Central to the Eastern time zone....  The Wayne County government made
    +# the same request in December.  And while Russell County officials have not
    +# taken action, the majority of respondents to a poll conducted there in
    +# August indicated they would like to change to "fast time" also.
    +# The three Lake Cumberland counties are the farthest east of any U.S.
    +# location in the Central time zone.
    +#
    +# From Rich Wales (2000-08-29):
    +# After prolonged debate, and despite continuing deep differences of opinion,
    +# Wayne County (central Kentucky) is switching from Central (-0600) to Eastern
    +# (-0500) time.  They won't "fall back" this year.  See Sara Shipley,
    +# The difference an hour makes, Nando Times (2000-08-29 15:33 -0400).
    +#
    +# From Paul Eggert (2001-07-16):
    +# The final rule was published in the
    +# 
    +# Federal Register 65, 160 (2000-08-17), page 50154-50158.
    +# 
    +#
    +Zone America/Kentucky/Monticello -5:39:24 - LMT	1883 Nov 18 12:20:36
    +			-6:00	US	C%sT	1946
    +			-6:00	-	CST	1968
    +			-6:00	US	C%sT	2000 Oct 29  2:00
    +			-5:00	US	E%sT
    +
    +
    +# From Rives McDow (2000-08-30):
    +# Here ... are all the changes in the US since 1985.
    +# Kearny County, KS (put all of county on central;
    +#	previously split between MST and CST) ... 1990-10
    +# Starke County, IN (from CST to EST) ... 1991-10
    +# Oliver County, ND (from MST to CST) ... 1992-10
    +# West Wendover, NV (from PST TO MST) ... 1999-10
    +# Wayne County, KY (from CST to EST) ... 2000-10
    +#
    +# From Paul Eggert (2001-07-17):
    +# We don't know where the line used to be within Kearny County, KS,
    +# so omit that change for now.
    +# See America/Indiana/Knox for the Starke County, IN change.
    +# See America/North_Dakota/Center for the Oliver County, ND change.
    +# West Wendover, NV officially switched from Pacific to mountain time on
    +# 1999-10-31.  See the
    +# 
    +# Federal Register 64, 203 (1999-10-21), page 56705-56707.
    +# 
    +# However, the Federal Register says that West Wendover already operated
    +# on mountain time, and the rule merely made this official;
    +# hence a separate tz entry is not needed.
    +
    +# Michigan
    +#
    +# From Bob Devine (1988-01-28):
    +# Michigan didn't observe DST from 1968 to 1973.
    +#
    +# From Paul Eggert (1999-03-31):
    +# Shanks writes that Michigan started using standard time on 1885-09-18,
    +# but Howse writes (pp 124-125, referring to Popular Astronomy, 1901-01)
    +# that Detroit kept
    +#
    +#	local time until 1900 when the City Council decreed that clocks should
    +#	be put back twenty-eight minutes to Central Standard Time.  Half the
    +#	city obeyed, half refused.  After considerable debate, the decision
    +#	was rescinded and the city reverted to Sun time.  A derisive offer to
    +#	erect a sundial in front of the city hall was referred to the
    +#	Committee on Sewers.  Then, in 1905, Central time was adopted
    +#	by city vote.
    +#
    +# This story is too entertaining to be false, so go with Howse over Shanks.
    +#
    +# From Paul Eggert (2001-03-06):
    +# Garland (1927) writes ``Cleveland and Detroit advanced their clocks
    +# one hour in 1914.''  This change is not in Shanks.  We have no more
    +# info, so omit this for now.
    +#
    +# Most of Michigan observed DST from 1973 on, but was a bit late in 1975.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule	Detroit	1948	only	-	Apr	lastSun	2:00	1:00	D
    +Rule	Detroit	1948	only	-	Sep	lastSun	2:00	0	S
    +Rule	Detroit	1967	only	-	Jun	14	2:00	1:00	D
    +Rule	Detroit	1967	only	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Detroit	-5:32:11 -	LMT	1905
    +			-6:00	-	CST	1915 May 15 2:00
    +			-5:00	-	EST	1942
    +			-5:00	US	E%sT	1946
    +			-5:00	Detroit	E%sT	1973
    +			-5:00	US	E%sT	1975
    +			-5:00	-	EST	1975 Apr 27 2:00
    +			-5:00	US	E%sT
    +#
    +# Dickinson, Gogebic, Iron, and Menominee Counties, Michigan,
    +# switched from EST to CST/CDT in 1973.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER
    +Rule Menominee	1946	only	-	Apr	lastSun	2:00	1:00	D
    +Rule Menominee	1946	only	-	Sep	lastSun	2:00	0	S
    +Rule Menominee	1966	only	-	Apr	lastSun	2:00	1:00	D
    +Rule Menominee	1966	only	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Menominee	-5:50:27 -	LMT	1885 Sep 18 12:00
    +			-6:00	US	C%sT	1946
    +			-6:00 Menominee	C%sT	1969 Apr 27 2:00
    +			-5:00	-	EST	1973 Apr 29 2:00
    +			-6:00	US	C%sT
    +
    +# Navassa
    +# administered by the US Fish and Wildlife Service
    +# claimed by US under the provisions of the 1856 Guano Islands Act
    +# also claimed by Haiti
    +# occupied 1857/1900 by the Navassa Phosphate Co
    +# US lighthouse 1917/1996-09
    +# currently uninhabited
    +# see Mark Fineman, ``An Isle Rich in Guano and Discord'',
    +# _Los Angeles Times_ (1998-11-10), A1, A10; it cites
    +# Jimmy Skaggs, _The Great Guano Rush_ (1994).
    +
    +################################################################################
    +
    +
    +# From Paul Eggert (2006-03-22):
    +# A good source for time zone historical data outside the U.S. is
    +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
    +# San Diego: ACS Publications, Inc. (2003).
    +#
    +# Gwillim Law writes that a good source
    +# for recent time zone data is the International Air Transport
    +# Association's Standard Schedules Information Manual (IATA SSIM),
    +# published semiannually.  Law sent in several helpful summaries
    +# of the IATA's data after 1990.
    +#
    +# Except where otherwise noted, Shanks & Pottenger is the source for
    +# entries through 1990, and IATA SSIM is the source for entries afterwards.
    +#
    +# Other sources occasionally used include:
    +#
    +#	Edward W. Whitman, World Time Differences,
    +#	Whitman Publishing Co, 2 Niagara Av, Ealing, London (undated),
    +#	which I found in the UCLA library.
    +#
    +#	
    +#	William Willett, The Waste of Daylight, 19th edition
    +#	 (1914-03)
    +#
    +# See the `europe' file for Greenland.
    +
    +# Canada
    +
    +# From Alain LaBont (1994-11-14):
    +# I post here the time zone abbreviations standardized in Canada
    +# for both English and French in the CAN/CSA-Z234.4-89 standard....
    +#
    +#	UTC	Standard time	Daylight savings time
    +#	offset	French	English	French	English
    +#	-2:30	-	-	HAT	NDT
    +#	-3	-	-	HAA	ADT
    +#	-3:30	HNT	NST	-	-
    +#	-4	HNA	AST	HAE	EDT
    +#	-5	HNE	EST	HAC	CDT
    +#	-6	HNC	CST	HAR	MDT
    +#	-7	HNR	MST	HAP	PDT
    +#	-8	HNP	PST	HAY	YDT
    +#	-9	HNY	YST	-	-
    +#
    +#	HN: Heure Normale	ST: Standard Time
    +#	HA: Heure Avance	DT: Daylight saving Time
    +#
    +#	A: de l'Atlantique	Atlantic
    +#	C: du Centre		Central
    +#	E: de l'Est		Eastern
    +#	M:			Mountain
    +#	N:			Newfoundland
    +#	P: du Pacifique		Pacific
    +#	R: des Rocheuses
    +#	T: de Terre-Neuve
    +#	Y: du Yukon		Yukon
    +#
    +# From Paul Eggert (1994-11-22):
    +# Alas, this sort of thing must be handled by localization software.
    +
    +# Unless otherwise specified, the data for Canada are all from Shanks
    +# & Pottenger.
    +
    +# From Chris Walton (2006-04-01, 2006-04-25, 2006-06-26, 2007-01-31,
    +# 2007-03-01):
    +# The British Columbia government announced yesterday that it will
    +# adjust daylight savings next year to align with changes in the
    +# U.S. and the rest of Canada....
    +# http://www2.news.gov.bc.ca/news_releases_2005-2009/2006AG0014-000330.htm
    +# ...
    +# Nova Scotia
    +# Daylight saving time will be extended by four weeks starting in 2007....
    +# http://www.gov.ns.ca/just/regulations/rg2/2006/ma1206.pdf
    +#
    +# [For New Brunswick] the new legislation dictates that the time change is to
    +# be done at 02:00 instead of 00:01.
    +# http://www.gnb.ca/0062/acts/BBA-2006/Chap-19.pdf
    +# ...
    +# Manitoba has traditionally changed the clock every fall at 03:00.
    +# As of 2006, the transition is to take place one hour earlier at 02:00.
    +# http://web2.gov.mb.ca/laws/statutes/ccsm/o030e.php
    +# ...
    +# [Alberta, Ontario, Quebec] will follow US rules.
    +# http://www.qp.gov.ab.ca/documents/spring/CH03_06.CFM
    +# http://www.e-laws.gov.on.ca/DBLaws/Source/Regs/English/2006/R06111_e.htm
    +# http://www2.publicationsduquebec.gouv.qc.ca/dynamicSearch/telecharge.php?type=5&file=2006C39A.PDF
    +# ...
    +# P.E.I. will follow US rules....
    +# http://www.assembly.pe.ca/bills/pdf_chapter/62/3/chapter-41.pdf
    +# ...
    +# Province of Newfoundland and Labrador....
    +# http://www.hoa.gov.nl.ca/hoa/bills/Bill0634.htm
    +# ...
    +# Yukon
    +# http://www.gov.yk.ca/legislation/regs/oic2006_127.pdf
    +# ...
    +# N.W.T. will follow US rules.  Whoever maintains the government web site
    +# does not seem to believe in bookmarks.  To see the news release, click the
    +# following link and search for "Daylight Savings Time Change".  Press the
    +# "Daylight Savings Time Change" link; it will fire off a popup using
    +# JavaScript.
    +# http://www.exec.gov.nt.ca/currentnews/currentPR.asp?mode=archive
    +# ...
    +# Nunavut
    +# An amendment to the Interpretation Act was registered on February 19/2007....
    +# http://action.attavik.ca/home/justice-gn/attach/2007/gaz02part2.pdf
    +
    +# From Paul Eggert (2006-04-25):
    +# H. David Matthews and Mary Vincent's map
    +# 
    +# "It's about TIME", _Canadian Geographic_ (September-October 1998)
    +#  contains detailed boundaries for regions observing nonstandard
    +# time and daylight saving time arrangements in Canada circa 1998.
    +#
    +# INMS, the Institute for National Measurement Standards in Ottawa, has 
    +# information about standard and daylight saving time zones in Canada.
    +#  (updated periodically).
    +# Its unofficial information is often taken from Matthews and Vincent.
    +
    +# From Paul Eggert (2006-06-27):
    +# For now, assume all of DST-observing Canada will fall into line with the
    +# new US DST rules,
    +
    +# From Chris Walton (2011-12-01)
    +# In the first of Tammy Hardwick's articles
    +# 
    +# http://www.ilovecreston.com/?p=articles&t=spec&ar=260
    +# 
    +# she quotes the Friday November 1/1918 edition of the Creston Review.
    +# The quote includes these two statements:
    +# 'Sunday the CPR went back to the old system of time...'
    +# '... The daylight saving scheme was dropped all over Canada at the same time,'
    +# These statements refer to a transition from daylight time to standard time
    +# that occurred nationally on Sunday October 27/1918.  This transition was
    +# also documented in the Saturday October 26/1918 edition of the Toronto Star.
    +
    +# In light of that evidence, we alter the date from the earlier believed
    +# Oct 31, to Oct 27, 1918 (and Sunday is a more likely transition day
    +# than Thursday) in all Canadian rulesets.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Canada	1918	only	-	Apr	14	2:00	1:00	D
    +Rule	Canada	1918	only	-	Oct	27	2:00	0	S
    +Rule	Canada	1942	only	-	Feb	 9	2:00	1:00	W # War
    +Rule	Canada	1945	only	-	Aug	14	23:00u	1:00	P # Peace
    +Rule	Canada	1945	only	-	Sep	30	2:00	0	S
    +Rule	Canada	1974	1986	-	Apr	lastSun	2:00	1:00	D
    +Rule	Canada	1974	2006	-	Oct	lastSun	2:00	0	S
    +Rule	Canada	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
    +Rule	Canada	2007	max	-	Mar	Sun>=8	2:00	1:00	D
    +Rule	Canada	2007	max	-	Nov	Sun>=1	2:00	0	S
    +
    +
    +# Newfoundland and Labrador
    +
    +# From Paul Eggert (2000-10-02):
    +# Matthews and Vincent (1998) write that Labrador should use NST/NDT,
    +# but the only part of Labrador that follows the rules is the
    +# southeast corner, including Port Hope Simpson and Mary's Harbour,
    +# but excluding, say, Black Tickle.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	StJohns	1917	only	-	Apr	 8	2:00	1:00	D
    +Rule	StJohns	1917	only	-	Sep	17	2:00	0	S
    +# Whitman gives 1919 Apr 5 and 1920 Apr 5; go with Shanks & Pottenger.
    +Rule	StJohns	1919	only	-	May	 5	23:00	1:00	D
    +Rule	StJohns	1919	only	-	Aug	12	23:00	0	S
    +# For 1931-1935 Whitman gives Apr same date; go with Shanks & Pottenger.
    +Rule	StJohns	1920	1935	-	May	Sun>=1	23:00	1:00	D
    +Rule	StJohns	1920	1935	-	Oct	lastSun	23:00	0	S
    +# For 1936-1941 Whitman gives May Sun>=8 and Oct Sun>=1; go with Shanks &
    +# Pottenger.
    +Rule	StJohns	1936	1941	-	May	Mon>=9	0:00	1:00	D
    +Rule	StJohns	1936	1941	-	Oct	Mon>=2	0:00	0	S
    +# Whitman gives the following transitions:
    +# 1942 03-01/12-31, 1943 05-30/09-05, 1944 07-10/09-02, 1945 01-01/10-07
    +# but go with Shanks & Pottenger and assume they used Canadian rules.
    +# For 1946-9 Whitman gives May 5,4,9,1 - Oct 1,5,3,2, and for 1950 he gives
    +# Apr 30 - Sep 24; go with Shanks & Pottenger.
    +Rule	StJohns	1946	1950	-	May	Sun>=8	2:00	1:00	D
    +Rule	StJohns	1946	1950	-	Oct	Sun>=2	2:00	0	S
    +Rule	StJohns	1951	1986	-	Apr	lastSun	2:00	1:00	D
    +Rule	StJohns	1951	1959	-	Sep	lastSun	2:00	0	S
    +Rule	StJohns	1960	1986	-	Oct	lastSun	2:00	0	S
    +# From Paul Eggert (2000-10-02):
    +# INMS (2000-09-12) says that, since 1988 at least, Newfoundland switches
    +# at 00:01 local time.  For now, assume it started in 1987.
    +
    +# From Michael Pelley (2011-09-12):
    +# We received today, Monday, September 12, 2011, notification that the
    +# changes to the Newfoundland Standard Time Act have been proclaimed.
    +# The change in the Act stipulates that the change from Daylight Savings
    +# Time to Standard Time and from Standard Time to Daylight Savings Time
    +# now occurs at 2:00AM.
    +# ...
    +# 
    +# http://www.assembly.nl.ca/legislation/sr/annualstatutes/2011/1106.chp.htm
    +# 
    +# ...
    +# MICHAEL PELLEY  |  Manager of Enterprise Architecture - Solution Delivery
    +# Office of the Chief Information Officer
    +# Executive Council
    +# Government of Newfoundland & Labrador
    +
    +Rule	StJohns	1987	only	-	Apr	Sun>=1	0:01	1:00	D
    +Rule	StJohns	1987	2006	-	Oct	lastSun	0:01	0	S
    +Rule	StJohns	1988	only	-	Apr	Sun>=1	0:01	2:00	DD
    +Rule	StJohns	1989	2006	-	Apr	Sun>=1	0:01	1:00	D
    +Rule	StJohns	2007	2011	-	Mar	Sun>=8	0:01	1:00	D
    +Rule	StJohns	2007	2010	-	Nov	Sun>=1	0:01	0	S
    +#
    +# St John's has an apostrophe, but Posix file names can't have apostrophes.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/St_Johns	-3:30:52 -	LMT	1884
    +			-3:30:52 StJohns N%sT	1918
    +			-3:30:52 Canada	N%sT	1919
    +			-3:30:52 StJohns N%sT	1935 Mar 30
    +			-3:30	StJohns	N%sT	1942 May 11
    +			-3:30	Canada	N%sT	1946
    +			-3:30	StJohns	N%sT	2011 Nov
    +			-3:30	Canada	N%sT
    +
    +# most of east Labrador
    +
    +# The name `Happy Valley-Goose Bay' is too long; use `Goose Bay'.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Goose_Bay	-4:01:40 -	LMT	1884 # Happy Valley-Goose Bay
    +			-3:30:52 -	NST	1918
    +			-3:30:52 Canada N%sT	1919
    +			-3:30:52 -	NST	1935 Mar 30
    +			-3:30	-	NST	1936
    +			-3:30	StJohns	N%sT	1942 May 11
    +			-3:30	Canada	N%sT	1946
    +			-3:30	StJohns	N%sT	1966 Mar 15 2:00
    +			-4:00	StJohns	A%sT	2011 Nov
    +			-4:00	Canada	A%sT
    +
    +
    +# west Labrador, Nova Scotia, Prince Edward I
    +
    +# From Paul Eggert (2006-03-22):
    +# Shanks & Pottenger write that since 1970 most of this region has been like
    +# Halifax.  Many locales did not observe peacetime DST until 1972;
    +# Glace Bay, NS is the largest that we know of.
    +# Shanks & Pottenger also write that Liverpool, NS was the only town
    +# in Canada to observe DST in 1971 but not 1970; for now we'll assume
    +# this is a typo.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Halifax	1916	only	-	Apr	 1	0:00	1:00	D
    +Rule	Halifax	1916	only	-	Oct	 1	0:00	0	S
    +Rule	Halifax	1920	only	-	May	 9	0:00	1:00	D
    +Rule	Halifax	1920	only	-	Aug	29	0:00	0	S
    +Rule	Halifax	1921	only	-	May	 6	0:00	1:00	D
    +Rule	Halifax	1921	1922	-	Sep	 5	0:00	0	S
    +Rule	Halifax	1922	only	-	Apr	30	0:00	1:00	D
    +Rule	Halifax	1923	1925	-	May	Sun>=1	0:00	1:00	D
    +Rule	Halifax	1923	only	-	Sep	 4	0:00	0	S
    +Rule	Halifax	1924	only	-	Sep	15	0:00	0	S
    +Rule	Halifax	1925	only	-	Sep	28	0:00	0	S
    +Rule	Halifax	1926	only	-	May	16	0:00	1:00	D
    +Rule	Halifax	1926	only	-	Sep	13	0:00	0	S
    +Rule	Halifax	1927	only	-	May	 1	0:00	1:00	D
    +Rule	Halifax	1927	only	-	Sep	26	0:00	0	S
    +Rule	Halifax	1928	1931	-	May	Sun>=8	0:00	1:00	D
    +Rule	Halifax	1928	only	-	Sep	 9	0:00	0	S
    +Rule	Halifax	1929	only	-	Sep	 3	0:00	0	S
    +Rule	Halifax	1930	only	-	Sep	15	0:00	0	S
    +Rule	Halifax	1931	1932	-	Sep	Mon>=24	0:00	0	S
    +Rule	Halifax	1932	only	-	May	 1	0:00	1:00	D
    +Rule	Halifax	1933	only	-	Apr	30	0:00	1:00	D
    +Rule	Halifax	1933	only	-	Oct	 2	0:00	0	S
    +Rule	Halifax	1934	only	-	May	20	0:00	1:00	D
    +Rule	Halifax	1934	only	-	Sep	16	0:00	0	S
    +Rule	Halifax	1935	only	-	Jun	 2	0:00	1:00	D
    +Rule	Halifax	1935	only	-	Sep	30	0:00	0	S
    +Rule	Halifax	1936	only	-	Jun	 1	0:00	1:00	D
    +Rule	Halifax	1936	only	-	Sep	14	0:00	0	S
    +Rule	Halifax	1937	1938	-	May	Sun>=1	0:00	1:00	D
    +Rule	Halifax	1937	1941	-	Sep	Mon>=24	0:00	0	S
    +Rule	Halifax	1939	only	-	May	28	0:00	1:00	D
    +Rule	Halifax	1940	1941	-	May	Sun>=1	0:00	1:00	D
    +Rule	Halifax	1946	1949	-	Apr	lastSun	2:00	1:00	D
    +Rule	Halifax	1946	1949	-	Sep	lastSun	2:00	0	S
    +Rule	Halifax	1951	1954	-	Apr	lastSun	2:00	1:00	D
    +Rule	Halifax	1951	1954	-	Sep	lastSun	2:00	0	S
    +Rule	Halifax	1956	1959	-	Apr	lastSun	2:00	1:00	D
    +Rule	Halifax	1956	1959	-	Sep	lastSun	2:00	0	S
    +Rule	Halifax	1962	1973	-	Apr	lastSun	2:00	1:00	D
    +Rule	Halifax	1962	1973	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Halifax	-4:14:24 -	LMT	1902 Jun 15
    +			-4:00	Halifax	A%sT	1918
    +			-4:00	Canada	A%sT	1919
    +			-4:00	Halifax	A%sT	1942 Feb  9 2:00s
    +			-4:00	Canada	A%sT	1946
    +			-4:00	Halifax	A%sT	1974
    +			-4:00	Canada	A%sT
    +Zone America/Glace_Bay	-3:59:48 -	LMT	1902 Jun 15
    +			-4:00	Canada	A%sT	1953
    +			-4:00	Halifax	A%sT	1954
    +			-4:00	-	AST	1972
    +			-4:00	Halifax	A%sT	1974
    +			-4:00	Canada	A%sT
    +
    +# New Brunswick
    +
    +# From Paul Eggert (2007-01-31):
    +# The Time Definition Act 
    +# says they changed at 00:01 through 2006, and
    +#  makes it
    +# clear that this was the case since at least 1993.
    +# For now, assume it started in 1993.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Moncton	1933	1935	-	Jun	Sun>=8	1:00	1:00	D
    +Rule	Moncton	1933	1935	-	Sep	Sun>=8	1:00	0	S
    +Rule	Moncton	1936	1938	-	Jun	Sun>=1	1:00	1:00	D
    +Rule	Moncton	1936	1938	-	Sep	Sun>=1	1:00	0	S
    +Rule	Moncton	1939	only	-	May	27	1:00	1:00	D
    +Rule	Moncton	1939	1941	-	Sep	Sat>=21	1:00	0	S
    +Rule	Moncton	1940	only	-	May	19	1:00	1:00	D
    +Rule	Moncton	1941	only	-	May	 4	1:00	1:00	D
    +Rule	Moncton	1946	1972	-	Apr	lastSun	2:00	1:00	D
    +Rule	Moncton	1946	1956	-	Sep	lastSun	2:00	0	S
    +Rule	Moncton	1957	1972	-	Oct	lastSun	2:00	0	S
    +Rule	Moncton	1993	2006	-	Apr	Sun>=1	0:01	1:00	D
    +Rule	Moncton	1993	2006	-	Oct	lastSun	0:01	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Moncton	-4:19:08 -	LMT	1883 Dec  9
    +			-5:00	-	EST	1902 Jun 15
    +			-4:00	Canada	A%sT	1933
    +			-4:00	Moncton	A%sT	1942
    +			-4:00	Canada	A%sT	1946
    +			-4:00	Moncton	A%sT	1973
    +			-4:00	Canada	A%sT	1993
    +			-4:00	Moncton	A%sT	2007
    +			-4:00	Canada	A%sT
    +
    +# Quebec
    +
    +# From Paul Eggert (2006-07-09):
    +# Shanks & Pottenger write that since 1970 most of Quebec has been
    +# like Montreal.
    +
    +# From Paul Eggert (2006-06-27):
    +# Matthews and Vincent (1998) also write that Quebec east of the -63
    +# meridian is supposed to observe AST, but residents as far east as
    +# Natashquan use EST/EDT, and residents east of Natashquan use AST.
    +# In "Official time in Quebec" the Quebec department of justice writes in
    +# http://www.justice.gouv.qc.ca/english/publications/generale/temps-regl-1-a.htm
    +# that "The residents of the Municipality of the
    +# Cote-Nord-du-Golfe-Saint-Laurent and the municipalities of Saint-Augustin,
    +# Bonne-Esperance and Blanc-Sablon apply the Official Time Act as it is
    +# written and use Atlantic standard time all year round. The same applies to
    +# the residents of the Native facilities along the lower North Shore."
    +# 
    +# says this common practice was codified into law as of 2007.
    +# For lack of better info, guess this practice began around 1970, contra to
    +# Shanks & Pottenger who have this region observing AST/ADT.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Mont	1917	only	-	Mar	25	2:00	1:00	D
    +Rule	Mont	1917	only	-	Apr	24	0:00	0	S
    +Rule	Mont	1919	only	-	Mar	31	2:30	1:00	D
    +Rule	Mont	1919	only	-	Oct	25	2:30	0	S
    +Rule	Mont	1920	only	-	May	 2	2:30	1:00	D
    +Rule	Mont	1920	1922	-	Oct	Sun>=1	2:30	0	S
    +Rule	Mont	1921	only	-	May	 1	2:00	1:00	D
    +Rule	Mont	1922	only	-	Apr	30	2:00	1:00	D
    +Rule	Mont	1924	only	-	May	17	2:00	1:00	D
    +Rule	Mont	1924	1926	-	Sep	lastSun	2:30	0	S
    +Rule	Mont	1925	1926	-	May	Sun>=1	2:00	1:00	D
    +# The 1927-to-1937 rules can be expressed more simply as
    +# Rule	Mont	1927	1937	-	Apr	lastSat	24:00	1:00	D
    +# Rule	Mont	1927	1937	-	Sep	lastSat	24:00	0	S
    +# The rules below avoid use of 24:00
    +# (which pre-1998 versions of zic cannot handle).
    +Rule	Mont	1927	only	-	May	1	0:00	1:00	D
    +Rule	Mont	1927	1932	-	Sep	lastSun	0:00	0	S
    +Rule	Mont	1928	1931	-	Apr	lastSun	0:00	1:00	D
    +Rule	Mont	1932	only	-	May	1	0:00	1:00	D
    +Rule	Mont	1933	1940	-	Apr	lastSun	0:00	1:00	D
    +Rule	Mont	1933	only	-	Oct	1	0:00	0	S
    +Rule	Mont	1934	1939	-	Sep	lastSun	0:00	0	S
    +Rule	Mont	1946	1973	-	Apr	lastSun	2:00	1:00	D
    +Rule	Mont	1945	1948	-	Sep	lastSun	2:00	0	S
    +Rule	Mont	1949	1950	-	Oct	lastSun	2:00	0	S
    +Rule	Mont	1951	1956	-	Sep	lastSun	2:00	0	S
    +Rule	Mont	1957	1973	-	Oct	lastSun	2:00	0	S
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Blanc-Sablon -3:48:28 -	LMT	1884
    +			-4:00	Canada	A%sT	1970
    +			-4:00	-	AST
    +Zone America/Montreal	-4:54:16 -	LMT	1884
    +			-5:00	Mont	E%sT	1918
    +			-5:00	Canada	E%sT	1919
    +			-5:00	Mont	E%sT	1942 Feb  9 2:00s
    +			-5:00	Canada	E%sT	1946
    +			-5:00	Mont	E%sT	1974
    +			-5:00	Canada	E%sT
    +
    +
    +# Ontario
    +
    +# From Paul Eggert (2006-07-09):
    +# Shanks & Pottenger write that since 1970 most of Ontario has been like
    +# Toronto.
    +# Thunder Bay skipped DST in 1973.
    +# Many smaller locales did not observe peacetime DST until 1974;
    +# Nipigon (EST) and Rainy River (CST) are the largest that we know of.
    +# Far west Ontario is like Winnipeg; far east Quebec is like Halifax.
    +
    +# From Mark Brader (2003-07-26):
    +# [According to the Toronto Star] Orillia, Ontario, adopted DST
    +# effective Saturday, 1912-06-22, 22:00; the article mentions that
    +# Port Arthur (now part of Thunder Bay, Ontario) as well as Moose Jaw
    +# have already done so.  In Orillia DST was to run until Saturday,
    +# 1912-08-31 (no time mentioned), but it was met with considerable
    +# hostility from certain segments of the public, and was revoked after
    +# only two weeks -- I copied it as Saturday, 1912-07-07, 22:00, but
    +# presumably that should be -07-06.  (1912-06-19, -07-12; also letters
    +# earlier in June).
    +#
    +# Kenora, Ontario, was to abandon DST on 1914-06-01 (-05-21).
    +
    +# From Paul Eggert (1997-10-17):
    +# Mark Brader writes that an article in the 1997-10-14 Toronto Star
    +# says that Atikokan, Ontario currently does not observe DST,
    +# but will vote on 11-10 whether to use EST/EDT.
    +# He also writes that the
    +# 
    +# Ontario Time Act (1990, Chapter T.9)
    +# 
    +# says that Ontario east of 90W uses EST/EDT, and west of 90W uses CST/CDT.
    +# Officially Atikokan is therefore on CST/CDT, and most likely this report
    +# concerns a non-official time observed as a matter of local practice.
    +#
    +# From Paul Eggert (2000-10-02):
    +# Matthews and Vincent (1998) write that Atikokan, Pickle Lake, and
    +# New Osnaburgh observe CST all year, that Big Trout Lake observes
    +# CST/CDT, and that Upsala and Shebandowan observe EST/EDT, all in
    +# violation of the official Ontario rules.
    +#
    +# From Paul Eggert (2006-07-09):
    +# Chris Walton (2006-07-06) mentioned an article by Stephanie MacLellan in the
    +# 2005-07-21 Chronicle-Journal, which said:
    +#
    +#	The clocks in Atikokan stay set on standard time year-round.
    +#	This means they spend about half the time on central time and
    +#	the other half on eastern time.
    +#
    +#	For the most part, the system works, Mayor Dennis Brown said.
    +#
    +#	"The majority of businesses in Atikokan deal more with Eastern
    +#	Canada, but there are some that deal with Western Canada," he
    +#	said.  "I don't see any changes happening here."
    +#
    +# Walton also writes "Supposedly Pickle Lake and Mishkeegogamang
    +# [New Osnaburgh] follow the same practice."
    +
    +# From Garry McKinnon (2006-07-14) via Chris Walton:
    +# I chatted with a member of my board who has an outstanding memory
    +# and a long history in Atikokan (and in the telecom industry) and he
    +# can say for certain that Atikokan has been practicing the current
    +# time keeping since 1952, at least.
    +
    +# From Paul Eggert (2006-07-17):
    +# Shanks & Pottenger say that Atikokan has agreed with Rainy River
    +# ever since standard time was introduced, but the information from
    +# McKinnon sounds more authoritative.  For now, assume that Atikokan
    +# switched to EST immediately after WWII era daylight saving time
    +# ended.  This matches the old (less-populous) America/Coral_Harbour
    +# entry since our cutoff date of 1970, so we can move
    +# America/Coral_Harbour to the 'backward' file.
    +
    +# From Mark Brader (2010-03-06):
    +#
    +# Currently the database has:
    +#
    +# # Ontario
    +#
    +# # From Paul Eggert (2006-07-09):
    +# # Shanks & Pottenger write that since 1970 most of Ontario has been like
    +# # Toronto.
    +# # Thunder Bay skipped DST in 1973.
    +# # Many smaller locales did not observe peacetime DST until 1974;
    +# # Nipigon (EST) and Rainy River (CST) are the largest that we know of.
    +#
    +# In the (Toronto) Globe and Mail for Saturday, 1955-09-24, in the bottom
    +# right corner of page 1, it says that Toronto will return to standard
    +# time at 2 am Sunday morning (which agrees with the database), and that:
    +#
    +#     The one-hour setback will go into effect throughout most of Ontario,
    +#     except in areas like Windsor which remains on standard time all year.
    +#
    +# Windsor is, of course, a lot larger than Nipigon.
    +#
    +# I only came across this incidentally.  I don't know if Windsor began
    +# observing DST when Detroit did, or in 1974, or on some other date.
    +#
    +# By the way, the article continues by noting that:
    +#
    +#     Some cities in the United States have pushed the deadline back
    +#     three weeks and will change over from daylight saving in October.
    +
    +# From Arthur David Olson (2010-07-17):
    +#
    +# "Standard Time and Time Zones in Canada" appeared in
    +# The Journal of The Royal Astronomical Society of Canada,
    +# volume 26, number 2 (February 1932) and, as of 2010-07-17,
    +# was available at
    +# 
    +# http://adsabs.harvard.edu/full/1932JRASC..26...49S
    +# 
    +#
    +# It includes the text below (starting on page 57):
    +#
    +#   A list of the places in Canada using daylight saving time would
    +# require yearly revision. From information kindly furnished by
    +# the provincial governments and by the postmasters in many cities
    +# and towns, it is found that the following places used daylight sav-
    +# ing in 1930. The information for the province of Quebec is definite,
    +# for the other provinces only approximate:
    +#
    +# 	Province	Daylight saving time used
    +# Prince Edward Island	Not used.
    +# Nova Scotia		In Halifax only.
    +# New Brunswick		In St. John only.
    +# Quebec		In the following places:
    +# 			Montreal	Lachine
    +# 			Quebec		Mont-Royal
    +# 			Levis		Iberville
    +# 			St. Lambert	Cap de la Madeleine
    +# 			Verdun		Loretteville
    +# 			Westmount	Richmond
    +# 			Outremont	St. Jerome
    +# 			Longueuil	Greenfield Park
    +# 			Arvida		Waterloo
    +# 			Chambly-Canton	Beaulieu
    +# 			Melbourne	La Tuque
    +# 			St. Theophile	Buckingham
    +# Ontario		Used generally in the cities and towns along
    +# 			the southerly part of the province. Not
    +# 			used in the northwesterlhy part.
    +# Manitoba		Not used.
    +# Saskatchewan		In Regina only.
    +# Alberta		Not used.
    +# British Columbia	Not used.
    +#
    +#   With some exceptions, the use of daylight saving may be said to be limited
    +# to those cities and towns lying between Quebec city and Windsor, Ont.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Toronto	1919	only	-	Mar	30	23:30	1:00	D
    +Rule	Toronto	1919	only	-	Oct	26	0:00	0	S
    +Rule	Toronto	1920	only	-	May	 2	2:00	1:00	D
    +Rule	Toronto	1920	only	-	Sep	26	0:00	0	S
    +Rule	Toronto	1921	only	-	May	15	2:00	1:00	D
    +Rule	Toronto	1921	only	-	Sep	15	2:00	0	S
    +Rule	Toronto	1922	1923	-	May	Sun>=8	2:00	1:00	D
    +# Shanks & Pottenger say 1923-09-19; assume it's a typo and that "-16"
    +# was meant.
    +Rule	Toronto	1922	1926	-	Sep	Sun>=15	2:00	0	S
    +Rule	Toronto	1924	1927	-	May	Sun>=1	2:00	1:00	D
    +# The 1927-to-1939 rules can be expressed more simply as
    +# Rule	Toronto	1927	1937	-	Sep	Sun>=25	2:00	0	S
    +# Rule	Toronto	1928	1937	-	Apr	Sun>=25	2:00	1:00	D
    +# Rule	Toronto	1938	1940	-	Apr	lastSun	2:00	1:00	D
    +# Rule	Toronto	1938	1939	-	Sep	lastSun	2:00	0	S
    +# The rules below avoid use of Sun>=25
    +# (which pre-2004 versions of zic cannot handle).
    +Rule	Toronto	1927	1932	-	Sep	lastSun	2:00	0	S
    +Rule	Toronto	1928	1931	-	Apr	lastSun	2:00	1:00	D
    +Rule	Toronto	1932	only	-	May	1	2:00	1:00	D
    +Rule	Toronto	1933	1940	-	Apr	lastSun	2:00	1:00	D
    +Rule	Toronto	1933	only	-	Oct	1	2:00	0	S
    +Rule	Toronto	1934	1939	-	Sep	lastSun	2:00	0	S
    +Rule	Toronto	1945	1946	-	Sep	lastSun	2:00	0	S
    +Rule	Toronto	1946	only	-	Apr	lastSun	2:00	1:00	D
    +Rule	Toronto	1947	1949	-	Apr	lastSun	0:00	1:00	D
    +Rule	Toronto	1947	1948	-	Sep	lastSun	0:00	0	S
    +Rule	Toronto	1949	only	-	Nov	lastSun	0:00	0	S
    +Rule	Toronto	1950	1973	-	Apr	lastSun	2:00	1:00	D
    +Rule	Toronto	1950	only	-	Nov	lastSun	2:00	0	S
    +Rule	Toronto	1951	1956	-	Sep	lastSun	2:00	0	S
    +# Shanks & Pottenger say Toronto ended DST a week early in 1971,
    +# namely on 1971-10-24, but Mark Brader wrote (2003-05-31) that this
    +# is wrong, and that he had confirmed it by checking the 1971-10-30
    +# Toronto Star, which said that DST was ending 1971-10-31 as usual.
    +Rule	Toronto	1957	1973	-	Oct	lastSun	2:00	0	S
    +
    +# From Paul Eggert (2003-07-27):
    +# Willett (1914-03) writes (p. 17) "In the Cities of Fort William, and
    +# Port Arthur, Ontario, the principle of the Bill has been in
    +# operation for the past three years, and in the City of Moose Jaw,
    +# Saskatchewan, for one year."
    +
    +# From David Bryan via Tory Tronrud, Director/Curator,
    +# Thunder Bay Museum (2003-11-12):
    +# There is some suggestion, however, that, by-law or not, daylight
    +# savings time was being practiced in Fort William and Port Arthur
    +# before 1909.... [I]n 1910, the line between the Eastern and Central
    +# Time Zones was permanently moved about two hundred miles west to
    +# include the Thunder Bay area....  When Canada adopted daylight
    +# savings time in 1916, Fort William and Port Arthur, having done so
    +# already, did not change their clocks....  During the Second World
    +# War,... [t]he cities agreed to implement DST during the summer
    +# months for the remainder of the war years.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Toronto	-5:17:32 -	LMT	1895
    +			-5:00	Canada	E%sT	1919
    +			-5:00	Toronto	E%sT	1942 Feb  9 2:00s
    +			-5:00	Canada	E%sT	1946
    +			-5:00	Toronto	E%sT	1974
    +			-5:00	Canada	E%sT
    +Zone America/Thunder_Bay -5:57:00 -	LMT	1895
    +			-6:00	-	CST	1910
    +			-5:00	-	EST	1942
    +			-5:00	Canada	E%sT	1970
    +			-5:00	Mont	E%sT	1973
    +			-5:00	-	EST	1974
    +			-5:00	Canada	E%sT
    +Zone America/Nipigon	-5:53:04 -	LMT	1895
    +			-5:00	Canada	E%sT	1940 Sep 29
    +			-5:00	1:00	EDT	1942 Feb  9 2:00s
    +			-5:00	Canada	E%sT
    +Zone America/Rainy_River -6:18:16 -	LMT	1895
    +			-6:00	Canada	C%sT	1940 Sep 29
    +			-6:00	1:00	CDT	1942 Feb  9 2:00s
    +			-6:00	Canada	C%sT
    +Zone America/Atikokan	-6:06:28 -	LMT	1895
    +			-6:00	Canada	C%sT	1940 Sep 29
    +			-6:00	1:00	CDT	1942 Feb  9 2:00s
    +			-6:00	Canada	C%sT	1945 Sep 30 2:00
    +			-5:00	-	EST
    +
    +
    +# Manitoba
    +
    +# From Rob Douglas (2006-04-06):
    +# the old Manitoba Time Act - as amended by Bill 2, assented to
    +# March 27, 1987 ... said ...
    +# "between two o'clock Central Standard Time in the morning of
    +# the first Sunday of April of each year and two o'clock Central
    +# Standard Time in the morning of the last Sunday of October next
    +# following, one hour in advance of Central Standard Time."...
    +# I believe that the English legislation [of the old time act] had =
    +# been assented to (March 22, 1967)....
    +# Also, as far as I can tell, there was no order-in-council varying
    +# the time of Daylight Saving Time for 2005 and so the provisions of
    +# the 1987 version would apply - the changeover was at 2:00 Central
    +# Standard Time (i.e. not until 3:00 Central Daylight Time).
    +
    +# From Paul Eggert (2006-04-10):
    +# Shanks & Pottenger say Manitoba switched at 02:00 (not 02:00s)
    +# starting 1966.  Since 02:00s is clearly correct for 1967 on, assume
    +# it was also 02:00s in 1966.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Winn	1916	only	-	Apr	23	0:00	1:00	D
    +Rule	Winn	1916	only	-	Sep	17	0:00	0	S
    +Rule	Winn	1918	only	-	Apr	14	2:00	1:00	D
    +Rule	Winn	1918	only	-	Oct	27	2:00	0	S
    +Rule	Winn	1937	only	-	May	16	2:00	1:00	D
    +Rule	Winn	1937	only	-	Sep	26	2:00	0	S
    +Rule	Winn	1942	only	-	Feb	 9	2:00	1:00	W # War
    +Rule	Winn	1945	only	-	Aug	14	23:00u	1:00	P # Peace
    +Rule	Winn	1945	only	-	Sep	lastSun	2:00	0	S
    +Rule	Winn	1946	only	-	May	12	2:00	1:00	D
    +Rule	Winn	1946	only	-	Oct	13	2:00	0	S
    +Rule	Winn	1947	1949	-	Apr	lastSun	2:00	1:00	D
    +Rule	Winn	1947	1949	-	Sep	lastSun	2:00	0	S
    +Rule	Winn	1950	only	-	May	 1	2:00	1:00	D
    +Rule	Winn	1950	only	-	Sep	30	2:00	0	S
    +Rule	Winn	1951	1960	-	Apr	lastSun	2:00	1:00	D
    +Rule	Winn	1951	1958	-	Sep	lastSun	2:00	0	S
    +Rule	Winn	1959	only	-	Oct	lastSun	2:00	0	S
    +Rule	Winn	1960	only	-	Sep	lastSun	2:00	0	S
    +Rule	Winn	1963	only	-	Apr	lastSun	2:00	1:00	D
    +Rule	Winn	1963	only	-	Sep	22	2:00	0	S
    +Rule	Winn	1966	1986	-	Apr	lastSun	2:00s	1:00	D
    +Rule	Winn	1966	2005	-	Oct	lastSun	2:00s	0	S
    +Rule	Winn	1987	2005	-	Apr	Sun>=1	2:00s	1:00	D
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Winnipeg	-6:28:36 -	LMT	1887 Jul 16
    +			-6:00	Winn	C%sT	2006
    +			-6:00	Canada	C%sT
    +
    +
    +# Saskatchewan
    +
    +# From Mark Brader (2003-07-26):
    +# The first actual adoption of DST in Canada was at the municipal
    +# level.  As the [Toronto] Star put it (1912-06-07), "While people
    +# elsewhere have long been talking of legislation to save daylight,
    +# the city of Moose Jaw [Saskatchewan] has acted on its own hook."
    +# DST in Moose Jaw began on Saturday, 1912-06-01 (no time mentioned:
    +# presumably late evening, as below), and would run until "the end of
    +# the summer".  The discrepancy between municipal time and railroad
    +# time was noted.
    +
    +# From Paul Eggert (2003-07-27):
    +# Willett (1914-03) notes that DST "has been in operation ... in the
    +# City of Moose Jaw, Saskatchewan, for one year."
    +
    +# From Paul Eggert (2006-03-22):
    +# Shanks & Pottenger say that since 1970 this region has mostly been as Regina.
    +# Some western towns (e.g. Swift Current) switched from MST/MDT to CST in 1972.
    +# Other western towns (e.g. Lloydminster) are like Edmonton.
    +# Matthews and Vincent (1998) write that Denare Beach and Creighton
    +# are like Winnipeg, in violation of Saskatchewan law.
    +
    +# From W. Jones (1992-11-06):
    +# The. . .below is based on information I got from our law library, the
    +# provincial archives, and the provincial Community Services department.
    +# A precise history would require digging through newspaper archives, and
    +# since you didn't say what you wanted, I didn't bother.
    +#
    +# Saskatchewan is split by a time zone meridian (105W) and over the years
    +# the boundary became pretty ragged as communities near it reevaluated
    +# their affiliations in one direction or the other.  In 1965 a provincial
    +# referendum favoured legislating common time practices.
    +#
    +# On 15 April 1966 the Time Act (c. T-14, Revised Statutes of
    +# Saskatchewan 1978) was proclaimed, and established that the eastern
    +# part of Saskatchewan would use CST year round, that districts in
    +# northwest Saskatchewan would by default follow CST but could opt to
    +# follow Mountain Time rules (thus 1 hour difference in the winter and
    +# zero in the summer), and that districts in southwest Saskatchewan would
    +# by default follow MT but could opt to follow CST.
    +#
    +# It took a few years for the dust to settle (I know one story of a town
    +# on one time zone having its school in another, such that a mom had to
    +# serve her family lunch in two shifts), but presently it seems that only
    +# a few towns on the border with Alberta (e.g. Lloydminster) follow MT
    +# rules any more; all other districts appear to have used CST year round
    +# since sometime in the 1960s.
    +
    +# From Chris Walton (2006-06-26):
    +# The Saskatchewan time act which was last updated in 1996 is about 30 pages
    +# long and rather painful to read.
    +# http://www.qp.gov.sk.ca/documents/English/Statutes/Statutes/T14.pdf
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Regina	1918	only	-	Apr	14	2:00	1:00	D
    +Rule	Regina	1918	only	-	Oct	27	2:00	0	S
    +Rule	Regina	1930	1934	-	May	Sun>=1	0:00	1:00	D
    +Rule	Regina	1930	1934	-	Oct	Sun>=1	0:00	0	S
    +Rule	Regina	1937	1941	-	Apr	Sun>=8	0:00	1:00	D
    +Rule	Regina	1937	only	-	Oct	Sun>=8	0:00	0	S
    +Rule	Regina	1938	only	-	Oct	Sun>=1	0:00	0	S
    +Rule	Regina	1939	1941	-	Oct	Sun>=8	0:00	0	S
    +Rule	Regina	1942	only	-	Feb	 9	2:00	1:00	W # War
    +Rule	Regina	1945	only	-	Aug	14	23:00u	1:00	P # Peace
    +Rule	Regina	1945	only	-	Sep	lastSun	2:00	0	S
    +Rule	Regina	1946	only	-	Apr	Sun>=8	2:00	1:00	D
    +Rule	Regina	1946	only	-	Oct	Sun>=8	2:00	0	S
    +Rule	Regina	1947	1957	-	Apr	lastSun	2:00	1:00	D
    +Rule	Regina	1947	1957	-	Sep	lastSun	2:00	0	S
    +Rule	Regina	1959	only	-	Apr	lastSun	2:00	1:00	D
    +Rule	Regina	1959	only	-	Oct	lastSun	2:00	0	S
    +#
    +Rule	Swift	1957	only	-	Apr	lastSun	2:00	1:00	D
    +Rule	Swift	1957	only	-	Oct	lastSun	2:00	0	S
    +Rule	Swift	1959	1961	-	Apr	lastSun	2:00	1:00	D
    +Rule	Swift	1959	only	-	Oct	lastSun	2:00	0	S
    +Rule	Swift	1960	1961	-	Sep	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Regina	-6:58:36 -	LMT	1905 Sep
    +			-7:00	Regina	M%sT	1960 Apr lastSun 2:00
    +			-6:00	-	CST
    +Zone America/Swift_Current -7:11:20 -	LMT	1905 Sep
    +			-7:00	Canada	M%sT	1946 Apr lastSun 2:00
    +			-7:00	Regina	M%sT	1950
    +			-7:00	Swift	M%sT	1972 Apr lastSun 2:00
    +			-6:00	-	CST
    +
    +
    +# Alberta
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Edm	1918	1919	-	Apr	Sun>=8	2:00	1:00	D
    +Rule	Edm	1918	only	-	Oct	27	2:00	0	S
    +Rule	Edm	1919	only	-	May	27	2:00	0	S
    +Rule	Edm	1920	1923	-	Apr	lastSun	2:00	1:00	D
    +Rule	Edm	1920	only	-	Oct	lastSun	2:00	0	S
    +Rule	Edm	1921	1923	-	Sep	lastSun	2:00	0	S
    +Rule	Edm	1942	only	-	Feb	 9	2:00	1:00	W # War
    +Rule	Edm	1945	only	-	Aug	14	23:00u	1:00	P # Peace
    +Rule	Edm	1945	only	-	Sep	lastSun	2:00	0	S
    +Rule	Edm	1947	only	-	Apr	lastSun	2:00	1:00	D
    +Rule	Edm	1947	only	-	Sep	lastSun	2:00	0	S
    +Rule	Edm	1967	only	-	Apr	lastSun	2:00	1:00	D
    +Rule	Edm	1967	only	-	Oct	lastSun	2:00	0	S
    +Rule	Edm	1969	only	-	Apr	lastSun	2:00	1:00	D
    +Rule	Edm	1969	only	-	Oct	lastSun	2:00	0	S
    +Rule	Edm	1972	1986	-	Apr	lastSun	2:00	1:00	D
    +Rule	Edm	1972	2006	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Edmonton	-7:33:52 -	LMT	1906 Sep
    +			-7:00	Edm	M%sT	1987
    +			-7:00	Canada	M%sT
    +
    +
    +# British Columbia
    +
    +# From Paul Eggert (2006-03-22):
    +# Shanks & Pottenger write that since 1970 most of this region has
    +# been like Vancouver.
    +# Dawson Creek uses MST.  Much of east BC is like Edmonton.
    +# Matthews and Vincent (1998) write that Creston is like Dawson Creek.
    +
    +# It seems though that (re: Creston) is not entirely correct:
    +
    +# From Chris Walton (2011-12-01):
    +# There are two areas within the Canadian province of British Columbia
    +# that do not currently observe daylight saving:
    +# a) The Creston Valley (includes the town of Creston and surrounding area)
    +# b) The eastern half of the Peace River Regional District
    +# (includes the cities of Dawson Creek and Fort St. John)
    +
    +# Earlier this year I stumbled across a detailed article about the time
    +# keeping history of Creston; it was written by Tammy Hardwick who is the
    +# manager of the Creston & District Museum. The article was written in May 2009.
    +# 
    +# http://www.ilovecreston.com/?p=articles&t=spec&ar=260
    +# 
    +# According to the article, Creston has not changed its clocks since June 1918.
    +# i.e. Creston has been stuck on UTC-7 for 93 years.
    +# Dawson Creek, on the other hand, changed its clocks as recently as April 1972.
    +
    +# Unfortunately the exact date for the time change in June 1918 remains
    +# unknown and will be difficult to ascertain.  I e-mailed Tammy a few months
    +# ago to ask if Sunday June 2 was a reasonable guess.  She said it was just
    +# as plausible as any other date (in June).  She also said that after writing the
    +# article she had discovered another time change in 1916; this is the subject
    +# of another article which she wrote in October 2010.
    +# 
    +# http://www.creston.museum.bc.ca/index.php?module=comments&uop=view_comment&cm+id=56
    +# 
    +
    +# Here is a summary of the three clock change events in Creston's history:
    +# 1. 1884 or 1885: adoption of Mountain Standard Time (GMT-7)
    +# Exact date unknown
    +# 2. Oct 1916: switch to Pacific Standard Time (GMT-8)
    +# Exact date in October unknown;  Sunday October 1 is a reasonable guess.
    +# 3. June 1918: switch to Pacific Daylight Time (GMT-7)
    +# Exact date in June unknown; Sunday June 2 is a reasonable guess.
    +# note#1:
    +# On Oct 27/1918 when daylight saving ended in the rest of Canada,
    +# Creston did not change its clocks.
    +# note#2:
    +# During WWII when the Federal Government legislated a mandatory clock change,
    +# Creston did not oblige.
    +# note#3:
    +# There is no guarantee that Creston will remain on Mountain Standard Time
    +# (UTC-7) forever.
    +# The subject was debated at least once this year by the town Council.
    +# 
    +# http://www.bclocalnews.com/kootenay_rockies/crestonvalleyadvance/news/116760809.html
    +# 
    +
    +# During a period WWII, summer time (Daylight saying) was mandatory in Canada.
    +# In Creston, that was handled by shifting the area to PST (-8:00) then applying
    +# summer time to cause the offset to be -7:00, the same as it had been before
    +# the change.  It can be argued that the timezone abbreviation during this
    +# period should be PDT rather than MST, but that doesn't seem important enough
    +# (to anyone) to further complicate the rules.
    +
    +# The transition dates (and times) are guesses.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Vanc	1918	only	-	Apr	14	2:00	1:00	D
    +Rule	Vanc	1918	only	-	Oct	27	2:00	0	S
    +Rule	Vanc	1942	only	-	Feb	 9	2:00	1:00	W # War
    +Rule	Vanc	1945	only	-	Aug	14	23:00u	1:00	P # Peace
    +Rule	Vanc	1945	only	-	Sep	30	2:00	0	S
    +Rule	Vanc	1946	1986	-	Apr	lastSun	2:00	1:00	D
    +Rule	Vanc	1946	only	-	Oct	13	2:00	0	S
    +Rule	Vanc	1947	1961	-	Sep	lastSun	2:00	0	S
    +Rule	Vanc	1962	2006	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Vancouver	-8:12:28 -	LMT	1884
    +			-8:00	Vanc	P%sT	1987
    +			-8:00	Canada	P%sT
    +Zone America/Dawson_Creek -8:00:56 -	LMT	1884
    +			-8:00	Canada	P%sT	1947
    +			-8:00	Vanc	P%sT	1972 Aug 30 2:00
    +			-7:00	-	MST
    +Zone America/Creston	-7:46:04 -	LMT	1884
    +			-7:00	-	MST	1916 Oct 1
    +			-8:00	-	PST	1918 Jun 2
    +			-7:00	-	MST
    +
    +# Northwest Territories, Nunavut, Yukon
    +
    +# From Paul Eggert (2006-03-22):
    +# Dawson switched to PST in 1973.  Inuvik switched to MST in 1979.
    +# Mathew Englander (1996-10-07) gives the following refs:
    +#	* 1967. Paragraph 28(34)(g) of the Interpretation Act, S.C. 1967-68,
    +#	c. 7 defines Yukon standard time as UTC-9.  This is still valid;
    +#	see Interpretation Act, R.S.C. 1985, c. I-21, s. 35(1).
    +#	* C.O. 1973/214 switched Yukon to PST on 1973-10-28 00:00.
    +#	* O.I.C. 1980/02 established DST.
    +#	* O.I.C. 1987/056 changed DST to Apr firstSun 2:00 to Oct lastSun 2:00.
    +# Shanks & Pottenger say Yukon's 1973-10-28 switch was at 2:00; go
    +# with Englander.
    +# From Chris Walton (2006-06-26):
    +# Here is a link to the old daylight saving portion of the interpretation
    +# act which was last updated in 1987:
    +# http://www.gov.yk.ca/legislation/regs/oic1987_056.pdf
    +
    +# From Rives McDow (1999-09-04):
    +# Nunavut ... moved ... to incorporate the whole territory into one time zone.
    +# 
    +# Nunavut moves to single time zone Oct. 31
    +# 
    +#
    +# From Antoine Leca (1999-09-06):
    +# We then need to create a new timezone for the Kitikmeot region of Nunavut
    +# to differentiate it from the Yellowknife region.
    +
    +# From Paul Eggert (1999-09-20):
    +# 
    +# Basic Facts: The New Territory
    +#  (1999) reports that Pangnirtung operates on eastern time,
    +# and that Coral Harbour does not observe DST.  We don't know when
    +# Pangnirtung switched to eastern time; we'll guess 1995.
    +
    +# From Rives McDow (1999-11-08):
    +# On October 31, when the rest of Nunavut went to Central time,
    +# Pangnirtung wobbled.  Here is the result of their wobble:
    +#
    +# The following businesses and organizations in Pangnirtung use Central Time:
    +#
    +#	First Air, Power Corp, Nunavut Construction, Health Center, RCMP,
    +#	Eastern Arctic National Parks, A & D Specialist
    +#
    +# The following businesses and organizations in Pangnirtung use Eastern Time:
    +#
    +#	Hamlet office, All other businesses, Both schools, Airport operator
    +#
    +# This has made for an interesting situation there, which warranted the news.
    +# No one there that I spoke with seems concerned, or has plans to
    +# change the local methods of keeping time, as it evidently does not
    +# really interfere with any activities or make things difficult locally.
    +# They plan to celebrate New Year's turn-over twice, one hour apart,
    +# so it appears that the situation will last at least that long.
    +# The Nunavut Intergovernmental Affairs hopes that they will "come to
    +# their senses", but the locals evidently don't see any problem with
    +# the current state of affairs.
    +
    +# From Michaela Rodrigue, writing in the
    +# 
    +# Nunatsiaq News (1999-11-19):
    +# Clyde River, Pangnirtung and Sanikiluaq now operate with two time zones,
    +# central - or Nunavut time - for government offices, and eastern time
    +# for municipal offices and schools....  Igloolik [was similar but then]
    +# made the switch to central time on Saturday, Nov. 6.
    +
    +# From Paul Eggert (2000-10-02):
    +# Matthews and Vincent (1998) say the following, but we lack histories
    +# for these potential new Zones.
    +#
    +# The Canadian Forces station at Alert uses Eastern Time while the
    +# handful of residents at the Eureka weather station [in the Central
    +# zone] skip daylight savings.  Baffin Island, which is crossed by the
    +# Central, Eastern and Atlantic Time zones only uses Eastern Time.
    +# Gjoa Haven, Taloyoak and Pelly Bay all use Mountain instead of
    +# Central Time and Southampton Island [in the Central zone] is not
    +# required to use daylight savings.
    +
    +# From
    +# 
    +# Nunavut now has two time zones
    +#  (2000-11-10):
    +# The Nunavut government would allow its employees in Kugluktuk and
    +# Cambridge Bay to operate on central time year-round, putting them
    +# one hour behind the rest of Nunavut for six months during the winter.
    +# At the end of October the two communities had rebelled against
    +# Nunavut's unified time zone, refusing to shift to eastern time with
    +# the rest of the territory for the winter.  Cambridge Bay remained on
    +# central time, while Kugluktuk, even farther west, reverted to
    +# mountain time, which they had used before the advent of Nunavut's
    +# unified time zone in 1999.
    +#
    +# From Rives McDow (2001-01-20), quoting the Nunavut government:
    +# The preceding decision came into effect at midnight, Saturday Nov 4, 2000.
    +
    +# From Paul Eggert (2000-12-04):
    +# Let's just keep track of the official times for now.
    +
    +# From Rives McDow (2001-03-07):
    +# The premier of Nunavut has issued a ministerial statement advising
    +# that effective 2001-04-01, the territory of Nunavut will revert
    +# back to three time zones (mountain, central, and eastern).  Of the
    +# cities in Nunavut, Coral Harbor is the only one that I know of that
    +# has said it will not observe dst, staying on EST year round.  I'm
    +# checking for more info, and will get back to you if I come up with
    +# more.
    +# [Also see  (2001-03-09).]
    +
    +# From Gwillim Law (2005-05-21):
    +# According to maps at
    +# http://inms-ienm.nrc-cnrc.gc.ca/images/time_services/TZ01SWE.jpg
    +# http://inms-ienm.nrc-cnrc.gc.ca/images/time_services/TZ01SSE.jpg
    +# (both dated 2003), and
    +# http://www.canadiangeographic.ca/Magazine/SO98/geomap.asp
    +# (from a 1998 Canadian Geographic article), the de facto and de jure time
    +# for Southampton Island (at the north end of Hudson Bay) is UTC-5 all year
    +# round.  Using Google, it's easy to find other websites that confirm this.
    +# I wasn't able to find how far back this time regimen goes, but since it
    +# predates the creation of Nunavut, it probably goes back many years....
    +# The Inuktitut name of Coral Harbour is Sallit, but it's rarely used.
    +#
    +# From Paul Eggert (2005-07-26):
    +# For lack of better information, assume that Southampton Island observed
    +# daylight saving only during wartime.
    +
    +# From Chris Walton (2007-03-01):
    +# ... the community of Resolute (located on Cornwallis Island in
    +# Nunavut) moved from Central Time to Eastern Time last November.
    +# Basically the community did not change its clocks at the end of
    +# daylight saving....
    +# http://www.nnsl.com/frames/newspapers/2006-11/nov13_06none.html
    +
    +# From Chris Walton (2011-03-21):
    +# Back in 2007 I initiated the creation of a new "zone file" for Resolute
    +# Bay. Resolute Bay is a small community located about 900km north of
    +# the Arctic Circle. The zone file was required because Resolute Bay had
    +# decided to use UTC-5 instead of UTC-6 for the winter of 2006-2007.
    +#
    +# According to new information which I received last week, Resolute Bay
    +# went back to using UTC-6 in the winter of 2007-2008...
    +#
    +# On March 11/2007 most of Canada went onto daylight saving. On March
    +# 14/2007 I phoned the Resolute Bay hamlet office to do a "time check." I
    +# talked to somebody that was both knowledgeable and helpful. I was able
    +# to confirm that Resolute Bay was still operating on UTC-5. It was
    +# explained to me that Resolute Bay had been on the Eastern Time zone
    +# (EST) in the winter, and was now back on the Central Time zone (CDT).
    +# i.e. the time zone had changed twice in the last year but the clocks
    +# had not moved. The residents had to know which time zone they were in
    +# so they could follow the correct TV schedule...
    +#
    +# On Nov 02/2008 most of Canada went onto standard time. On Nov 03/2008 I
    +# phoned the Resolute Bay hamlet office...[D]ue to the challenging nature
    +# of the phone call, I decided to seek out an alternate source of
    +# information. I found an e-mail address for somebody by the name of
    +# Stephanie Adams whose job was listed as "Inns North Support Officer for
    +# Arctic Co-operatives." I was under the impression that Stephanie lived
    +# and worked in Resolute Bay...
    +#
    +# On March 14/2011 I phoned the hamlet office again. I was told that
    +# Resolute Bay had been using Central Standard Time over the winter of
    +# 2010-2011 and that the clocks had therefore been moved one hour ahead
    +# on March 13/2011. The person I talked to was aware that Resolute Bay
    +# had previously experimented with Eastern Standard Time but he could not
    +# tell me when the practice had stopped.
    +#
    +# On March 17/2011 I searched the Web to find an e-mail address of
    +# somebody that might be able to tell me exactly when Resolute Bay went
    +# off Eastern Standard Time. I stumbled on the name "Aziz Kheraj." Aziz
    +# used to be the mayor of Resolute Bay and he apparently owns half the
    +# businesses including "South Camp Inn." This website has some info on
    +# Aziz:
    +# 
    +# http://www.uphere.ca/node/493
    +# 
    +#
    +# I sent Aziz an e-mail asking when Resolute Bay had stopped using
    +# Eastern Standard Time.
    +#
    +# Aziz responded quickly with this: "hi, The time was not changed for the
    +# 1 year only, the following year, the community went back to the old way
    +# of "spring ahead-fall behind" currently we are zulu plus 5 hrs and in
    +# the winter Zulu plus 6 hrs"
    +#
    +# This of course conflicted with everything I had ascertained in November 2008.
    +#
    +# I sent Aziz a copy of my 2008 e-mail exchange with Stephanie. Aziz
    +# responded with this: "Hi, Stephanie lives in Winnipeg. I live here, You
    +# may want to check with the weather office in Resolute Bay or do a
    +# search on the weather through Env. Canada. web site"
    +#
    +# If I had realized the Stephanie did not live in Resolute Bay I would
    +# never have contacted her.  I now believe that all the information I
    +# obtained in November 2008 should be ignored...
    +# I apologize for reporting incorrect information in 2008.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	NT_YK	1918	only	-	Apr	14	2:00	1:00	D
    +Rule	NT_YK	1918	only	-	Oct	27	2:00	0	S
    +Rule	NT_YK	1919	only	-	May	25	2:00	1:00	D
    +Rule	NT_YK	1919	only	-	Nov	 1	0:00	0	S
    +Rule	NT_YK	1942	only	-	Feb	 9	2:00	1:00	W # War
    +Rule	NT_YK	1945	only	-	Aug	14	23:00u	1:00	P # Peace
    +Rule	NT_YK	1945	only	-	Sep	30	2:00	0	S
    +Rule	NT_YK	1965	only	-	Apr	lastSun	0:00	2:00	DD
    +Rule	NT_YK	1965	only	-	Oct	lastSun	2:00	0	S
    +Rule	NT_YK	1980	1986	-	Apr	lastSun	2:00	1:00	D
    +Rule	NT_YK	1980	2006	-	Oct	lastSun	2:00	0	S
    +Rule	NT_YK	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +# aka Panniqtuuq
    +Zone America/Pangnirtung 0	-	zzz	1921 # trading post est.
    +			-4:00	NT_YK	A%sT	1995 Apr Sun>=1 2:00
    +			-5:00	Canada	E%sT	1999 Oct 31 2:00
    +			-6:00	Canada	C%sT	2000 Oct 29 2:00
    +			-5:00	Canada	E%sT
    +# formerly Frobisher Bay
    +Zone America/Iqaluit	0	-	zzz	1942 Aug # Frobisher Bay est.
    +			-5:00	NT_YK	E%sT	1999 Oct 31 2:00
    +			-6:00	Canada	C%sT	2000 Oct 29 2:00
    +			-5:00	Canada	E%sT
    +# aka Qausuittuq
    +Zone America/Resolute	0	-	zzz	1947 Aug 31 # Resolute founded
    +			-6:00	NT_YK	C%sT	2000 Oct 29 2:00
    +			-5:00	-	EST	2001 Apr  1 3:00
    +			-6:00	Canada	C%sT	2006 Oct 29 2:00
    +			-5:00	-	EST	2007 Mar 11 3:00
    +			-6:00	Canada	C%sT
    +# aka Kangiqiniq
    +Zone America/Rankin_Inlet 0	-	zzz	1957 # Rankin Inlet founded
    +			-6:00	NT_YK	C%sT	2000 Oct 29 2:00
    +			-5:00	-	EST	2001 Apr  1 3:00
    +			-6:00	Canada	C%sT
    +# aka Iqaluktuuttiaq
    +Zone America/Cambridge_Bay 0	-	zzz	1920 # trading post est.?
    +			-7:00	NT_YK	M%sT	1999 Oct 31 2:00
    +			-6:00	Canada	C%sT	2000 Oct 29 2:00
    +			-5:00	-	EST	2000 Nov  5 0:00
    +			-6:00	-	CST	2001 Apr  1 3:00
    +			-7:00	Canada	M%sT
    +Zone America/Yellowknife 0	-	zzz	1935 # Yellowknife founded?
    +			-7:00	NT_YK	M%sT	1980
    +			-7:00	Canada	M%sT
    +Zone America/Inuvik	0	-	zzz	1953 # Inuvik founded
    +			-8:00	NT_YK	P%sT	1979 Apr lastSun 2:00
    +			-7:00	NT_YK	M%sT	1980
    +			-7:00	Canada	M%sT
    +Zone America/Whitehorse	-9:00:12 -	LMT	1900 Aug 20
    +			-9:00	NT_YK	Y%sT	1966 Jul 1 2:00
    +			-8:00	NT_YK	P%sT	1980
    +			-8:00	Canada	P%sT
    +Zone America/Dawson	-9:17:40 -	LMT	1900 Aug 20
    +			-9:00	NT_YK	Y%sT	1973 Oct 28 0:00
    +			-8:00	NT_YK	P%sT	1980
    +			-8:00	Canada	P%sT
    +
    +
    +###############################################################################
    +
    +# Mexico
    +
    +# From Paul Eggert (2001-03-05):
    +# The Investigation and Analysis Service of the
    +# Mexican Library of Congress (MLoC) has published a
    +# 
    +# history of Mexican local time (in Spanish)
    +# .
    +#
    +# Here are the discrepancies between Shanks & Pottenger (S&P) and the MLoC.
    +# (In all cases we go with the MLoC.)
    +# S&P report that Baja was at -8:00 in 1922/1923.
    +# S&P say the 1930 transition in Baja was 1930-11-16.
    +# S&P report no DST during summer 1931.
    +# S&P report a transition at 1932-03-30 23:00, not 1932-04-01.
    +
    +# From Gwillim Law (2001-02-20):
    +# There are some other discrepancies between the Decrees page and the
    +# tz database.  I think they can best be explained by supposing that
    +# the researchers who prepared the Decrees page failed to find some of
    +# the relevant documents.
    +
    +# From Alan Perry (1996-02-15):
    +# A guy from our Mexico subsidiary finally found the Presidential Decree
    +# outlining the timezone changes in Mexico.
    +#
    +# ------------- Begin Forwarded Message -------------
    +#
    +# I finally got my hands on the Official Presidential Decree that sets up the
    +# rules for the DST changes. The rules are:
    +#
    +# 1. The country is divided in 3 timezones:
    +#    - Baja California Norte (the Mexico/BajaNorte TZ)
    +#    - Baja California Sur, Nayarit, Sinaloa and Sonora (the Mexico/BajaSur TZ)
    +#    - The rest of the country (the Mexico/General TZ)
    +#
    +# 2. From the first Sunday in April at 2:00 AM to the last Sunday in October
    +#    at 2:00 AM, the times in each zone are as follows:
    +#    BajaNorte: GMT+7
    +#    BajaSur:   GMT+6
    +#    General:   GMT+5
    +#
    +# 3. The rest of the year, the times are as follows:
    +#    BajaNorte: GMT+8
    +#    BajaSur:   GMT+7
    +#    General:   GMT+6
    +#
    +# The Decree was published in Mexico's Official Newspaper on January 4th.
    +#
    +# -------------- End Forwarded Message --------------
    +# From Paul Eggert (1996-06-12):
    +# For an English translation of the decree, see
    +# 
    +# ``Diario Oficial: Time Zone Changeover'' (1996-01-04).
    +# 
    +
    +# From Rives McDow (1998-10-08):
    +# The State of Quintana Roo has reverted back to central STD and DST times
    +# (i.e. UTC -0600 and -0500 as of 1998-08-02).
    +
    +# From Rives McDow (2000-01-10):
    +# Effective April 4, 1999 at 2:00 AM local time, Sonora changed to the time
    +# zone 5 hours from the International Date Line, and will not observe daylight
    +# savings time so as to stay on the same time zone as the southern part of
    +# Arizona year round.
    +
    +# From Jesper Norgaard, translating
    +#  (2001-01-17):
    +# In Oaxaca, the 55.000 teachers from the Section 22 of the National
    +# Syndicate of Education Workers, refuse to apply daylight saving each
    +# year, so that the more than 10,000 schools work at normal hour the
    +# whole year.
    +
    +# From Gwillim Law (2001-01-19):
    +#  ... says
    +# (translated):...
    +# January 17, 2000 - The Energy Secretary, Ernesto Martens, announced
    +# that Summer Time will be reduced from seven to five months, starting
    +# this year....
    +# 
    +# [translated], says "summer time will ... take effect on the first Sunday
    +# in May, and end on the last Sunday of September.
    +
    +# From Arthur David Olson (2001-01-25):
    +# The 2001-01-24 traditional Washington Post contained the page one
    +# story "Timely Issue Divides Mexicans."...
    +# http://www.washingtonpost.com/wp-dyn/articles/A37383-2001Jan23.html
    +# ... Mexico City Mayor Lopez Obrador "...is threatening to keep
    +# Mexico City and its 20 million residents on a different time than
    +# the rest of the country..." In particular, Lopez Obrador would abolish
    +# observation of Daylight Saving Time.
    +
    +# 
    +# Official statute published by the Energy Department
    +#  (2001-02-01) shows Baja and Chihauhua as still using US DST rules,
    +# and Sonora with no DST.  This was reported by Jesper Norgaard (2001-02-03).
    +
    +# From Paul Eggert (2001-03-03):
    +#
    +# 
    +# James F. Smith writes in today's LA Times
    +# 
    +# * Sonora will continue to observe standard time.
    +# * Last week Mexico City's mayor Andres Manuel Lopez Obrador decreed that
    +#   the Federal District will not adopt DST.
    +# * 4 of 16 district leaders announced they'll ignore the decree.
    +# * The decree does not affect federal-controlled facilities including
    +#   the airport, banks, hospitals, and schools.
    +#
    +# For now we'll assume that the Federal District will bow to federal rules.
    +
    +# From Jesper Norgaard (2001-04-01):
    +# I found some references to the Mexican application of daylight
    +# saving, which modifies what I had already sent you, stating earlier
    +# that a number of northern Mexican states would go on daylight
    +# saving. The modification reverts this to only cover Baja California
    +# (Norte), while all other states (except Sonora, who has no daylight
    +# saving all year) will follow the original decree of president
    +# Vicente Fox, starting daylight saving May 6, 2001 and ending
    +# September 30, 2001.
    +# References: "Diario de Monterrey" 
    +# Palabra  (2001-03-31)
    +
    +# From Reuters (2001-09-04):
    +# Mexico's Supreme Court on Tuesday declared that daylight savings was
    +# unconstitutional in Mexico City, creating the possibility the
    +# capital will be in a different time zone from the rest of the nation
    +# next year....  The Supreme Court's ruling takes effect at 2:00
    +# a.m. (0800 GMT) on Sept. 30, when Mexico is scheduled to revert to
    +# standard time. "This is so residents of the Federal District are not
    +# subject to unexpected time changes," a statement from the court said.
    +
    +# From Jesper Norgaard Welen (2002-03-12):
    +# ... consulting my local grocery store(!) and my coworkers, they all insisted
    +# that a new decision had been made to reinstate US style DST in Mexico....
    +# http://www.conae.gob.mx/ahorro/horaver2001_m1_2002.html (2002-02-20)
    +# confirms this.  Sonora as usual is the only state where DST is not applied.
    +
    +# From Steffen Thorsen (2009-12-28):
    +#
    +# Steffen Thorsen wrote:
    +# > Mexico's House of Representatives has approved a proposal for northern
    +# > Mexico's border cities to share the same daylight saving schedule as
    +# > the United States.
    +# Now this has passed both the Congress and the Senate, so starting from
    +# 2010, some border regions will be the same:
    +# 
    +# http://www.signonsandiego.com/news/2009/dec/28/clocks-will-match-both-sides-border/
    +# 
    +# 
    +# http://www.elmananarey.com/diario/noticia/nacional/noticias/empatan_horario_de_frontera_con_eu/621939
    +# 
    +# (Spanish)
    +#
    +# Could not find the new law text, but the proposed law text changes are here:
    +# 
    +# http://gaceta.diputados.gob.mx/Gaceta/61/2009/dic/20091210-V.pdf
    +# 
    +# (Gaceta Parlamentaria)
    +#
    +# There is also a list of the votes here:
    +# 
    +# http://gaceta.diputados.gob.mx/Gaceta/61/2009/dic/V2-101209.html
    +# 
    +#
    +# Our page:
    +# 
    +# http://www.timeanddate.com/news/time/north-mexico-dst-change.html
    +# 
    +
    +# From Arthur David Olson (2010-01-20):
    +# The page
    +# 
    +# http://dof.gob.mx/nota_detalle.php?codigo=5127480&fecha=06/01/2010
    +# 
    +# includes this text:
    +# En los municipios fronterizos de Tijuana y Mexicali en Baja California;
    +# Juárez y Ojinaga en Chihuahua; Acuña y Piedras Negras en Coahuila;
    +# Anáhuac en Nuevo León; y Nuevo Laredo, Reynosa y Matamoros en
    +# Tamaulipas, la aplicación de este horario estacional surtirá efecto
    +# desde las dos horas del segundo domingo de marzo y concluirá a las dos
    +# horas del primer domingo de noviembre.
    +# En los municipios fronterizos que se encuentren ubicados en la franja
    +# fronteriza norte en el territorio comprendido entre la línea
    +# internacional y la línea paralela ubicada a una distancia de veinte
    +# kilómetros, así como la Ciudad de Ensenada, Baja California, hacia el
    +# interior del país, la aplicación de este horario estacional surtirá
    +# efecto desde las dos horas del segundo domingo de marzo y concluirá a
    +# las dos horas del primer domingo de noviembre.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Mexico	1939	only	-	Feb	5	0:00	1:00	D
    +Rule	Mexico	1939	only	-	Jun	25	0:00	0	S
    +Rule	Mexico	1940	only	-	Dec	9	0:00	1:00	D
    +Rule	Mexico	1941	only	-	Apr	1	0:00	0	S
    +Rule	Mexico	1943	only	-	Dec	16	0:00	1:00	W # War
    +Rule	Mexico	1944	only	-	May	1	0:00	0	S
    +Rule	Mexico	1950	only	-	Feb	12	0:00	1:00	D
    +Rule	Mexico	1950	only	-	Jul	30	0:00	0	S
    +Rule	Mexico	1996	2000	-	Apr	Sun>=1	2:00	1:00	D
    +Rule	Mexico	1996	2000	-	Oct	lastSun	2:00	0	S
    +Rule	Mexico	2001	only	-	May	Sun>=1	2:00	1:00	D
    +Rule	Mexico	2001	only	-	Sep	lastSun	2:00	0	S
    +Rule	Mexico	2002	max	-	Apr	Sun>=1	2:00	1:00	D
    +Rule	Mexico	2002	max	-	Oct	lastSun	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +# Quintana Roo
    +Zone America/Cancun	-5:47:04 -	LMT	1922 Jan  1  0:12:56
    +			-6:00	-	CST	1981 Dec 23
    +			-5:00	Mexico	E%sT	1998 Aug  2  2:00
    +			-6:00	Mexico	C%sT
    +# Campeche, Yucatan
    +Zone America/Merida	-5:58:28 -	LMT	1922 Jan  1  0:01:32
    +			-6:00	-	CST	1981 Dec 23
    +			-5:00	-	EST	1982 Dec  2
    +			-6:00	Mexico	C%sT
    +# Coahuila, Durango, Nuevo Leon, Tamaulipas (near US border)
    +Zone America/Matamoros	-6:40:00 -	LMT	1921 Dec 31 23:20:00
    +			-6:00	-	CST	1988
    +			-6:00	US	C%sT	1989
    +			-6:00	Mexico	C%sT	2010
    +			-6:00	US	C%sT
    +# Coahuila, Durango, Nuevo Leon, Tamaulipas (away from US border)
    +Zone America/Monterrey	-6:41:16 -	LMT	1921 Dec 31 23:18:44
    +			-6:00	-	CST	1988
    +			-6:00	US	C%sT	1989
    +			-6:00	Mexico	C%sT
    +# Central Mexico
    +Zone America/Mexico_City -6:36:36 -	LMT	1922 Jan  1 0:23:24
    +			-7:00	-	MST	1927 Jun 10 23:00
    +			-6:00	-	CST	1930 Nov 15
    +			-7:00	-	MST	1931 May  1 23:00
    +			-6:00	-	CST	1931 Oct
    +			-7:00	-	MST	1932 Apr  1
    +			-6:00	Mexico	C%sT	2001 Sep 30 02:00
    +			-6:00	-	CST	2002 Feb 20
    +			-6:00	Mexico	C%sT
    +# Chihuahua (near US border)
    +Zone America/Ojinaga	-6:57:40 -	LMT	1922 Jan 1 0:02:20
    +			-7:00	-	MST	1927 Jun 10 23:00
    +			-6:00	-	CST	1930 Nov 15
    +			-7:00	-	MST	1931 May  1 23:00
    +			-6:00	-	CST	1931 Oct
    +			-7:00	-	MST	1932 Apr  1
    +			-6:00	-	CST	1996
    +			-6:00	Mexico	C%sT	1998
    +			-6:00	-	CST	1998 Apr Sun>=1 3:00
    +			-7:00	Mexico	M%sT	2010
    +			-7:00	US	M%sT
    +# Chihuahua (away from US border)
    +Zone America/Chihuahua	-7:04:20 -	LMT	1921 Dec 31 23:55:40
    +			-7:00	-	MST	1927 Jun 10 23:00
    +			-6:00	-	CST	1930 Nov 15
    +			-7:00	-	MST	1931 May  1 23:00
    +			-6:00	-	CST	1931 Oct
    +			-7:00	-	MST	1932 Apr  1
    +			-6:00	-	CST	1996
    +			-6:00	Mexico	C%sT	1998
    +			-6:00	-	CST	1998 Apr Sun>=1 3:00
    +			-7:00	Mexico	M%sT
    +# Sonora
    +Zone America/Hermosillo	-7:23:52 -	LMT	1921 Dec 31 23:36:08
    +			-7:00	-	MST	1927 Jun 10 23:00
    +			-6:00	-	CST	1930 Nov 15
    +			-7:00	-	MST	1931 May  1 23:00
    +			-6:00	-	CST	1931 Oct
    +			-7:00	-	MST	1932 Apr  1
    +			-6:00	-	CST	1942 Apr 24
    +			-7:00	-	MST	1949 Jan 14
    +			-8:00	-	PST	1970
    +			-7:00	Mexico	M%sT	1999
    +			-7:00	-	MST
    +
    +# From Alexander Krivenyshev (2010-04-21):
    +# According to news, Bahía de Banderas (Mexican state of Nayarit)
    +# changed time zone UTC-7 to new time zone UTC-6 on April 4, 2010 (to
    +# share the same time zone as nearby city Puerto Vallarta, Jalisco).
    +#
    +# (Spanish)
    +# Bahía de Banderas homologa su horario al del centro del
    +# país, a partir de este domingo
    +# 
    +# http://www.nayarit.gob.mx/notes.asp?id=20748
    +# 
    +#
    +# Bahía de Banderas homologa su horario con el del Centro del
    +# País
    +# 
    +# http://www.bahiadebanderas.gob.mx/principal/index.php?option=com_content&view=article&id=261:bahia-de-banderas-homologa-su-horario-con-el-del-centro-del-pais&catid=42:comunicacion-social&Itemid=50"
    +# 
    +#
    +# (English)
    +# Puerto Vallarta and Bahía de Banderas: One Time Zone
    +# 
    +# http://virtualvallarta.com/puertovallarta/puertovallarta/localnews/2009-12-03-Puerto-Vallarta-and-Bahia-de-Banderas-One-Time-Zone.shtml
    +# 
    +#
    +# or
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_mexico08.html
    +# 
    +#
    +# "Mexico's Senate approved the amendments to the Mexican Schedule System that
    +# will allow Bahía de Banderas and Puerto Vallarta to share the same time
    +# zone ..."
    +# Baja California Sur, Nayarit, Sinaloa
    +
    +# From Arthur David Olson (2010-05-01):
    +# Use "Bahia_Banderas" to keep the name to fourteen characters.
    +
    +Zone America/Mazatlan	-7:05:40 -	LMT	1921 Dec 31 23:54:20
    +			-7:00	-	MST	1927 Jun 10 23:00
    +			-6:00	-	CST	1930 Nov 15
    +			-7:00	-	MST	1931 May  1 23:00
    +			-6:00	-	CST	1931 Oct
    +			-7:00	-	MST	1932 Apr  1
    +			-6:00	-	CST	1942 Apr 24
    +			-7:00	-	MST	1949 Jan 14
    +			-8:00	-	PST	1970
    +			-7:00	Mexico	M%sT
    +
    +Zone America/Bahia_Banderas	-7:01:00 -	LMT	1921 Dec 31 23:59:00
    +			-7:00	-	MST	1927 Jun 10 23:00
    +			-6:00	-	CST	1930 Nov 15
    +			-7:00	-	MST	1931 May  1 23:00
    +			-6:00	-	CST	1931 Oct
    +			-7:00	-	MST	1932 Apr  1
    +			-6:00	-	CST	1942 Apr 24
    +			-7:00	-	MST	1949 Jan 14
    +			-8:00	-	PST	1970
    +			-7:00	Mexico	M%sT	2010 Apr 4 2:00
    +			-6:00	Mexico	C%sT
    +
    +# Baja California (near US border)
    +Zone America/Tijuana	-7:48:04 -	LMT	1922 Jan  1  0:11:56
    +			-7:00	-	MST	1924
    +			-8:00	-	PST	1927 Jun 10 23:00
    +			-7:00	-	MST	1930 Nov 15
    +			-8:00	-	PST	1931 Apr  1
    +			-8:00	1:00	PDT	1931 Sep 30
    +			-8:00	-	PST	1942 Apr 24
    +			-8:00	1:00	PWT	1945 Aug 14 23:00u
    +			-8:00	1:00	PPT	1945 Nov 12 # Peace
    +			-8:00	-	PST	1948 Apr  5
    +			-8:00	1:00	PDT	1949 Jan 14
    +			-8:00	-	PST	1954
    +			-8:00	CA	P%sT	1961
    +			-8:00	-	PST	1976
    +			-8:00	US	P%sT	1996
    +			-8:00	Mexico	P%sT	2001
    +			-8:00	US	P%sT	2002 Feb 20
    +			-8:00	Mexico	P%sT	2010
    +			-8:00	US	P%sT
    +# Baja California (away from US border)
    +Zone America/Santa_Isabel	-7:39:28 -	LMT	1922 Jan  1  0:20:32
    +			-7:00	-	MST	1924
    +			-8:00	-	PST	1927 Jun 10 23:00
    +			-7:00	-	MST	1930 Nov 15
    +			-8:00	-	PST	1931 Apr  1
    +			-8:00	1:00	PDT	1931 Sep 30
    +			-8:00	-	PST	1942 Apr 24
    +			-8:00	1:00	PWT	1945 Aug 14 23:00u
    +			-8:00	1:00	PPT	1945 Nov 12 # Peace
    +			-8:00	-	PST	1948 Apr  5
    +			-8:00	1:00	PDT	1949 Jan 14
    +			-8:00	-	PST	1954
    +			-8:00	CA	P%sT	1961
    +			-8:00	-	PST	1976
    +			-8:00	US	P%sT	1996
    +			-8:00	Mexico	P%sT	2001
    +			-8:00	US	P%sT	2002 Feb 20
    +			-8:00	Mexico	P%sT
    +# From Paul Eggert (2006-03-22):
    +# Formerly there was an America/Ensenada zone, which differed from
    +# America/Tijuana only in that it did not observe DST from 1976
    +# through 1995.  This was as per Shanks (1999).  But Shanks & Pottenger say
    +# Ensenada did not observe DST from 1948 through 1975.  Guy Harris reports
    +# that the 1987 OAG says "Only Ensenada, Mexicale, San Felipe and
    +# Tijuana observe DST," which agrees with Shanks & Pottenger but implies that
    +# DST-observance was a town-by-town matter back then.  This concerns
    +# data after 1970 so most likely there should be at least one Zone
    +# other than America/Tijuana for Baja, but it's not clear yet what its
    +# name or contents should be.
    +#
    +# Revillagigedo Is
    +# no information
    +
    +###############################################################################
    +
    +# Anguilla
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Anguilla	-4:12:16 -	LMT	1912 Mar 2
    +			-4:00	-	AST
    +
    +# Antigua and Barbuda
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Antigua	-4:07:12 -	LMT	1912 Mar 2
    +			-5:00	-	EST	1951
    +			-4:00	-	AST
    +
    +# Bahamas
    +#
    +# From Sue Williams (2006-12-07):
    +# The Bahamas announced about a month ago that they plan to change their DST
    +# rules to sync with the U.S. starting in 2007....
    +# http://www.jonesbahamas.com/?c=45&a=10412
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Bahamas	1964	1975	-	Oct	lastSun	2:00	0	S
    +Rule	Bahamas	1964	1975	-	Apr	lastSun	2:00	1:00	D
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Nassau	-5:09:24 -	LMT	1912 Mar 2
    +			-5:00	Bahamas	E%sT	1976
    +			-5:00	US	E%sT
    +
    +# Barbados
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Barb	1977	only	-	Jun	12	2:00	1:00	D
    +Rule	Barb	1977	1978	-	Oct	Sun>=1	2:00	0	S
    +Rule	Barb	1978	1980	-	Apr	Sun>=15	2:00	1:00	D
    +Rule	Barb	1979	only	-	Sep	30	2:00	0	S
    +Rule	Barb	1980	only	-	Sep	25	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Barbados	-3:58:28 -	LMT	1924		# Bridgetown
    +			-3:58:28 -	BMT	1932	  # Bridgetown Mean Time
    +			-4:00	Barb	A%sT
    +
    +# Belize
    +# Whitman entirely disagrees with Shanks; go with Shanks & Pottenger.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Belize	1918	1942	-	Oct	Sun>=2	0:00	0:30	HD
    +Rule	Belize	1919	1943	-	Feb	Sun>=9	0:00	0	S
    +Rule	Belize	1973	only	-	Dec	 5	0:00	1:00	D
    +Rule	Belize	1974	only	-	Feb	 9	0:00	0	S
    +Rule	Belize	1982	only	-	Dec	18	0:00	1:00	D
    +Rule	Belize	1983	only	-	Feb	12	0:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Belize	-5:52:48 -	LMT	1912 Apr
    +			-6:00	Belize	C%sT
    +
    +# Bermuda
    +
    +# From Dan Jones, reporting in The Royal Gazette (2006-06-26):
    +
    +# Next year, however, clocks in the US will go forward on the second Sunday
    +# in March, until the first Sunday in November.  And, after the Time Zone
    +# (Seasonal Variation) Bill 2006 was passed in the House of Assembly on
    +# Friday, the same thing will happen in Bermuda.
    +# http://www.theroyalgazette.com/apps/pbcs.dll/article?AID=/20060529/NEWS/105290135
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Atlantic/Bermuda	-4:19:04 -	LMT	1930 Jan  1 2:00    # Hamilton
    +			-4:00	-	AST	1974 Apr 28 2:00
    +			-4:00	Bahamas	A%sT	1976
    +			-4:00	US	A%sT
    +
    +# Cayman Is
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Cayman	-5:25:32 -	LMT	1890		# Georgetown
    +			-5:07:12 -	KMT	1912 Feb    # Kingston Mean Time
    +			-5:00	-	EST
    +
    +# Costa Rica
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	CR	1979	1980	-	Feb	lastSun	0:00	1:00	D
    +Rule	CR	1979	1980	-	Jun	Sun>=1	0:00	0	S
    +Rule	CR	1991	1992	-	Jan	Sat>=15	0:00	1:00	D
    +# IATA SSIM (1991-09) says the following was at 1:00;
    +# go with Shanks & Pottenger.
    +Rule	CR	1991	only	-	Jul	 1	0:00	0	S
    +Rule	CR	1992	only	-	Mar	15	0:00	0	S
    +# There are too many San Joses elsewhere, so we'll use `Costa Rica'.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Costa_Rica	-5:36:20 -	LMT	1890		# San Jose
    +			-5:36:20 -	SJMT	1921 Jan 15 # San Jose Mean Time
    +			-6:00	CR	C%sT
    +# Coco
    +# no information; probably like America/Costa_Rica
    +
    +# Cuba
    +
    +# From Arthur David Olson (1999-03-29):
    +# The 1999-03-28 exhibition baseball game held in Havana, Cuba, between
    +# the Cuban National Team and the Baltimore Orioles was carried live on
    +# the Orioles Radio Network, including affiliate WTOP in Washington, DC.
    +# During the game, play-by-play announcer Jim Hunter noted that
    +# "We'll be losing two hours of sleep...Cuba switched to Daylight Saving
    +# Time today."  (The "two hour" remark referred to losing one hour of
    +# sleep on 1999-03-28--when the announcers were in Cuba as it switched
    +# to DST--and one more hour on 1999-04-04--when the announcers will have
    +# returned to Baltimore, which switches on that date.)
    +
    +# From Evert van der Veer via Steffen Thorsen (2004-10-28):
    +# Cuba is not going back to standard time this year.
    +# From Paul Eggert (2006-03-22):
    +# http://www.granma.cu/ingles/2004/septiembre/juev30/41medid-i.html
    +# says that it's due to a problem at the Antonio Guiteras
    +# thermoelectric plant, and says "This October there will be no return
    +# to normal hours (after daylight saving time)".
    +# For now, let's assume that it's a temporary measure.
    +
    +# From Carlos A. Carnero Delgado (2005-11-12):
    +# This year (just like in 2004-2005) there's no change in time zone
    +# adjustment in Cuba.  We will stay in daylight saving time:
    +# http://www.granma.cu/espanol/2005/noviembre/mier9/horario.html
    +
    +# From Jesper Norgaard Welen (2006-10-21):
    +# An article in GRANMA INTERNACIONAL claims that Cuba will end
    +# the 3 years of permanent DST next weekend, see
    +# http://www.granma.cu/ingles/2006/octubre/lun16/43horario.html
    +# "On Saturday night, October 28 going into Sunday, October 29, at 01:00,
    +# watches should be set back one hour -- going back to 00:00 hours -- returning
    +# to the normal schedule....
    +
    +# From Paul Eggert (2007-03-02):
    +# http://www.granma.cubaweb.cu/english/news/art89.html, dated yesterday,
    +# says Cuban clocks will advance at midnight on March 10.
    +# For lack of better information, assume Cuba will use US rules,
    +# except that it switches at midnight standard time as usual.
    +#
    +# From Steffen Thorsen (2007-10-25):
    +# Carlos Alberto Fonseca Arauz informed me that Cuba will end DST one week
    +# earlier - on the last Sunday of October, just like in 2006.
    +#
    +# He supplied these references:
    +#
    +# http://www.prensalatina.com.mx/article.asp?ID=%7B4CC32C1B-A9F7-42FB-8A07-8631AFC923AF%7D&language=ES
    +# http://actualidad.terra.es/sociedad/articulo/cuba_llama_ahorrar_energia_cambio_1957044.htm
    +#
    +# From Alex Kryvenishev (2007-10-25):
    +# Here is also article from Granma (Cuba):
    +#
    +# [Regira] el Horario Normal desde el [proximo] domingo 28 de octubre
    +# http://www.granma.cubaweb.cu/2007/10/24/nacional/artic07.html
    +#
    +# http://www.worldtimezone.com/dst_news/dst_news_cuba03.html
    +
    +# From Arthur David Olson (2008-03-09):
    +# I'm in Maryland which is now observing United States Eastern Daylight
    +# Time. At 9:44 local time I used RealPlayer to listen to
    +# 
    +# http://media.enet.cu/radioreloj
    +# , a Cuban information station, and heard
    +# the time announced as "ocho cuarenta y cuatro" ("eight forty-four"),
    +# indicating that Cuba is still on standard time.
    +
    +# From Steffen Thorsen (2008-03-12):
    +# It seems that Cuba will start DST on Sunday, 2007-03-16...
    +# It was announced yesterday, according to this source (in Spanish):
    +# 
    +# http://www.nnc.cubaweb.cu/marzo-2008/cien-1-11-3-08.htm
    +# 
    +#
    +# Some more background information is posted here:
    +# 
    +# http://www.timeanddate.com/news/time/cuba-starts-dst-march-16.html
    +# 
    +#
    +# The article also says that Cuba has been observing DST since 1963,
    +# while Shanks (and tzdata) has 1965 as the first date (except in the
    +# 1940's). Many other web pages in Cuba also claim that it has been
    +# observed since 1963, but with the exception of 1970 - an exception
    +# which is not present in tzdata/Shanks. So there is a chance we need to
    +# change some historic records as well.
    +#
    +# One example:
    +# 
    +# http://www.radiohc.cu/espanol/noticias/mar07/11mar/hor.htm
    +# 
    +
    +# From Jesper Norgaard Welen (2008-03-13):
    +# The Cuban time change has just been confirmed on the most authoritative
    +# web site, the Granma.  Please check out
    +# 
    +# http://www.granma.cubaweb.cu/2008/03/13/nacional/artic10.html
    +# 
    +#
    +# Basically as expected after Steffen Thorsens information, the change
    +# will take place midnight between Saturday and Sunday.
    +
    +# From Arthur David Olson (2008-03-12):
    +# Assume Sun>=15 (third Sunday) going forward.
    +
    +# From Alexander Krivenyshev (2009-03-04)
    +# According to the Radio Reloj - Cuba will start Daylight Saving Time on
    +# midnight between Saturday, March 07, 2009 and Sunday, March 08, 2009-
    +# not on midnight March 14 / March 15 as previously thought.
    +#
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_cuba05.html
    +# (in Spanish)
    +# 
    +
    +# From Arthur David Olson (2009-03-09)
    +# I listened over the Internet to
    +# 
    +# http://media.enet.cu/readioreloj
    +# 
    +# this morning; when it was 10:05 a. m. here in Bethesda, Maryland the
    +# the time was announced as "diez cinco"--the same time as here, indicating
    +# that has indeed switched to DST. Assume second Sunday from 2009 forward.
    +
    +# From Steffen Thorsen (2011-03-08):
    +# Granma announced that Cuba is going to start DST on 2011-03-20 00:00:00
    +# this year. Nothing about the end date known so far (if that has
    +# changed at all).
    +#
    +# Source:
    +# 
    +# http://granma.co.cu/2011/03/08/nacional/artic01.html
    +# 
    +#
    +# Our info:
    +# 
    +# http://www.timeanddate.com/news/time/cuba-starts-dst-2011.html
    +# 
    +#
    +# From Steffen Thorsen (2011-10-30)
    +# Cuba will end DST two weeks later this year. Instead of going back
    +# tonight, it has been delayed to 2011-11-13 at 01:00.
    +#
    +# One source (Spanish)
    +# 
    +# http://www.radioangulo.cu/noticias/cuba/17105-cuba-restablecera-el-horario-del-meridiano-de-greenwich.html
    +# 
    +#
    +# Our page:
    +# 
    +# http://www.timeanddate.com/news/time/cuba-time-changes-2011.html
    +# 
    +#
    +# From Steffen Thorsen (2012-03-01)
    +# According to Radio Reloj, Cuba will start DST on Midnight between March
    +# 31 and April 1.
    +#
    +# Radio Reloj has the following info (Spanish):
    +# 
    +# http://www.radioreloj.cu/index.php/noticias-radio-reloj/71-miscelaneas/7529-cuba-aplicara-el-horario-de-verano-desde-el-1-de-abril
    +# 
    +#
    +# Our info on it:
    +# 
    +# http://www.timeanddate.com/news/time/cuba-starts-dst-2012.html
    +# 
    +
    +# From Steffen Thorsen (2012-11-03):
    +# Radio Reloj and many other sources report that Cuba is changing back
    +# to standard time on 2012-11-04:
    +# http://www.radioreloj.cu/index.php/noticias-radio-reloj/36-nacionales/9961-regira-horario-normal-en-cuba-desde-el-domingo-cuatro-de-noviembre
    +# From Paul Eggert (2012-11-03):
    +# For now, assume the future rule is first Sunday in November.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Cuba	1928	only	-	Jun	10	0:00	1:00	D
    +Rule	Cuba	1928	only	-	Oct	10	0:00	0	S
    +Rule	Cuba	1940	1942	-	Jun	Sun>=1	0:00	1:00	D
    +Rule	Cuba	1940	1942	-	Sep	Sun>=1	0:00	0	S
    +Rule	Cuba	1945	1946	-	Jun	Sun>=1	0:00	1:00	D
    +Rule	Cuba	1945	1946	-	Sep	Sun>=1	0:00	0	S
    +Rule	Cuba	1965	only	-	Jun	1	0:00	1:00	D
    +Rule	Cuba	1965	only	-	Sep	30	0:00	0	S
    +Rule	Cuba	1966	only	-	May	29	0:00	1:00	D
    +Rule	Cuba	1966	only	-	Oct	2	0:00	0	S
    +Rule	Cuba	1967	only	-	Apr	8	0:00	1:00	D
    +Rule	Cuba	1967	1968	-	Sep	Sun>=8	0:00	0	S
    +Rule	Cuba	1968	only	-	Apr	14	0:00	1:00	D
    +Rule	Cuba	1969	1977	-	Apr	lastSun	0:00	1:00	D
    +Rule	Cuba	1969	1971	-	Oct	lastSun	0:00	0	S
    +Rule	Cuba	1972	1974	-	Oct	8	0:00	0	S
    +Rule	Cuba	1975	1977	-	Oct	lastSun	0:00	0	S
    +Rule	Cuba	1978	only	-	May	7	0:00	1:00	D
    +Rule	Cuba	1978	1990	-	Oct	Sun>=8	0:00	0	S
    +Rule	Cuba	1979	1980	-	Mar	Sun>=15	0:00	1:00	D
    +Rule	Cuba	1981	1985	-	May	Sun>=5	0:00	1:00	D
    +Rule	Cuba	1986	1989	-	Mar	Sun>=14	0:00	1:00	D
    +Rule	Cuba	1990	1997	-	Apr	Sun>=1	0:00	1:00	D
    +Rule	Cuba	1991	1995	-	Oct	Sun>=8	0:00s	0	S
    +Rule	Cuba	1996	only	-	Oct	 6	0:00s	0	S
    +Rule	Cuba	1997	only	-	Oct	12	0:00s	0	S
    +Rule	Cuba	1998	1999	-	Mar	lastSun	0:00s	1:00	D
    +Rule	Cuba	1998	2003	-	Oct	lastSun	0:00s	0	S
    +Rule	Cuba	2000	2004	-	Apr	Sun>=1	0:00s	1:00	D
    +Rule	Cuba	2006	2010	-	Oct	lastSun	0:00s	0	S
    +Rule	Cuba	2007	only	-	Mar	Sun>=8	0:00s	1:00	D
    +Rule	Cuba	2008	only	-	Mar	Sun>=15	0:00s	1:00	D
    +Rule	Cuba	2009	2010	-	Mar	Sun>=8	0:00s	1:00	D
    +Rule	Cuba	2011	only	-	Mar	Sun>=15	0:00s	1:00	D
    +Rule	Cuba	2011	only	-	Nov	13	0:00s	0	S
    +Rule	Cuba	2012	only	-	Apr	1	0:00s	1:00	D
    +Rule	Cuba	2012	max	-	Nov	Sun>=1	0:00s	0	S
    +Rule	Cuba	2013	max	-	Mar	Sun>=8	0:00s	1:00	D
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Havana	-5:29:28 -	LMT	1890
    +			-5:29:36 -	HMT	1925 Jul 19 12:00 # Havana MT
    +			-5:00	Cuba	C%sT
    +
    +# Dominica
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Dominica	-4:05:36 -	LMT	1911 Jul 1 0:01		# Roseau
    +			-4:00	-	AST
    +
    +# Dominican Republic
    +
    +# From Steffen Thorsen (2000-10-30):
    +# Enrique Morales reported to me that the Dominican Republic has changed the
    +# time zone to Eastern Standard Time as of Sunday 29 at 2 am....
    +# http://www.listin.com.do/antes/261000/republica/princi.html
    +
    +# From Paul Eggert (2000-12-04):
    +# That URL (2000-10-26, in Spanish) says they planned to use US-style DST.
    +
    +# From Rives McDow (2000-12-01):
    +# Dominican Republic changed its mind and presidential decree on Tuesday,
    +# November 28, 2000, with a new decree.  On Sunday, December 3 at 1:00 AM the
    +# Dominican Republic will be reverting to 8 hours from the International Date
    +# Line, and will not be using DST in the foreseeable future.  The reason they
    +# decided to use DST was to be in synch with Puerto Rico, who was also going
    +# to implement DST.  When Puerto Rico didn't implement DST, the president
    +# decided to revert.
    +
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	DR	1966	only	-	Oct	30	0:00	1:00	D
    +Rule	DR	1967	only	-	Feb	28	0:00	0	S
    +Rule	DR	1969	1973	-	Oct	lastSun	0:00	0:30	HD
    +Rule	DR	1970	only	-	Feb	21	0:00	0	S
    +Rule	DR	1971	only	-	Jan	20	0:00	0	S
    +Rule	DR	1972	1974	-	Jan	21	0:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Santo_Domingo -4:39:36 -	LMT	1890
    +			-4:40	-	SDMT	1933 Apr  1 12:00 # S. Dom. MT
    +			-5:00	DR	E%sT	1974 Oct 27
    +			-4:00	-	AST	2000 Oct 29 02:00
    +			-5:00	US	E%sT	2000 Dec  3 01:00
    +			-4:00	-	AST
    +
    +# El Salvador
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Salv	1987	1988	-	May	Sun>=1	0:00	1:00	D
    +Rule	Salv	1987	1988	-	Sep	lastSun	0:00	0	S
    +# There are too many San Salvadors elsewhere, so use America/El_Salvador
    +# instead of America/San_Salvador.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/El_Salvador -5:56:48 -	LMT	1921		# San Salvador
    +			-6:00	Salv	C%sT
    +
    +# Grenada
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Grenada	-4:07:00 -	LMT	1911 Jul	# St George's
    +			-4:00	-	AST
    +
    +# Guadeloupe
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Guadeloupe	-4:06:08 -	LMT	1911 Jun 8	# Pointe a Pitre
    +			-4:00	-	AST
    +# St Barthelemy
    +Link America/Guadeloupe	America/St_Barthelemy
    +# St Martin (French part)
    +Link America/Guadeloupe	America/Marigot
    +
    +# Guatemala
    +#
    +# From Gwillim Law (2006-04-22), after a heads-up from Oscar van Vlijmen:
    +# Diario Co Latino, at
    +# http://www.diariocolatino.com/internacionales/detalles.asp?NewsID=8079,
    +# says in an article dated 2006-04-19 that the Guatemalan government had
    +# decided on that date to advance official time by 60 minutes, to lessen the
    +# impact of the elevated cost of oil....  Daylight saving time will last from
    +# 2006-04-29 24:00 (Guatemalan standard time) to 2006-09-30 (time unspecified).
    +# From Paul Eggert (2006-06-22):
    +# The Ministry of Energy and Mines, press release CP-15/2006
    +# (2006-04-19), says DST ends at 24:00.  See
    +# .
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Guat	1973	only	-	Nov	25	0:00	1:00	D
    +Rule	Guat	1974	only	-	Feb	24	0:00	0	S
    +Rule	Guat	1983	only	-	May	21	0:00	1:00	D
    +Rule	Guat	1983	only	-	Sep	22	0:00	0	S
    +Rule	Guat	1991	only	-	Mar	23	0:00	1:00	D
    +Rule	Guat	1991	only	-	Sep	 7	0:00	0	S
    +Rule	Guat	2006	only	-	Apr	30	0:00	1:00	D
    +Rule	Guat	2006	only	-	Oct	 1	0:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Guatemala	-6:02:04 -	LMT	1918 Oct 5
    +			-6:00	Guat	C%sT
    +
    +# Haiti
    +# From Gwillim Law (2005-04-15):
    +# Risto O. Nykanen wrote me that Haiti is now on DST.
    +# I searched for confirmation, and I found a
    +#  press release
    +# on the Web page of the Haitian Consulate in Chicago (2005-03-31),
    +# .  Translated from French, it says:
    +#
    +#  "The Prime Minister's Communication Office notifies the public in general
    +#   and the press in particular that, following a decision of the Interior
    +#   Ministry and the Territorial Collectivities [I suppose that means the
    +#   provinces], Haiti will move to Eastern Daylight Time in the night from next
    +#   Saturday the 2nd to Sunday the 3rd.
    +#
    +#  "Consequently, the Prime Minister's Communication Office wishes to inform
    +#   the population that the country's clocks will be set forward one hour
    +#   starting at midnight.  This provision will hold until the last Saturday in
    +#   October 2005.
    +#
    +#  "Port-au-Prince, March 31, 2005"
    +#
    +# From Steffen Thorsen (2006-04-04):
    +# I have been informed by users that Haiti observes DST this year like
    +# last year, so the current "only" rule for 2005 might be changed to a
    +# "max" rule or to last until 2006. (Who knows if they will observe DST
    +# next year or if they will extend their DST like US/Canada next year).
    +#
    +# I have found this article about it (in French):
    +# http://www.haitipressnetwork.com/news.cfm?articleID=7612
    +#
    +# The reason seems to be an energy crisis.
    +
    +# From Stephen Colebourne (2007-02-22):
    +# Some IATA info: Haiti won't be having DST in 2007.
    +
    +# From Steffen Thorsen (2012-03-11):
    +# According to several news sources, Haiti will observe DST this year,
    +# apparently using the same start and end date as USA/Canada.
    +# So this means they have already changed their time.
    +#
    +# (Sources in French):
    +# 
    +# http://www.alterpresse.org/spip.php?article12510
    +# 
    +# 
    +# http://radiovision2000haiti.net/home/?p=13253
    +# 
    +#
    +# Our coverage:
    +# 
    +# http://www.timeanddate.com/news/time/haiti-dst-2012.html
    +# 
    +
    +# From Arthur David Olson (2012-03-11):
    +# The alterpresse.org source seems to show a US-style leap from 2:00 a.m. to
    +# 3:00 a.m. rather than the traditional Haitian jump at midnight.
    +# Assume a US-style fall back as well XXX.
    +# Do not yet assume that the change carries forward past 2012 XXX.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Haiti	1983	only	-	May	8	0:00	1:00	D
    +Rule	Haiti	1984	1987	-	Apr	lastSun	0:00	1:00	D
    +Rule	Haiti	1983	1987	-	Oct	lastSun	0:00	0	S
    +# Shanks & Pottenger say AT is 2:00, but IATA SSIM (1991/1997) says 1:00s.
    +# Go with IATA.
    +Rule	Haiti	1988	1997	-	Apr	Sun>=1	1:00s	1:00	D
    +Rule	Haiti	1988	1997	-	Oct	lastSun	1:00s	0	S
    +Rule	Haiti	2005	2006	-	Apr	Sun>=1	0:00	1:00	D
    +Rule	Haiti	2005	2006	-	Oct	lastSun	0:00	0	S
    +Rule	Haiti	2012	only	-	Mar	Sun>=8	2:00	1:00	D
    +Rule	Haiti	2012	only	-	Nov	Sun>=1	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Port-au-Prince -4:49:20 -	LMT	1890
    +			-4:49	-	PPMT	1917 Jan 24 12:00 # P-a-P MT
    +			-5:00	Haiti	E%sT
    +
    +# Honduras
    +# Shanks & Pottenger say 1921 Jan 1; go with Whitman's more precise Apr 1.
    +
    +# From Paul Eggert (2006-05-05):
    +# worldtimezone.com reports a 2006-05-02 Spanish-language AP article
    +# saying Honduras will start using DST midnight Saturday, effective 4
    +# months until September.  La Tribuna reported today
    +#  that Manuel Zelaya, the president
    +# of Honduras, refused to back down on this.
    +
    +# From Jesper Norgaard Welen (2006-08-08):
    +# It seems that Honduras has returned from DST to standard time this Monday at
    +# 00:00 hours (prolonging Sunday to 25 hours duration).
    +# http://www.worldtimezone.com/dst_news/dst_news_honduras04.html
    +
    +# From Paul Eggert (2006-08-08):
    +# Also see Diario El Heraldo, The country returns to standard time (2006-08-08)
    +# .
    +# It mentions executive decree 18-2006.
    +
    +# From Steffen Thorsen (2006-08-17):
    +# Honduras will observe DST from 2007 to 2009, exact dates are not
    +# published, I have located this authoritative source:
    +# http://www.presidencia.gob.hn/noticia.aspx?nId=47
    +
    +# From Steffen Thorsen (2007-03-30):
    +# http://www.laprensahn.com/pais_nota.php?id04962=7386
    +# So it seems that Honduras will not enter DST this year....
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Hond	1987	1988	-	May	Sun>=1	0:00	1:00	D
    +Rule	Hond	1987	1988	-	Sep	lastSun	0:00	0	S
    +Rule	Hond	2006	only	-	May	Sun>=1	0:00	1:00	D
    +Rule	Hond	2006	only	-	Aug	Mon>=1	0:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Tegucigalpa -5:48:52 -	LMT	1921 Apr
    +			-6:00	Hond	C%sT
    +#
    +# Great Swan I ceded by US to Honduras in 1972
    +
    +# Jamaica
    +
    +# From Bob Devine (1988-01-28):
    +# Follows US rules.
    +
    +# From U. S. Naval Observatory (1989-01-19):
    +# JAMAICA             5 H  BEHIND UTC
    +
    +# From Shanks & Pottenger:
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Jamaica	-5:07:12 -	LMT	1890		# Kingston
    +			-5:07:12 -	KMT	1912 Feb    # Kingston Mean Time
    +			-5:00	-	EST	1974 Apr 28 2:00
    +			-5:00	US	E%sT	1984
    +			-5:00	-	EST
    +
    +# Martinique
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Martinique	-4:04:20 -      LMT	1890		# Fort-de-France
    +			-4:04:20 -	FFMT	1911 May     # Fort-de-France MT
    +			-4:00	-	AST	1980 Apr  6
    +			-4:00	1:00	ADT	1980 Sep 28
    +			-4:00	-	AST
    +
    +# Montserrat
    +# From Paul Eggert (2006-03-22):
    +# In 1995 volcanic eruptions forced evacuation of Plymouth, the capital.
    +# world.gazetteer.com says Cork Hill is the most populous location now.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Montserrat	-4:08:52 -	LMT	1911 Jul 1 0:01   # Cork Hill
    +			-4:00	-	AST
    +
    +# Nicaragua
    +#
    +# This uses Shanks & Pottenger for times before 2005.
    +#
    +# From Steffen Thorsen (2005-04-12):
    +# I've got reports from 8 different people that Nicaragua just started
    +# DST on Sunday 2005-04-10, in order to save energy because of
    +# expensive petroleum.  The exact end date for DST is not yet
    +# announced, only "September" but some sites also say "mid-September".
    +# Some background information is available on the President's official site:
    +# http://www.presidencia.gob.ni/Presidencia/Files_index/Secretaria/Notas%20de%20Prensa/Presidente/2005/ABRIL/Gobierno-de-nicaragua-adelanta-hora-oficial-06abril.htm
    +# The Decree, no 23-2005 is available here:
    +# http://www.presidencia.gob.ni/buscador_gaceta/BD/DECRETOS/2005/Decreto%2023-2005%20Se%20adelanta%20en%20una%20hora%20en%20todo%20el%20territorio%20nacional%20apartir%20de%20las%2024horas%20del%2009%20de%20Abril.pdf
    +#
    +# From Paul Eggert (2005-05-01):
    +# The decree doesn't say anything about daylight saving, but for now let's
    +# assume that it is daylight saving....
    +#
    +# From Gwillim Law (2005-04-21):
    +# The Associated Press story on the time change, which can be found at
    +# http://www.lapalmainteractivo.com/guias/content/gen/ap/America_Latina/AMC_GEN_NICARAGUA_HORA.html
    +# and elsewhere, says (fifth paragraph, translated from Spanish):  "The last
    +# time that a change of clocks was applied to save energy was in the year 2000
    +# during the Arnoldo Aleman administration."...
    +# The northamerica file says that Nicaragua has been on UTC-6 continuously
    +# since December 1998.  I wasn't able to find any details of Nicaraguan time
    +# changes in 2000.  Perhaps a note could be added to the northamerica file, to
    +# the effect that we have indirect evidence that DST was observed in 2000.
    +#
    +# From Jesper Norgaard Welen (2005-11-02):
    +# Nicaragua left DST the 2005-10-02 at 00:00 (local time).
    +# http://www.presidencia.gob.ni/presidencia/files_index/secretaria/comunicados/2005/septiembre/26septiembre-cambio-hora.htm
    +# (2005-09-26)
    +#
    +# From Jesper Norgaard Welen (2006-05-05):
    +# http://www.elnuevodiario.com.ni/2006/05/01/nacionales/18410
    +# (my informal translation)
    +# By order of the president of the republic, Enrique Bolanos, Nicaragua
    +# advanced by sixty minutes their official time, yesterday at 2 in the
    +# morning, and will stay that way until 30.th. of september.
    +#
    +# From Jesper Norgaard Welen (2006-09-30):
    +# http://www.presidencia.gob.ni/buscador_gaceta/BD/DECRETOS/2006/D-063-2006P-PRN-Cambio-Hora.pdf
    +# My informal translation runs:
    +# The natural sun time is restored in all the national territory, in that the
    +# time is returned one hour at 01:00 am of October 1 of 2006.
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Nic	1979	1980	-	Mar	Sun>=16	0:00	1:00	D
    +Rule	Nic	1979	1980	-	Jun	Mon>=23	0:00	0	S
    +Rule	Nic	2005	only	-	Apr	10	0:00	1:00	D
    +Rule	Nic	2005	only	-	Oct	Sun>=1	0:00	0	S
    +Rule	Nic	2006	only	-	Apr	30	2:00	1:00	D
    +Rule	Nic	2006	only	-	Oct	Sun>=1	1:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Managua	-5:45:08 -	LMT	1890
    +			-5:45:12 -	MMT	1934 Jun 23 # Managua Mean Time?
    +			-6:00	-	CST	1973 May
    +			-5:00	-	EST	1975 Feb 16
    +			-6:00	Nic	C%sT	1992 Jan  1 4:00
    +			-5:00	-	EST	1992 Sep 24
    +			-6:00	-	CST	1993
    +			-5:00	-	EST	1997
    +			-6:00	Nic	C%sT
    +
    +# Panama
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Panama	-5:18:08 -	LMT	1890
    +			-5:19:36 -	CMT	1908 Apr 22   # Colon Mean Time
    +			-5:00	-	EST
    +
    +# Puerto Rico
    +# There are too many San Juans elsewhere, so we'll use `Puerto_Rico'.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Puerto_Rico -4:24:25 -	LMT	1899 Mar 28 12:00    # San Juan
    +			-4:00	-	AST	1942 May  3
    +			-4:00	US	A%sT	1946
    +			-4:00	-	AST
    +
    +# St Kitts-Nevis
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/St_Kitts	-4:10:52 -	LMT	1912 Mar 2	# Basseterre
    +			-4:00	-	AST
    +
    +# St Lucia
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/St_Lucia	-4:04:00 -	LMT	1890		# Castries
    +			-4:04:00 -	CMT	1912	    # Castries Mean Time
    +			-4:00	-	AST
    +
    +# St Pierre and Miquelon
    +# There are too many St Pierres elsewhere, so we'll use `Miquelon'.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Miquelon	-3:44:40 -	LMT	1911 May 15	# St Pierre
    +			-4:00	-	AST	1980 May
    +			-3:00	-	PMST	1987 # Pierre & Miquelon Time
    +			-3:00	Canada	PM%sT
    +
    +# St Vincent and the Grenadines
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/St_Vincent	-4:04:56 -	LMT	1890		# Kingstown
    +			-4:04:56 -	KMT	1912	   # Kingstown Mean Time
    +			-4:00	-	AST
    +
    +# Turks and Caicos
    +#
    +# From Chris Dunn in
    +# 
    +# (2007-03-15): In the Turks & Caicos Islands (America/Grand_Turk) the
    +# daylight saving dates for time changes have been adjusted to match
    +# the recent U.S. change of dates.
    +#
    +# From Brian Inglis (2007-04-28):
    +# http://www.turksandcaicos.tc/calendar/index.htm [2007-04-26]
    +# there is an entry for Nov 4 "Daylight Savings Time Ends 2007" and three
    +# rows before that there is an out of date entry for Oct:
    +# "Eastern Standard Times Begins 2007
    +# Clocks are set back one hour at 2:00 a.m. local Daylight Saving Time"
    +# indicating that the normal ET rules are followed.
    +#
    +# From Paul Eggert (2006-05-01):
    +# Shanks & Pottenger say they use US DST rules, but IATA SSIM (1991/1998)
    +# says they switch at midnight.  Go with Shanks & Pottenger.
    +#
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	TC	1979	1986	-	Apr	lastSun	2:00	1:00	D
    +Rule	TC	1979	2006	-	Oct	lastSun	2:00	0	S
    +Rule	TC	1987	2006	-	Apr	Sun>=1	2:00	1:00	D
    +Rule	TC	2007	max	-	Mar	Sun>=8	2:00	1:00	D
    +Rule	TC	2007	max	-	Nov	Sun>=1	2:00	0	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Grand_Turk	-4:44:32 -	LMT	1890
    +			-5:07:12 -	KMT	1912 Feb    # Kingston Mean Time
    +			-5:00	TC	E%sT
    +
    +# British Virgin Is
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Tortola	-4:18:28 -	LMT	1911 Jul    # Road Town
    +			-4:00	-	AST
    +
    +# Virgin Is
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/St_Thomas	-4:19:44 -	LMT	1911 Jul    # Charlotte Amalie
    +			-4:00	-	AST
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/pacificnew b/jdk/test/sun/util/calendar/zi/tzdata/pacificnew
    new file mode 100644
    index 00000000000..7738a48087b
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/pacificnew
    @@ -0,0 +1,51 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# From Arthur David Olson (1989-04-05):
    +# On 1989-04-05, the U. S. House of Representatives passed (238-154) a bill
    +# establishing "Pacific Presidential Election Time"; it was not acted on
    +# by the Senate or signed into law by the President.
    +# You might want to change the "PE" (Presidential Election) below to
    +# "Q" (Quadrennial) to maintain three-character zone abbreviations.
    +# If you're really conservative, you might want to change it to "D".
    +# Avoid "L" (Leap Year), which won't be true in 2100.
    +
    +# If Presidential Election Time is ever established, replace "XXXX" below
    +# with the year the law takes effect and uncomment the "##" lines.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +## Rule	Twilite	XXXX	max	-	Apr	Sun>=1	2:00	1:00	D
    +## Rule	Twilite	XXXX	max	uspres	Oct	lastSun	2:00	1:00	PE
    +## Rule	Twilite	XXXX	max	uspres	Nov	Sun>=7	2:00	0	S
    +## Rule	Twilite	XXXX	max	nonpres	Oct	lastSun	2:00	0	S
    +
    +# Zone	NAME			GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
    +## Zone	America/Los_Angeles-PET	-8:00	US		P%sT	XXXX
    +##				-8:00	Twilite		P%sT
    +
    +# For now...
    +Link	America/Los_Angeles	US/Pacific-New	##
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/solar87 b/jdk/test/sun/util/calendar/zi/tzdata/solar87
    new file mode 100644
    index 00000000000..46b1d56025f
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/solar87
    @@ -0,0 +1,413 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# So much for footnotes about Saudi Arabia.
    +# Apparent noon times below are for Riyadh; your mileage will vary.
    +# Times were computed using formulas in the U.S. Naval Observatory's
    +# Almanac for Computers 1987; the formulas "will give EqT to an accuracy of
    +# [plus or minus two] seconds during the current year."
    +#
    +# Rounding to the nearest five seconds results in fewer than
    +# 256 different "time types"--a limit that's faced because time types are
    +# stored on disk as unsigned chars.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	sol87	1987	only	-	Jan	1	12:03:20s -0:03:20 -
    +Rule	sol87	1987	only	-	Jan	2	12:03:50s -0:03:50 -
    +Rule	sol87	1987	only	-	Jan	3	12:04:15s -0:04:15 -
    +Rule	sol87	1987	only	-	Jan	4	12:04:45s -0:04:45 -
    +Rule	sol87	1987	only	-	Jan	5	12:05:10s -0:05:10 -
    +Rule	sol87	1987	only	-	Jan	6	12:05:40s -0:05:40 -
    +Rule	sol87	1987	only	-	Jan	7	12:06:05s -0:06:05 -
    +Rule	sol87	1987	only	-	Jan	8	12:06:30s -0:06:30 -
    +Rule	sol87	1987	only	-	Jan	9	12:06:55s -0:06:55 -
    +Rule	sol87	1987	only	-	Jan	10	12:07:20s -0:07:20 -
    +Rule	sol87	1987	only	-	Jan	11	12:07:45s -0:07:45 -
    +Rule	sol87	1987	only	-	Jan	12	12:08:10s -0:08:10 -
    +Rule	sol87	1987	only	-	Jan	13	12:08:30s -0:08:30 -
    +Rule	sol87	1987	only	-	Jan	14	12:08:55s -0:08:55 -
    +Rule	sol87	1987	only	-	Jan	15	12:09:15s -0:09:15 -
    +Rule	sol87	1987	only	-	Jan	16	12:09:35s -0:09:35 -
    +Rule	sol87	1987	only	-	Jan	17	12:09:55s -0:09:55 -
    +Rule	sol87	1987	only	-	Jan	18	12:10:15s -0:10:15 -
    +Rule	sol87	1987	only	-	Jan	19	12:10:35s -0:10:35 -
    +Rule	sol87	1987	only	-	Jan	20	12:10:55s -0:10:55 -
    +Rule	sol87	1987	only	-	Jan	21	12:11:10s -0:11:10 -
    +Rule	sol87	1987	only	-	Jan	22	12:11:30s -0:11:30 -
    +Rule	sol87	1987	only	-	Jan	23	12:11:45s -0:11:45 -
    +Rule	sol87	1987	only	-	Jan	24	12:12:00s -0:12:00 -
    +Rule	sol87	1987	only	-	Jan	25	12:12:15s -0:12:15 -
    +Rule	sol87	1987	only	-	Jan	26	12:12:30s -0:12:30 -
    +Rule	sol87	1987	only	-	Jan	27	12:12:40s -0:12:40 -
    +Rule	sol87	1987	only	-	Jan	28	12:12:55s -0:12:55 -
    +Rule	sol87	1987	only	-	Jan	29	12:13:05s -0:13:05 -
    +Rule	sol87	1987	only	-	Jan	30	12:13:15s -0:13:15 -
    +Rule	sol87	1987	only	-	Jan	31	12:13:25s -0:13:25 -
    +Rule	sol87	1987	only	-	Feb	1	12:13:35s -0:13:35 -
    +Rule	sol87	1987	only	-	Feb	2	12:13:40s -0:13:40 -
    +Rule	sol87	1987	only	-	Feb	3	12:13:50s -0:13:50 -
    +Rule	sol87	1987	only	-	Feb	4	12:13:55s -0:13:55 -
    +Rule	sol87	1987	only	-	Feb	5	12:14:00s -0:14:00 -
    +Rule	sol87	1987	only	-	Feb	6	12:14:05s -0:14:05 -
    +Rule	sol87	1987	only	-	Feb	7	12:14:10s -0:14:10 -
    +Rule	sol87	1987	only	-	Feb	8	12:14:10s -0:14:10 -
    +Rule	sol87	1987	only	-	Feb	9	12:14:15s -0:14:15 -
    +Rule	sol87	1987	only	-	Feb	10	12:14:15s -0:14:15 -
    +Rule	sol87	1987	only	-	Feb	11	12:14:15s -0:14:15 -
    +Rule	sol87	1987	only	-	Feb	12	12:14:15s -0:14:15 -
    +Rule	sol87	1987	only	-	Feb	13	12:14:15s -0:14:15 -
    +Rule	sol87	1987	only	-	Feb	14	12:14:15s -0:14:15 -
    +Rule	sol87	1987	only	-	Feb	15	12:14:10s -0:14:10 -
    +Rule	sol87	1987	only	-	Feb	16	12:14:10s -0:14:10 -
    +Rule	sol87	1987	only	-	Feb	17	12:14:05s -0:14:05 -
    +Rule	sol87	1987	only	-	Feb	18	12:14:00s -0:14:00 -
    +Rule	sol87	1987	only	-	Feb	19	12:13:55s -0:13:55 -
    +Rule	sol87	1987	only	-	Feb	20	12:13:50s -0:13:50 -
    +Rule	sol87	1987	only	-	Feb	21	12:13:45s -0:13:45 -
    +Rule	sol87	1987	only	-	Feb	22	12:13:35s -0:13:35 -
    +Rule	sol87	1987	only	-	Feb	23	12:13:30s -0:13:30 -
    +Rule	sol87	1987	only	-	Feb	24	12:13:20s -0:13:20 -
    +Rule	sol87	1987	only	-	Feb	25	12:13:10s -0:13:10 -
    +Rule	sol87	1987	only	-	Feb	26	12:13:00s -0:13:00 -
    +Rule	sol87	1987	only	-	Feb	27	12:12:50s -0:12:50 -
    +Rule	sol87	1987	only	-	Feb	28	12:12:40s -0:12:40 -
    +Rule	sol87	1987	only	-	Mar	1	12:12:30s -0:12:30 -
    +Rule	sol87	1987	only	-	Mar	2	12:12:20s -0:12:20 -
    +Rule	sol87	1987	only	-	Mar	3	12:12:05s -0:12:05 -
    +Rule	sol87	1987	only	-	Mar	4	12:11:55s -0:11:55 -
    +Rule	sol87	1987	only	-	Mar	5	12:11:40s -0:11:40 -
    +Rule	sol87	1987	only	-	Mar	6	12:11:25s -0:11:25 -
    +Rule	sol87	1987	only	-	Mar	7	12:11:15s -0:11:15 -
    +Rule	sol87	1987	only	-	Mar	8	12:11:00s -0:11:00 -
    +Rule	sol87	1987	only	-	Mar	9	12:10:45s -0:10:45 -
    +Rule	sol87	1987	only	-	Mar	10	12:10:30s -0:10:30 -
    +Rule	sol87	1987	only	-	Mar	11	12:10:15s -0:10:15 -
    +Rule	sol87	1987	only	-	Mar	12	12:09:55s -0:09:55 -
    +Rule	sol87	1987	only	-	Mar	13	12:09:40s -0:09:40 -
    +Rule	sol87	1987	only	-	Mar	14	12:09:25s -0:09:25 -
    +Rule	sol87	1987	only	-	Mar	15	12:09:10s -0:09:10 -
    +Rule	sol87	1987	only	-	Mar	16	12:08:50s -0:08:50 -
    +Rule	sol87	1987	only	-	Mar	17	12:08:35s -0:08:35 -
    +Rule	sol87	1987	only	-	Mar	18	12:08:15s -0:08:15 -
    +Rule	sol87	1987	only	-	Mar	19	12:08:00s -0:08:00 -
    +Rule	sol87	1987	only	-	Mar	20	12:07:40s -0:07:40 -
    +Rule	sol87	1987	only	-	Mar	21	12:07:25s -0:07:25 -
    +Rule	sol87	1987	only	-	Mar	22	12:07:05s -0:07:05 -
    +Rule	sol87	1987	only	-	Mar	23	12:06:50s -0:06:50 -
    +Rule	sol87	1987	only	-	Mar	24	12:06:30s -0:06:30 -
    +Rule	sol87	1987	only	-	Mar	25	12:06:10s -0:06:10 -
    +Rule	sol87	1987	only	-	Mar	26	12:05:55s -0:05:55 -
    +Rule	sol87	1987	only	-	Mar	27	12:05:35s -0:05:35 -
    +Rule	sol87	1987	only	-	Mar	28	12:05:15s -0:05:15 -
    +Rule	sol87	1987	only	-	Mar	29	12:05:00s -0:05:00 -
    +Rule	sol87	1987	only	-	Mar	30	12:04:40s -0:04:40 -
    +Rule	sol87	1987	only	-	Mar	31	12:04:25s -0:04:25 -
    +Rule	sol87	1987	only	-	Apr	1	12:04:05s -0:04:05 -
    +Rule	sol87	1987	only	-	Apr	2	12:03:45s -0:03:45 -
    +Rule	sol87	1987	only	-	Apr	3	12:03:30s -0:03:30 -
    +Rule	sol87	1987	only	-	Apr	4	12:03:10s -0:03:10 -
    +Rule	sol87	1987	only	-	Apr	5	12:02:55s -0:02:55 -
    +Rule	sol87	1987	only	-	Apr	6	12:02:35s -0:02:35 -
    +Rule	sol87	1987	only	-	Apr	7	12:02:20s -0:02:20 -
    +Rule	sol87	1987	only	-	Apr	8	12:02:05s -0:02:05 -
    +Rule	sol87	1987	only	-	Apr	9	12:01:45s -0:01:45 -
    +Rule	sol87	1987	only	-	Apr	10	12:01:30s -0:01:30 -
    +Rule	sol87	1987	only	-	Apr	11	12:01:15s -0:01:15 -
    +Rule	sol87	1987	only	-	Apr	12	12:00:55s -0:00:55 -
    +Rule	sol87	1987	only	-	Apr	13	12:00:40s -0:00:40 -
    +Rule	sol87	1987	only	-	Apr	14	12:00:25s -0:00:25 -
    +Rule	sol87	1987	only	-	Apr	15	12:00:10s -0:00:10 -
    +Rule	sol87	1987	only	-	Apr	16	11:59:55s 0:00:05 -
    +Rule	sol87	1987	only	-	Apr	17	11:59:45s 0:00:15 -
    +Rule	sol87	1987	only	-	Apr	18	11:59:30s 0:00:30 -
    +Rule	sol87	1987	only	-	Apr	19	11:59:15s 0:00:45 -
    +Rule	sol87	1987	only	-	Apr	20	11:59:05s 0:00:55 -
    +Rule	sol87	1987	only	-	Apr	21	11:58:50s 0:01:10 -
    +Rule	sol87	1987	only	-	Apr	22	11:58:40s 0:01:20 -
    +Rule	sol87	1987	only	-	Apr	23	11:58:25s 0:01:35 -
    +Rule	sol87	1987	only	-	Apr	24	11:58:15s 0:01:45 -
    +Rule	sol87	1987	only	-	Apr	25	11:58:05s 0:01:55 -
    +Rule	sol87	1987	only	-	Apr	26	11:57:55s 0:02:05 -
    +Rule	sol87	1987	only	-	Apr	27	11:57:45s 0:02:15 -
    +Rule	sol87	1987	only	-	Apr	28	11:57:35s 0:02:25 -
    +Rule	sol87	1987	only	-	Apr	29	11:57:25s 0:02:35 -
    +Rule	sol87	1987	only	-	Apr	30	11:57:15s 0:02:45 -
    +Rule	sol87	1987	only	-	May	1	11:57:10s 0:02:50 -
    +Rule	sol87	1987	only	-	May	2	11:57:00s 0:03:00 -
    +Rule	sol87	1987	only	-	May	3	11:56:55s 0:03:05 -
    +Rule	sol87	1987	only	-	May	4	11:56:50s 0:03:10 -
    +Rule	sol87	1987	only	-	May	5	11:56:45s 0:03:15 -
    +Rule	sol87	1987	only	-	May	6	11:56:40s 0:03:20 -
    +Rule	sol87	1987	only	-	May	7	11:56:35s 0:03:25 -
    +Rule	sol87	1987	only	-	May	8	11:56:30s 0:03:30 -
    +Rule	sol87	1987	only	-	May	9	11:56:25s 0:03:35 -
    +Rule	sol87	1987	only	-	May	10	11:56:25s 0:03:35 -
    +Rule	sol87	1987	only	-	May	11	11:56:20s 0:03:40 -
    +Rule	sol87	1987	only	-	May	12	11:56:20s 0:03:40 -
    +Rule	sol87	1987	only	-	May	13	11:56:20s 0:03:40 -
    +Rule	sol87	1987	only	-	May	14	11:56:20s 0:03:40 -
    +Rule	sol87	1987	only	-	May	15	11:56:20s 0:03:40 -
    +Rule	sol87	1987	only	-	May	16	11:56:20s 0:03:40 -
    +Rule	sol87	1987	only	-	May	17	11:56:20s 0:03:40 -
    +Rule	sol87	1987	only	-	May	18	11:56:20s 0:03:40 -
    +Rule	sol87	1987	only	-	May	19	11:56:25s 0:03:35 -
    +Rule	sol87	1987	only	-	May	20	11:56:25s 0:03:35 -
    +Rule	sol87	1987	only	-	May	21	11:56:30s 0:03:30 -
    +Rule	sol87	1987	only	-	May	22	11:56:35s 0:03:25 -
    +Rule	sol87	1987	only	-	May	23	11:56:40s 0:03:20 -
    +Rule	sol87	1987	only	-	May	24	11:56:45s 0:03:15 -
    +Rule	sol87	1987	only	-	May	25	11:56:50s 0:03:10 -
    +Rule	sol87	1987	only	-	May	26	11:56:55s 0:03:05 -
    +Rule	sol87	1987	only	-	May	27	11:57:00s 0:03:00 -
    +Rule	sol87	1987	only	-	May	28	11:57:10s 0:02:50 -
    +Rule	sol87	1987	only	-	May	29	11:57:15s 0:02:45 -
    +Rule	sol87	1987	only	-	May	30	11:57:25s 0:02:35 -
    +Rule	sol87	1987	only	-	May	31	11:57:30s 0:02:30 -
    +Rule	sol87	1987	only	-	Jun	1	11:57:40s 0:02:20 -
    +Rule	sol87	1987	only	-	Jun	2	11:57:50s 0:02:10 -
    +Rule	sol87	1987	only	-	Jun	3	11:58:00s 0:02:00 -
    +Rule	sol87	1987	only	-	Jun	4	11:58:10s 0:01:50 -
    +Rule	sol87	1987	only	-	Jun	5	11:58:20s 0:01:40 -
    +Rule	sol87	1987	only	-	Jun	6	11:58:30s 0:01:30 -
    +Rule	sol87	1987	only	-	Jun	7	11:58:40s 0:01:20 -
    +Rule	sol87	1987	only	-	Jun	8	11:58:50s 0:01:10 -
    +Rule	sol87	1987	only	-	Jun	9	11:59:05s 0:00:55 -
    +Rule	sol87	1987	only	-	Jun	10	11:59:15s 0:00:45 -
    +Rule	sol87	1987	only	-	Jun	11	11:59:30s 0:00:30 -
    +Rule	sol87	1987	only	-	Jun	12	11:59:40s 0:00:20 -
    +Rule	sol87	1987	only	-	Jun	13	11:59:50s 0:00:10 -
    +Rule	sol87	1987	only	-	Jun	14	12:00:05s -0:00:05 -
    +Rule	sol87	1987	only	-	Jun	15	12:00:15s -0:00:15 -
    +Rule	sol87	1987	only	-	Jun	16	12:00:30s -0:00:30 -
    +Rule	sol87	1987	only	-	Jun	17	12:00:45s -0:00:45 -
    +Rule	sol87	1987	only	-	Jun	18	12:00:55s -0:00:55 -
    +Rule	sol87	1987	only	-	Jun	19	12:01:10s -0:01:10 -
    +Rule	sol87	1987	only	-	Jun	20	12:01:20s -0:01:20 -
    +Rule	sol87	1987	only	-	Jun	21	12:01:35s -0:01:35 -
    +Rule	sol87	1987	only	-	Jun	22	12:01:50s -0:01:50 -
    +Rule	sol87	1987	only	-	Jun	23	12:02:00s -0:02:00 -
    +Rule	sol87	1987	only	-	Jun	24	12:02:15s -0:02:15 -
    +Rule	sol87	1987	only	-	Jun	25	12:02:25s -0:02:25 -
    +Rule	sol87	1987	only	-	Jun	26	12:02:40s -0:02:40 -
    +Rule	sol87	1987	only	-	Jun	27	12:02:50s -0:02:50 -
    +Rule	sol87	1987	only	-	Jun	28	12:03:05s -0:03:05 -
    +Rule	sol87	1987	only	-	Jun	29	12:03:15s -0:03:15 -
    +Rule	sol87	1987	only	-	Jun	30	12:03:30s -0:03:30 -
    +Rule	sol87	1987	only	-	Jul	1	12:03:40s -0:03:40 -
    +Rule	sol87	1987	only	-	Jul	2	12:03:50s -0:03:50 -
    +Rule	sol87	1987	only	-	Jul	3	12:04:05s -0:04:05 -
    +Rule	sol87	1987	only	-	Jul	4	12:04:15s -0:04:15 -
    +Rule	sol87	1987	only	-	Jul	5	12:04:25s -0:04:25 -
    +Rule	sol87	1987	only	-	Jul	6	12:04:35s -0:04:35 -
    +Rule	sol87	1987	only	-	Jul	7	12:04:45s -0:04:45 -
    +Rule	sol87	1987	only	-	Jul	8	12:04:55s -0:04:55 -
    +Rule	sol87	1987	only	-	Jul	9	12:05:05s -0:05:05 -
    +Rule	sol87	1987	only	-	Jul	10	12:05:15s -0:05:15 -
    +Rule	sol87	1987	only	-	Jul	11	12:05:20s -0:05:20 -
    +Rule	sol87	1987	only	-	Jul	12	12:05:30s -0:05:30 -
    +Rule	sol87	1987	only	-	Jul	13	12:05:40s -0:05:40 -
    +Rule	sol87	1987	only	-	Jul	14	12:05:45s -0:05:45 -
    +Rule	sol87	1987	only	-	Jul	15	12:05:50s -0:05:50 -
    +Rule	sol87	1987	only	-	Jul	16	12:06:00s -0:06:00 -
    +Rule	sol87	1987	only	-	Jul	17	12:06:05s -0:06:05 -
    +Rule	sol87	1987	only	-	Jul	18	12:06:10s -0:06:10 -
    +Rule	sol87	1987	only	-	Jul	19	12:06:15s -0:06:15 -
    +Rule	sol87	1987	only	-	Jul	20	12:06:15s -0:06:15 -
    +Rule	sol87	1987	only	-	Jul	21	12:06:20s -0:06:20 -
    +Rule	sol87	1987	only	-	Jul	22	12:06:25s -0:06:25 -
    +Rule	sol87	1987	only	-	Jul	23	12:06:25s -0:06:25 -
    +Rule	sol87	1987	only	-	Jul	24	12:06:25s -0:06:25 -
    +Rule	sol87	1987	only	-	Jul	25	12:06:30s -0:06:30 -
    +Rule	sol87	1987	only	-	Jul	26	12:06:30s -0:06:30 -
    +Rule	sol87	1987	only	-	Jul	27	12:06:30s -0:06:30 -
    +Rule	sol87	1987	only	-	Jul	28	12:06:30s -0:06:30 -
    +Rule	sol87	1987	only	-	Jul	29	12:06:25s -0:06:25 -
    +Rule	sol87	1987	only	-	Jul	30	12:06:25s -0:06:25 -
    +Rule	sol87	1987	only	-	Jul	31	12:06:25s -0:06:25 -
    +Rule	sol87	1987	only	-	Aug	1	12:06:20s -0:06:20 -
    +Rule	sol87	1987	only	-	Aug	2	12:06:15s -0:06:15 -
    +Rule	sol87	1987	only	-	Aug	3	12:06:10s -0:06:10 -
    +Rule	sol87	1987	only	-	Aug	4	12:06:05s -0:06:05 -
    +Rule	sol87	1987	only	-	Aug	5	12:06:00s -0:06:00 -
    +Rule	sol87	1987	only	-	Aug	6	12:05:55s -0:05:55 -
    +Rule	sol87	1987	only	-	Aug	7	12:05:50s -0:05:50 -
    +Rule	sol87	1987	only	-	Aug	8	12:05:40s -0:05:40 -
    +Rule	sol87	1987	only	-	Aug	9	12:05:35s -0:05:35 -
    +Rule	sol87	1987	only	-	Aug	10	12:05:25s -0:05:25 -
    +Rule	sol87	1987	only	-	Aug	11	12:05:15s -0:05:15 -
    +Rule	sol87	1987	only	-	Aug	12	12:05:05s -0:05:05 -
    +Rule	sol87	1987	only	-	Aug	13	12:04:55s -0:04:55 -
    +Rule	sol87	1987	only	-	Aug	14	12:04:45s -0:04:45 -
    +Rule	sol87	1987	only	-	Aug	15	12:04:35s -0:04:35 -
    +Rule	sol87	1987	only	-	Aug	16	12:04:25s -0:04:25 -
    +Rule	sol87	1987	only	-	Aug	17	12:04:10s -0:04:10 -
    +Rule	sol87	1987	only	-	Aug	18	12:04:00s -0:04:00 -
    +Rule	sol87	1987	only	-	Aug	19	12:03:45s -0:03:45 -
    +Rule	sol87	1987	only	-	Aug	20	12:03:30s -0:03:30 -
    +Rule	sol87	1987	only	-	Aug	21	12:03:15s -0:03:15 -
    +Rule	sol87	1987	only	-	Aug	22	12:03:00s -0:03:00 -
    +Rule	sol87	1987	only	-	Aug	23	12:02:45s -0:02:45 -
    +Rule	sol87	1987	only	-	Aug	24	12:02:30s -0:02:30 -
    +Rule	sol87	1987	only	-	Aug	25	12:02:15s -0:02:15 -
    +Rule	sol87	1987	only	-	Aug	26	12:02:00s -0:02:00 -
    +Rule	sol87	1987	only	-	Aug	27	12:01:40s -0:01:40 -
    +Rule	sol87	1987	only	-	Aug	28	12:01:25s -0:01:25 -
    +Rule	sol87	1987	only	-	Aug	29	12:01:05s -0:01:05 -
    +Rule	sol87	1987	only	-	Aug	30	12:00:50s -0:00:50 -
    +Rule	sol87	1987	only	-	Aug	31	12:00:30s -0:00:30 -
    +Rule	sol87	1987	only	-	Sep	1	12:00:10s -0:00:10 -
    +Rule	sol87	1987	only	-	Sep	2	11:59:50s 0:00:10 -
    +Rule	sol87	1987	only	-	Sep	3	11:59:35s 0:00:25 -
    +Rule	sol87	1987	only	-	Sep	4	11:59:15s 0:00:45 -
    +Rule	sol87	1987	only	-	Sep	5	11:58:55s 0:01:05 -
    +Rule	sol87	1987	only	-	Sep	6	11:58:35s 0:01:25 -
    +Rule	sol87	1987	only	-	Sep	7	11:58:15s 0:01:45 -
    +Rule	sol87	1987	only	-	Sep	8	11:57:55s 0:02:05 -
    +Rule	sol87	1987	only	-	Sep	9	11:57:30s 0:02:30 -
    +Rule	sol87	1987	only	-	Sep	10	11:57:10s 0:02:50 -
    +Rule	sol87	1987	only	-	Sep	11	11:56:50s 0:03:10 -
    +Rule	sol87	1987	only	-	Sep	12	11:56:30s 0:03:30 -
    +Rule	sol87	1987	only	-	Sep	13	11:56:10s 0:03:50 -
    +Rule	sol87	1987	only	-	Sep	14	11:55:45s 0:04:15 -
    +Rule	sol87	1987	only	-	Sep	15	11:55:25s 0:04:35 -
    +Rule	sol87	1987	only	-	Sep	16	11:55:05s 0:04:55 -
    +Rule	sol87	1987	only	-	Sep	17	11:54:45s 0:05:15 -
    +Rule	sol87	1987	only	-	Sep	18	11:54:20s 0:05:40 -
    +Rule	sol87	1987	only	-	Sep	19	11:54:00s 0:06:00 -
    +Rule	sol87	1987	only	-	Sep	20	11:53:40s 0:06:20 -
    +Rule	sol87	1987	only	-	Sep	21	11:53:15s 0:06:45 -
    +Rule	sol87	1987	only	-	Sep	22	11:52:55s 0:07:05 -
    +Rule	sol87	1987	only	-	Sep	23	11:52:35s 0:07:25 -
    +Rule	sol87	1987	only	-	Sep	24	11:52:15s 0:07:45 -
    +Rule	sol87	1987	only	-	Sep	25	11:51:55s 0:08:05 -
    +Rule	sol87	1987	only	-	Sep	26	11:51:35s 0:08:25 -
    +Rule	sol87	1987	only	-	Sep	27	11:51:10s 0:08:50 -
    +Rule	sol87	1987	only	-	Sep	28	11:50:50s 0:09:10 -
    +Rule	sol87	1987	only	-	Sep	29	11:50:30s 0:09:30 -
    +Rule	sol87	1987	only	-	Sep	30	11:50:10s 0:09:50 -
    +Rule	sol87	1987	only	-	Oct	1	11:49:50s 0:10:10 -
    +Rule	sol87	1987	only	-	Oct	2	11:49:35s 0:10:25 -
    +Rule	sol87	1987	only	-	Oct	3	11:49:15s 0:10:45 -
    +Rule	sol87	1987	only	-	Oct	4	11:48:55s 0:11:05 -
    +Rule	sol87	1987	only	-	Oct	5	11:48:35s 0:11:25 -
    +Rule	sol87	1987	only	-	Oct	6	11:48:20s 0:11:40 -
    +Rule	sol87	1987	only	-	Oct	7	11:48:00s 0:12:00 -
    +Rule	sol87	1987	only	-	Oct	8	11:47:45s 0:12:15 -
    +Rule	sol87	1987	only	-	Oct	9	11:47:25s 0:12:35 -
    +Rule	sol87	1987	only	-	Oct	10	11:47:10s 0:12:50 -
    +Rule	sol87	1987	only	-	Oct	11	11:46:55s 0:13:05 -
    +Rule	sol87	1987	only	-	Oct	12	11:46:40s 0:13:20 -
    +Rule	sol87	1987	only	-	Oct	13	11:46:25s 0:13:35 -
    +Rule	sol87	1987	only	-	Oct	14	11:46:10s 0:13:50 -
    +Rule	sol87	1987	only	-	Oct	15	11:45:55s 0:14:05 -
    +Rule	sol87	1987	only	-	Oct	16	11:45:45s 0:14:15 -
    +Rule	sol87	1987	only	-	Oct	17	11:45:30s 0:14:30 -
    +Rule	sol87	1987	only	-	Oct	18	11:45:20s 0:14:40 -
    +Rule	sol87	1987	only	-	Oct	19	11:45:05s 0:14:55 -
    +Rule	sol87	1987	only	-	Oct	20	11:44:55s 0:15:05 -
    +Rule	sol87	1987	only	-	Oct	21	11:44:45s 0:15:15 -
    +Rule	sol87	1987	only	-	Oct	22	11:44:35s 0:15:25 -
    +Rule	sol87	1987	only	-	Oct	23	11:44:25s 0:15:35 -
    +Rule	sol87	1987	only	-	Oct	24	11:44:20s 0:15:40 -
    +Rule	sol87	1987	only	-	Oct	25	11:44:10s 0:15:50 -
    +Rule	sol87	1987	only	-	Oct	26	11:44:05s 0:15:55 -
    +Rule	sol87	1987	only	-	Oct	27	11:43:55s 0:16:05 -
    +Rule	sol87	1987	only	-	Oct	28	11:43:50s 0:16:10 -
    +Rule	sol87	1987	only	-	Oct	29	11:43:45s 0:16:15 -
    +Rule	sol87	1987	only	-	Oct	30	11:43:45s 0:16:15 -
    +Rule	sol87	1987	only	-	Oct	31	11:43:40s 0:16:20 -
    +Rule	sol87	1987	only	-	Nov	1	11:43:40s 0:16:20 -
    +Rule	sol87	1987	only	-	Nov	2	11:43:35s 0:16:25 -
    +Rule	sol87	1987	only	-	Nov	3	11:43:35s 0:16:25 -
    +Rule	sol87	1987	only	-	Nov	4	11:43:35s 0:16:25 -
    +Rule	sol87	1987	only	-	Nov	5	11:43:35s 0:16:25 -
    +Rule	sol87	1987	only	-	Nov	6	11:43:40s 0:16:20 -
    +Rule	sol87	1987	only	-	Nov	7	11:43:40s 0:16:20 -
    +Rule	sol87	1987	only	-	Nov	8	11:43:45s 0:16:15 -
    +Rule	sol87	1987	only	-	Nov	9	11:43:50s 0:16:10 -
    +Rule	sol87	1987	only	-	Nov	10	11:43:55s 0:16:05 -
    +Rule	sol87	1987	only	-	Nov	11	11:44:00s 0:16:00 -
    +Rule	sol87	1987	only	-	Nov	12	11:44:05s 0:15:55 -
    +Rule	sol87	1987	only	-	Nov	13	11:44:15s 0:15:45 -
    +Rule	sol87	1987	only	-	Nov	14	11:44:20s 0:15:40 -
    +Rule	sol87	1987	only	-	Nov	15	11:44:30s 0:15:30 -
    +Rule	sol87	1987	only	-	Nov	16	11:44:40s 0:15:20 -
    +Rule	sol87	1987	only	-	Nov	17	11:44:50s 0:15:10 -
    +Rule	sol87	1987	only	-	Nov	18	11:45:05s 0:14:55 -
    +Rule	sol87	1987	only	-	Nov	19	11:45:15s 0:14:45 -
    +Rule	sol87	1987	only	-	Nov	20	11:45:30s 0:14:30 -
    +Rule	sol87	1987	only	-	Nov	21	11:45:45s 0:14:15 -
    +Rule	sol87	1987	only	-	Nov	22	11:46:00s 0:14:00 -
    +Rule	sol87	1987	only	-	Nov	23	11:46:15s 0:13:45 -
    +Rule	sol87	1987	only	-	Nov	24	11:46:30s 0:13:30 -
    +Rule	sol87	1987	only	-	Nov	25	11:46:50s 0:13:10 -
    +Rule	sol87	1987	only	-	Nov	26	11:47:10s 0:12:50 -
    +Rule	sol87	1987	only	-	Nov	27	11:47:25s 0:12:35 -
    +Rule	sol87	1987	only	-	Nov	28	11:47:45s 0:12:15 -
    +Rule	sol87	1987	only	-	Nov	29	11:48:05s 0:11:55 -
    +Rule	sol87	1987	only	-	Nov	30	11:48:30s 0:11:30 -
    +Rule	sol87	1987	only	-	Dec	1	11:48:50s 0:11:10 -
    +Rule	sol87	1987	only	-	Dec	2	11:49:10s 0:10:50 -
    +Rule	sol87	1987	only	-	Dec	3	11:49:35s 0:10:25 -
    +Rule	sol87	1987	only	-	Dec	4	11:50:00s 0:10:00 -
    +Rule	sol87	1987	only	-	Dec	5	11:50:25s 0:09:35 -
    +Rule	sol87	1987	only	-	Dec	6	11:50:50s 0:09:10 -
    +Rule	sol87	1987	only	-	Dec	7	11:51:15s 0:08:45 -
    +Rule	sol87	1987	only	-	Dec	8	11:51:40s 0:08:20 -
    +Rule	sol87	1987	only	-	Dec	9	11:52:05s 0:07:55 -
    +Rule	sol87	1987	only	-	Dec	10	11:52:30s 0:07:30 -
    +Rule	sol87	1987	only	-	Dec	11	11:53:00s 0:07:00 -
    +Rule	sol87	1987	only	-	Dec	12	11:53:25s 0:06:35 -
    +Rule	sol87	1987	only	-	Dec	13	11:53:55s 0:06:05 -
    +Rule	sol87	1987	only	-	Dec	14	11:54:25s 0:05:35 -
    +Rule	sol87	1987	only	-	Dec	15	11:54:50s 0:05:10 -
    +Rule	sol87	1987	only	-	Dec	16	11:55:20s 0:04:40 -
    +Rule	sol87	1987	only	-	Dec	17	11:55:50s 0:04:10 -
    +Rule	sol87	1987	only	-	Dec	18	11:56:20s 0:03:40 -
    +Rule	sol87	1987	only	-	Dec	19	11:56:50s 0:03:10 -
    +Rule	sol87	1987	only	-	Dec	20	11:57:20s 0:02:40 -
    +Rule	sol87	1987	only	-	Dec	21	11:57:50s 0:02:10 -
    +Rule	sol87	1987	only	-	Dec	22	11:58:20s 0:01:40 -
    +Rule	sol87	1987	only	-	Dec	23	11:58:50s 0:01:10 -
    +Rule	sol87	1987	only	-	Dec	24	11:59:20s 0:00:40 -
    +Rule	sol87	1987	only	-	Dec	25	11:59:50s 0:00:10 -
    +Rule	sol87	1987	only	-	Dec	26	12:00:20s -0:00:20 -
    +Rule	sol87	1987	only	-	Dec	27	12:00:45s -0:00:45 -
    +Rule	sol87	1987	only	-	Dec	28	12:01:15s -0:01:15 -
    +Rule	sol87	1987	only	-	Dec	29	12:01:45s -0:01:45 -
    +Rule	sol87	1987	only	-	Dec	30	12:02:15s -0:02:15 -
    +Rule	sol87	1987	only	-	Dec	31	12:02:45s -0:02:45 -
    +
    +# Riyadh is at about 46 degrees 46 minutes East:  3 hrs, 7 mins, 4 secs
    +# Before and after 1987, we'll operate on local mean solar time.
    +
    +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
    +Zone	Asia/Riyadh87	3:07:04	-		zzz	1987
    +			3:07:04	sol87		zzz	1988
    +			3:07:04	-		zzz
    +# For backward compatibility...
    +Link	Asia/Riyadh87	Mideast/Riyadh87
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/solar88 b/jdk/test/sun/util/calendar/zi/tzdata/solar88
    new file mode 100644
    index 00000000000..71b60d5d74a
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/solar88
    @@ -0,0 +1,413 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# Apparent noon times below are for Riyadh; they're a bit off for other places.
    +# Times were computed using formulas in the U.S. Naval Observatory's
    +# Almanac for Computers 1988; the formulas "will give EqT to an accuracy of
    +# [plus or minus two] seconds during the current year."
    +#
    +# Rounding to the nearest five seconds results in fewer than
    +# 256 different "time types"--a limit that's faced because time types are
    +# stored on disk as unsigned chars.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	sol88	1988	only	-	Jan	1	12:03:15s -0:03:15 -
    +Rule	sol88	1988	only	-	Jan	2	12:03:40s -0:03:40 -
    +Rule	sol88	1988	only	-	Jan	3	12:04:10s -0:04:10 -
    +Rule	sol88	1988	only	-	Jan	4	12:04:40s -0:04:40 -
    +Rule	sol88	1988	only	-	Jan	5	12:05:05s -0:05:05 -
    +Rule	sol88	1988	only	-	Jan	6	12:05:30s -0:05:30 -
    +Rule	sol88	1988	only	-	Jan	7	12:06:00s -0:06:00 -
    +Rule	sol88	1988	only	-	Jan	8	12:06:25s -0:06:25 -
    +Rule	sol88	1988	only	-	Jan	9	12:06:50s -0:06:50 -
    +Rule	sol88	1988	only	-	Jan	10	12:07:15s -0:07:15 -
    +Rule	sol88	1988	only	-	Jan	11	12:07:40s -0:07:40 -
    +Rule	sol88	1988	only	-	Jan	12	12:08:05s -0:08:05 -
    +Rule	sol88	1988	only	-	Jan	13	12:08:25s -0:08:25 -
    +Rule	sol88	1988	only	-	Jan	14	12:08:50s -0:08:50 -
    +Rule	sol88	1988	only	-	Jan	15	12:09:10s -0:09:10 -
    +Rule	sol88	1988	only	-	Jan	16	12:09:30s -0:09:30 -
    +Rule	sol88	1988	only	-	Jan	17	12:09:50s -0:09:50 -
    +Rule	sol88	1988	only	-	Jan	18	12:10:10s -0:10:10 -
    +Rule	sol88	1988	only	-	Jan	19	12:10:30s -0:10:30 -
    +Rule	sol88	1988	only	-	Jan	20	12:10:50s -0:10:50 -
    +Rule	sol88	1988	only	-	Jan	21	12:11:05s -0:11:05 -
    +Rule	sol88	1988	only	-	Jan	22	12:11:25s -0:11:25 -
    +Rule	sol88	1988	only	-	Jan	23	12:11:40s -0:11:40 -
    +Rule	sol88	1988	only	-	Jan	24	12:11:55s -0:11:55 -
    +Rule	sol88	1988	only	-	Jan	25	12:12:10s -0:12:10 -
    +Rule	sol88	1988	only	-	Jan	26	12:12:25s -0:12:25 -
    +Rule	sol88	1988	only	-	Jan	27	12:12:40s -0:12:40 -
    +Rule	sol88	1988	only	-	Jan	28	12:12:50s -0:12:50 -
    +Rule	sol88	1988	only	-	Jan	29	12:13:00s -0:13:00 -
    +Rule	sol88	1988	only	-	Jan	30	12:13:10s -0:13:10 -
    +Rule	sol88	1988	only	-	Jan	31	12:13:20s -0:13:20 -
    +Rule	sol88	1988	only	-	Feb	1	12:13:30s -0:13:30 -
    +Rule	sol88	1988	only	-	Feb	2	12:13:40s -0:13:40 -
    +Rule	sol88	1988	only	-	Feb	3	12:13:45s -0:13:45 -
    +Rule	sol88	1988	only	-	Feb	4	12:13:55s -0:13:55 -
    +Rule	sol88	1988	only	-	Feb	5	12:14:00s -0:14:00 -
    +Rule	sol88	1988	only	-	Feb	6	12:14:05s -0:14:05 -
    +Rule	sol88	1988	only	-	Feb	7	12:14:10s -0:14:10 -
    +Rule	sol88	1988	only	-	Feb	8	12:14:10s -0:14:10 -
    +Rule	sol88	1988	only	-	Feb	9	12:14:15s -0:14:15 -
    +Rule	sol88	1988	only	-	Feb	10	12:14:15s -0:14:15 -
    +Rule	sol88	1988	only	-	Feb	11	12:14:15s -0:14:15 -
    +Rule	sol88	1988	only	-	Feb	12	12:14:15s -0:14:15 -
    +Rule	sol88	1988	only	-	Feb	13	12:14:15s -0:14:15 -
    +Rule	sol88	1988	only	-	Feb	14	12:14:15s -0:14:15 -
    +Rule	sol88	1988	only	-	Feb	15	12:14:10s -0:14:10 -
    +Rule	sol88	1988	only	-	Feb	16	12:14:10s -0:14:10 -
    +Rule	sol88	1988	only	-	Feb	17	12:14:05s -0:14:05 -
    +Rule	sol88	1988	only	-	Feb	18	12:14:00s -0:14:00 -
    +Rule	sol88	1988	only	-	Feb	19	12:13:55s -0:13:55 -
    +Rule	sol88	1988	only	-	Feb	20	12:13:50s -0:13:50 -
    +Rule	sol88	1988	only	-	Feb	21	12:13:45s -0:13:45 -
    +Rule	sol88	1988	only	-	Feb	22	12:13:40s -0:13:40 -
    +Rule	sol88	1988	only	-	Feb	23	12:13:30s -0:13:30 -
    +Rule	sol88	1988	only	-	Feb	24	12:13:20s -0:13:20 -
    +Rule	sol88	1988	only	-	Feb	25	12:13:15s -0:13:15 -
    +Rule	sol88	1988	only	-	Feb	26	12:13:05s -0:13:05 -
    +Rule	sol88	1988	only	-	Feb	27	12:12:55s -0:12:55 -
    +Rule	sol88	1988	only	-	Feb	28	12:12:45s -0:12:45 -
    +Rule	sol88	1988	only	-	Feb	29	12:12:30s -0:12:30 -
    +Rule	sol88	1988	only	-	Mar	1	12:12:20s -0:12:20 -
    +Rule	sol88	1988	only	-	Mar	2	12:12:10s -0:12:10 -
    +Rule	sol88	1988	only	-	Mar	3	12:11:55s -0:11:55 -
    +Rule	sol88	1988	only	-	Mar	4	12:11:45s -0:11:45 -
    +Rule	sol88	1988	only	-	Mar	5	12:11:30s -0:11:30 -
    +Rule	sol88	1988	only	-	Mar	6	12:11:15s -0:11:15 -
    +Rule	sol88	1988	only	-	Mar	7	12:11:00s -0:11:00 -
    +Rule	sol88	1988	only	-	Mar	8	12:10:45s -0:10:45 -
    +Rule	sol88	1988	only	-	Mar	9	12:10:30s -0:10:30 -
    +Rule	sol88	1988	only	-	Mar	10	12:10:15s -0:10:15 -
    +Rule	sol88	1988	only	-	Mar	11	12:10:00s -0:10:00 -
    +Rule	sol88	1988	only	-	Mar	12	12:09:45s -0:09:45 -
    +Rule	sol88	1988	only	-	Mar	13	12:09:30s -0:09:30 -
    +Rule	sol88	1988	only	-	Mar	14	12:09:10s -0:09:10 -
    +Rule	sol88	1988	only	-	Mar	15	12:08:55s -0:08:55 -
    +Rule	sol88	1988	only	-	Mar	16	12:08:40s -0:08:40 -
    +Rule	sol88	1988	only	-	Mar	17	12:08:20s -0:08:20 -
    +Rule	sol88	1988	only	-	Mar	18	12:08:05s -0:08:05 -
    +Rule	sol88	1988	only	-	Mar	19	12:07:45s -0:07:45 -
    +Rule	sol88	1988	only	-	Mar	20	12:07:30s -0:07:30 -
    +Rule	sol88	1988	only	-	Mar	21	12:07:10s -0:07:10 -
    +Rule	sol88	1988	only	-	Mar	22	12:06:50s -0:06:50 -
    +Rule	sol88	1988	only	-	Mar	23	12:06:35s -0:06:35 -
    +Rule	sol88	1988	only	-	Mar	24	12:06:15s -0:06:15 -
    +Rule	sol88	1988	only	-	Mar	25	12:06:00s -0:06:00 -
    +Rule	sol88	1988	only	-	Mar	26	12:05:40s -0:05:40 -
    +Rule	sol88	1988	only	-	Mar	27	12:05:20s -0:05:20 -
    +Rule	sol88	1988	only	-	Mar	28	12:05:05s -0:05:05 -
    +Rule	sol88	1988	only	-	Mar	29	12:04:45s -0:04:45 -
    +Rule	sol88	1988	only	-	Mar	30	12:04:25s -0:04:25 -
    +Rule	sol88	1988	only	-	Mar	31	12:04:10s -0:04:10 -
    +Rule	sol88	1988	only	-	Apr	1	12:03:50s -0:03:50 -
    +Rule	sol88	1988	only	-	Apr	2	12:03:35s -0:03:35 -
    +Rule	sol88	1988	only	-	Apr	3	12:03:15s -0:03:15 -
    +Rule	sol88	1988	only	-	Apr	4	12:03:00s -0:03:00 -
    +Rule	sol88	1988	only	-	Apr	5	12:02:40s -0:02:40 -
    +Rule	sol88	1988	only	-	Apr	6	12:02:25s -0:02:25 -
    +Rule	sol88	1988	only	-	Apr	7	12:02:05s -0:02:05 -
    +Rule	sol88	1988	only	-	Apr	8	12:01:50s -0:01:50 -
    +Rule	sol88	1988	only	-	Apr	9	12:01:35s -0:01:35 -
    +Rule	sol88	1988	only	-	Apr	10	12:01:15s -0:01:15 -
    +Rule	sol88	1988	only	-	Apr	11	12:01:00s -0:01:00 -
    +Rule	sol88	1988	only	-	Apr	12	12:00:45s -0:00:45 -
    +Rule	sol88	1988	only	-	Apr	13	12:00:30s -0:00:30 -
    +Rule	sol88	1988	only	-	Apr	14	12:00:15s -0:00:15 -
    +Rule	sol88	1988	only	-	Apr	15	12:00:00s 0:00:00 -
    +Rule	sol88	1988	only	-	Apr	16	11:59:45s 0:00:15 -
    +Rule	sol88	1988	only	-	Apr	17	11:59:30s 0:00:30 -
    +Rule	sol88	1988	only	-	Apr	18	11:59:20s 0:00:40 -
    +Rule	sol88	1988	only	-	Apr	19	11:59:05s 0:00:55 -
    +Rule	sol88	1988	only	-	Apr	20	11:58:55s 0:01:05 -
    +Rule	sol88	1988	only	-	Apr	21	11:58:40s 0:01:20 -
    +Rule	sol88	1988	only	-	Apr	22	11:58:30s 0:01:30 -
    +Rule	sol88	1988	only	-	Apr	23	11:58:15s 0:01:45 -
    +Rule	sol88	1988	only	-	Apr	24	11:58:05s 0:01:55 -
    +Rule	sol88	1988	only	-	Apr	25	11:57:55s 0:02:05 -
    +Rule	sol88	1988	only	-	Apr	26	11:57:45s 0:02:15 -
    +Rule	sol88	1988	only	-	Apr	27	11:57:35s 0:02:25 -
    +Rule	sol88	1988	only	-	Apr	28	11:57:30s 0:02:30 -
    +Rule	sol88	1988	only	-	Apr	29	11:57:20s 0:02:40 -
    +Rule	sol88	1988	only	-	Apr	30	11:57:10s 0:02:50 -
    +Rule	sol88	1988	only	-	May	1	11:57:05s 0:02:55 -
    +Rule	sol88	1988	only	-	May	2	11:56:55s 0:03:05 -
    +Rule	sol88	1988	only	-	May	3	11:56:50s 0:03:10 -
    +Rule	sol88	1988	only	-	May	4	11:56:45s 0:03:15 -
    +Rule	sol88	1988	only	-	May	5	11:56:40s 0:03:20 -
    +Rule	sol88	1988	only	-	May	6	11:56:35s 0:03:25 -
    +Rule	sol88	1988	only	-	May	7	11:56:30s 0:03:30 -
    +Rule	sol88	1988	only	-	May	8	11:56:25s 0:03:35 -
    +Rule	sol88	1988	only	-	May	9	11:56:25s 0:03:35 -
    +Rule	sol88	1988	only	-	May	10	11:56:20s 0:03:40 -
    +Rule	sol88	1988	only	-	May	11	11:56:20s 0:03:40 -
    +Rule	sol88	1988	only	-	May	12	11:56:20s 0:03:40 -
    +Rule	sol88	1988	only	-	May	13	11:56:20s 0:03:40 -
    +Rule	sol88	1988	only	-	May	14	11:56:20s 0:03:40 -
    +Rule	sol88	1988	only	-	May	15	11:56:20s 0:03:40 -
    +Rule	sol88	1988	only	-	May	16	11:56:20s 0:03:40 -
    +Rule	sol88	1988	only	-	May	17	11:56:20s 0:03:40 -
    +Rule	sol88	1988	only	-	May	18	11:56:25s 0:03:35 -
    +Rule	sol88	1988	only	-	May	19	11:56:25s 0:03:35 -
    +Rule	sol88	1988	only	-	May	20	11:56:30s 0:03:30 -
    +Rule	sol88	1988	only	-	May	21	11:56:35s 0:03:25 -
    +Rule	sol88	1988	only	-	May	22	11:56:40s 0:03:20 -
    +Rule	sol88	1988	only	-	May	23	11:56:45s 0:03:15 -
    +Rule	sol88	1988	only	-	May	24	11:56:50s 0:03:10 -
    +Rule	sol88	1988	only	-	May	25	11:56:55s 0:03:05 -
    +Rule	sol88	1988	only	-	May	26	11:57:00s 0:03:00 -
    +Rule	sol88	1988	only	-	May	27	11:57:05s 0:02:55 -
    +Rule	sol88	1988	only	-	May	28	11:57:15s 0:02:45 -
    +Rule	sol88	1988	only	-	May	29	11:57:20s 0:02:40 -
    +Rule	sol88	1988	only	-	May	30	11:57:30s 0:02:30 -
    +Rule	sol88	1988	only	-	May	31	11:57:40s 0:02:20 -
    +Rule	sol88	1988	only	-	Jun	1	11:57:50s 0:02:10 -
    +Rule	sol88	1988	only	-	Jun	2	11:57:55s 0:02:05 -
    +Rule	sol88	1988	only	-	Jun	3	11:58:05s 0:01:55 -
    +Rule	sol88	1988	only	-	Jun	4	11:58:15s 0:01:45 -
    +Rule	sol88	1988	only	-	Jun	5	11:58:30s 0:01:30 -
    +Rule	sol88	1988	only	-	Jun	6	11:58:40s 0:01:20 -
    +Rule	sol88	1988	only	-	Jun	7	11:58:50s 0:01:10 -
    +Rule	sol88	1988	only	-	Jun	8	11:59:00s 0:01:00 -
    +Rule	sol88	1988	only	-	Jun	9	11:59:15s 0:00:45 -
    +Rule	sol88	1988	only	-	Jun	10	11:59:25s 0:00:35 -
    +Rule	sol88	1988	only	-	Jun	11	11:59:35s 0:00:25 -
    +Rule	sol88	1988	only	-	Jun	12	11:59:50s 0:00:10 -
    +Rule	sol88	1988	only	-	Jun	13	12:00:00s 0:00:00 -
    +Rule	sol88	1988	only	-	Jun	14	12:00:15s -0:00:15 -
    +Rule	sol88	1988	only	-	Jun	15	12:00:25s -0:00:25 -
    +Rule	sol88	1988	only	-	Jun	16	12:00:40s -0:00:40 -
    +Rule	sol88	1988	only	-	Jun	17	12:00:55s -0:00:55 -
    +Rule	sol88	1988	only	-	Jun	18	12:01:05s -0:01:05 -
    +Rule	sol88	1988	only	-	Jun	19	12:01:20s -0:01:20 -
    +Rule	sol88	1988	only	-	Jun	20	12:01:30s -0:01:30 -
    +Rule	sol88	1988	only	-	Jun	21	12:01:45s -0:01:45 -
    +Rule	sol88	1988	only	-	Jun	22	12:02:00s -0:02:00 -
    +Rule	sol88	1988	only	-	Jun	23	12:02:10s -0:02:10 -
    +Rule	sol88	1988	only	-	Jun	24	12:02:25s -0:02:25 -
    +Rule	sol88	1988	only	-	Jun	25	12:02:35s -0:02:35 -
    +Rule	sol88	1988	only	-	Jun	26	12:02:50s -0:02:50 -
    +Rule	sol88	1988	only	-	Jun	27	12:03:00s -0:03:00 -
    +Rule	sol88	1988	only	-	Jun	28	12:03:15s -0:03:15 -
    +Rule	sol88	1988	only	-	Jun	29	12:03:25s -0:03:25 -
    +Rule	sol88	1988	only	-	Jun	30	12:03:40s -0:03:40 -
    +Rule	sol88	1988	only	-	Jul	1	12:03:50s -0:03:50 -
    +Rule	sol88	1988	only	-	Jul	2	12:04:00s -0:04:00 -
    +Rule	sol88	1988	only	-	Jul	3	12:04:10s -0:04:10 -
    +Rule	sol88	1988	only	-	Jul	4	12:04:25s -0:04:25 -
    +Rule	sol88	1988	only	-	Jul	5	12:04:35s -0:04:35 -
    +Rule	sol88	1988	only	-	Jul	6	12:04:45s -0:04:45 -
    +Rule	sol88	1988	only	-	Jul	7	12:04:55s -0:04:55 -
    +Rule	sol88	1988	only	-	Jul	8	12:05:05s -0:05:05 -
    +Rule	sol88	1988	only	-	Jul	9	12:05:10s -0:05:10 -
    +Rule	sol88	1988	only	-	Jul	10	12:05:20s -0:05:20 -
    +Rule	sol88	1988	only	-	Jul	11	12:05:30s -0:05:30 -
    +Rule	sol88	1988	only	-	Jul	12	12:05:35s -0:05:35 -
    +Rule	sol88	1988	only	-	Jul	13	12:05:45s -0:05:45 -
    +Rule	sol88	1988	only	-	Jul	14	12:05:50s -0:05:50 -
    +Rule	sol88	1988	only	-	Jul	15	12:05:55s -0:05:55 -
    +Rule	sol88	1988	only	-	Jul	16	12:06:00s -0:06:00 -
    +Rule	sol88	1988	only	-	Jul	17	12:06:05s -0:06:05 -
    +Rule	sol88	1988	only	-	Jul	18	12:06:10s -0:06:10 -
    +Rule	sol88	1988	only	-	Jul	19	12:06:15s -0:06:15 -
    +Rule	sol88	1988	only	-	Jul	20	12:06:20s -0:06:20 -
    +Rule	sol88	1988	only	-	Jul	21	12:06:25s -0:06:25 -
    +Rule	sol88	1988	only	-	Jul	22	12:06:25s -0:06:25 -
    +Rule	sol88	1988	only	-	Jul	23	12:06:25s -0:06:25 -
    +Rule	sol88	1988	only	-	Jul	24	12:06:30s -0:06:30 -
    +Rule	sol88	1988	only	-	Jul	25	12:06:30s -0:06:30 -
    +Rule	sol88	1988	only	-	Jul	26	12:06:30s -0:06:30 -
    +Rule	sol88	1988	only	-	Jul	27	12:06:30s -0:06:30 -
    +Rule	sol88	1988	only	-	Jul	28	12:06:30s -0:06:30 -
    +Rule	sol88	1988	only	-	Jul	29	12:06:25s -0:06:25 -
    +Rule	sol88	1988	only	-	Jul	30	12:06:25s -0:06:25 -
    +Rule	sol88	1988	only	-	Jul	31	12:06:20s -0:06:20 -
    +Rule	sol88	1988	only	-	Aug	1	12:06:15s -0:06:15 -
    +Rule	sol88	1988	only	-	Aug	2	12:06:15s -0:06:15 -
    +Rule	sol88	1988	only	-	Aug	3	12:06:10s -0:06:10 -
    +Rule	sol88	1988	only	-	Aug	4	12:06:05s -0:06:05 -
    +Rule	sol88	1988	only	-	Aug	5	12:05:55s -0:05:55 -
    +Rule	sol88	1988	only	-	Aug	6	12:05:50s -0:05:50 -
    +Rule	sol88	1988	only	-	Aug	7	12:05:45s -0:05:45 -
    +Rule	sol88	1988	only	-	Aug	8	12:05:35s -0:05:35 -
    +Rule	sol88	1988	only	-	Aug	9	12:05:25s -0:05:25 -
    +Rule	sol88	1988	only	-	Aug	10	12:05:20s -0:05:20 -
    +Rule	sol88	1988	only	-	Aug	11	12:05:10s -0:05:10 -
    +Rule	sol88	1988	only	-	Aug	12	12:05:00s -0:05:00 -
    +Rule	sol88	1988	only	-	Aug	13	12:04:50s -0:04:50 -
    +Rule	sol88	1988	only	-	Aug	14	12:04:35s -0:04:35 -
    +Rule	sol88	1988	only	-	Aug	15	12:04:25s -0:04:25 -
    +Rule	sol88	1988	only	-	Aug	16	12:04:15s -0:04:15 -
    +Rule	sol88	1988	only	-	Aug	17	12:04:00s -0:04:00 -
    +Rule	sol88	1988	only	-	Aug	18	12:03:50s -0:03:50 -
    +Rule	sol88	1988	only	-	Aug	19	12:03:35s -0:03:35 -
    +Rule	sol88	1988	only	-	Aug	20	12:03:20s -0:03:20 -
    +Rule	sol88	1988	only	-	Aug	21	12:03:05s -0:03:05 -
    +Rule	sol88	1988	only	-	Aug	22	12:02:50s -0:02:50 -
    +Rule	sol88	1988	only	-	Aug	23	12:02:35s -0:02:35 -
    +Rule	sol88	1988	only	-	Aug	24	12:02:20s -0:02:20 -
    +Rule	sol88	1988	only	-	Aug	25	12:02:00s -0:02:00 -
    +Rule	sol88	1988	only	-	Aug	26	12:01:45s -0:01:45 -
    +Rule	sol88	1988	only	-	Aug	27	12:01:30s -0:01:30 -
    +Rule	sol88	1988	only	-	Aug	28	12:01:10s -0:01:10 -
    +Rule	sol88	1988	only	-	Aug	29	12:00:50s -0:00:50 -
    +Rule	sol88	1988	only	-	Aug	30	12:00:35s -0:00:35 -
    +Rule	sol88	1988	only	-	Aug	31	12:00:15s -0:00:15 -
    +Rule	sol88	1988	only	-	Sep	1	11:59:55s 0:00:05 -
    +Rule	sol88	1988	only	-	Sep	2	11:59:35s 0:00:25 -
    +Rule	sol88	1988	only	-	Sep	3	11:59:20s 0:00:40 -
    +Rule	sol88	1988	only	-	Sep	4	11:59:00s 0:01:00 -
    +Rule	sol88	1988	only	-	Sep	5	11:58:40s 0:01:20 -
    +Rule	sol88	1988	only	-	Sep	6	11:58:20s 0:01:40 -
    +Rule	sol88	1988	only	-	Sep	7	11:58:00s 0:02:00 -
    +Rule	sol88	1988	only	-	Sep	8	11:57:35s 0:02:25 -
    +Rule	sol88	1988	only	-	Sep	9	11:57:15s 0:02:45 -
    +Rule	sol88	1988	only	-	Sep	10	11:56:55s 0:03:05 -
    +Rule	sol88	1988	only	-	Sep	11	11:56:35s 0:03:25 -
    +Rule	sol88	1988	only	-	Sep	12	11:56:15s 0:03:45 -
    +Rule	sol88	1988	only	-	Sep	13	11:55:50s 0:04:10 -
    +Rule	sol88	1988	only	-	Sep	14	11:55:30s 0:04:30 -
    +Rule	sol88	1988	only	-	Sep	15	11:55:10s 0:04:50 -
    +Rule	sol88	1988	only	-	Sep	16	11:54:50s 0:05:10 -
    +Rule	sol88	1988	only	-	Sep	17	11:54:25s 0:05:35 -
    +Rule	sol88	1988	only	-	Sep	18	11:54:05s 0:05:55 -
    +Rule	sol88	1988	only	-	Sep	19	11:53:45s 0:06:15 -
    +Rule	sol88	1988	only	-	Sep	20	11:53:25s 0:06:35 -
    +Rule	sol88	1988	only	-	Sep	21	11:53:00s 0:07:00 -
    +Rule	sol88	1988	only	-	Sep	22	11:52:40s 0:07:20 -
    +Rule	sol88	1988	only	-	Sep	23	11:52:20s 0:07:40 -
    +Rule	sol88	1988	only	-	Sep	24	11:52:00s 0:08:00 -
    +Rule	sol88	1988	only	-	Sep	25	11:51:40s 0:08:20 -
    +Rule	sol88	1988	only	-	Sep	26	11:51:15s 0:08:45 -
    +Rule	sol88	1988	only	-	Sep	27	11:50:55s 0:09:05 -
    +Rule	sol88	1988	only	-	Sep	28	11:50:35s 0:09:25 -
    +Rule	sol88	1988	only	-	Sep	29	11:50:15s 0:09:45 -
    +Rule	sol88	1988	only	-	Sep	30	11:49:55s 0:10:05 -
    +Rule	sol88	1988	only	-	Oct	1	11:49:35s 0:10:25 -
    +Rule	sol88	1988	only	-	Oct	2	11:49:20s 0:10:40 -
    +Rule	sol88	1988	only	-	Oct	3	11:49:00s 0:11:00 -
    +Rule	sol88	1988	only	-	Oct	4	11:48:40s 0:11:20 -
    +Rule	sol88	1988	only	-	Oct	5	11:48:25s 0:11:35 -
    +Rule	sol88	1988	only	-	Oct	6	11:48:05s 0:11:55 -
    +Rule	sol88	1988	only	-	Oct	7	11:47:50s 0:12:10 -
    +Rule	sol88	1988	only	-	Oct	8	11:47:30s 0:12:30 -
    +Rule	sol88	1988	only	-	Oct	9	11:47:15s 0:12:45 -
    +Rule	sol88	1988	only	-	Oct	10	11:47:00s 0:13:00 -
    +Rule	sol88	1988	only	-	Oct	11	11:46:45s 0:13:15 -
    +Rule	sol88	1988	only	-	Oct	12	11:46:30s 0:13:30 -
    +Rule	sol88	1988	only	-	Oct	13	11:46:15s 0:13:45 -
    +Rule	sol88	1988	only	-	Oct	14	11:46:00s 0:14:00 -
    +Rule	sol88	1988	only	-	Oct	15	11:45:45s 0:14:15 -
    +Rule	sol88	1988	only	-	Oct	16	11:45:35s 0:14:25 -
    +Rule	sol88	1988	only	-	Oct	17	11:45:20s 0:14:40 -
    +Rule	sol88	1988	only	-	Oct	18	11:45:10s 0:14:50 -
    +Rule	sol88	1988	only	-	Oct	19	11:45:00s 0:15:00 -
    +Rule	sol88	1988	only	-	Oct	20	11:44:45s 0:15:15 -
    +Rule	sol88	1988	only	-	Oct	21	11:44:40s 0:15:20 -
    +Rule	sol88	1988	only	-	Oct	22	11:44:30s 0:15:30 -
    +Rule	sol88	1988	only	-	Oct	23	11:44:20s 0:15:40 -
    +Rule	sol88	1988	only	-	Oct	24	11:44:10s 0:15:50 -
    +Rule	sol88	1988	only	-	Oct	25	11:44:05s 0:15:55 -
    +Rule	sol88	1988	only	-	Oct	26	11:44:00s 0:16:00 -
    +Rule	sol88	1988	only	-	Oct	27	11:43:55s 0:16:05 -
    +Rule	sol88	1988	only	-	Oct	28	11:43:50s 0:16:10 -
    +Rule	sol88	1988	only	-	Oct	29	11:43:45s 0:16:15 -
    +Rule	sol88	1988	only	-	Oct	30	11:43:40s 0:16:20 -
    +Rule	sol88	1988	only	-	Oct	31	11:43:40s 0:16:20 -
    +Rule	sol88	1988	only	-	Nov	1	11:43:35s 0:16:25 -
    +Rule	sol88	1988	only	-	Nov	2	11:43:35s 0:16:25 -
    +Rule	sol88	1988	only	-	Nov	3	11:43:35s 0:16:25 -
    +Rule	sol88	1988	only	-	Nov	4	11:43:35s 0:16:25 -
    +Rule	sol88	1988	only	-	Nov	5	11:43:40s 0:16:20 -
    +Rule	sol88	1988	only	-	Nov	6	11:43:40s 0:16:20 -
    +Rule	sol88	1988	only	-	Nov	7	11:43:45s 0:16:15 -
    +Rule	sol88	1988	only	-	Nov	8	11:43:45s 0:16:15 -
    +Rule	sol88	1988	only	-	Nov	9	11:43:50s 0:16:10 -
    +Rule	sol88	1988	only	-	Nov	10	11:44:00s 0:16:00 -
    +Rule	sol88	1988	only	-	Nov	11	11:44:05s 0:15:55 -
    +Rule	sol88	1988	only	-	Nov	12	11:44:10s 0:15:50 -
    +Rule	sol88	1988	only	-	Nov	13	11:44:20s 0:15:40 -
    +Rule	sol88	1988	only	-	Nov	14	11:44:30s 0:15:30 -
    +Rule	sol88	1988	only	-	Nov	15	11:44:40s 0:15:20 -
    +Rule	sol88	1988	only	-	Nov	16	11:44:50s 0:15:10 -
    +Rule	sol88	1988	only	-	Nov	17	11:45:00s 0:15:00 -
    +Rule	sol88	1988	only	-	Nov	18	11:45:15s 0:14:45 -
    +Rule	sol88	1988	only	-	Nov	19	11:45:25s 0:14:35 -
    +Rule	sol88	1988	only	-	Nov	20	11:45:40s 0:14:20 -
    +Rule	sol88	1988	only	-	Nov	21	11:45:55s 0:14:05 -
    +Rule	sol88	1988	only	-	Nov	22	11:46:10s 0:13:50 -
    +Rule	sol88	1988	only	-	Nov	23	11:46:30s 0:13:30 -
    +Rule	sol88	1988	only	-	Nov	24	11:46:45s 0:13:15 -
    +Rule	sol88	1988	only	-	Nov	25	11:47:05s 0:12:55 -
    +Rule	sol88	1988	only	-	Nov	26	11:47:20s 0:12:40 -
    +Rule	sol88	1988	only	-	Nov	27	11:47:40s 0:12:20 -
    +Rule	sol88	1988	only	-	Nov	28	11:48:00s 0:12:00 -
    +Rule	sol88	1988	only	-	Nov	29	11:48:25s 0:11:35 -
    +Rule	sol88	1988	only	-	Nov	30	11:48:45s 0:11:15 -
    +Rule	sol88	1988	only	-	Dec	1	11:49:05s 0:10:55 -
    +Rule	sol88	1988	only	-	Dec	2	11:49:30s 0:10:30 -
    +Rule	sol88	1988	only	-	Dec	3	11:49:55s 0:10:05 -
    +Rule	sol88	1988	only	-	Dec	4	11:50:15s 0:09:45 -
    +Rule	sol88	1988	only	-	Dec	5	11:50:40s 0:09:20 -
    +Rule	sol88	1988	only	-	Dec	6	11:51:05s 0:08:55 -
    +Rule	sol88	1988	only	-	Dec	7	11:51:35s 0:08:25 -
    +Rule	sol88	1988	only	-	Dec	8	11:52:00s 0:08:00 -
    +Rule	sol88	1988	only	-	Dec	9	11:52:25s 0:07:35 -
    +Rule	sol88	1988	only	-	Dec	10	11:52:55s 0:07:05 -
    +Rule	sol88	1988	only	-	Dec	11	11:53:20s 0:06:40 -
    +Rule	sol88	1988	only	-	Dec	12	11:53:50s 0:06:10 -
    +Rule	sol88	1988	only	-	Dec	13	11:54:15s 0:05:45 -
    +Rule	sol88	1988	only	-	Dec	14	11:54:45s 0:05:15 -
    +Rule	sol88	1988	only	-	Dec	15	11:55:15s 0:04:45 -
    +Rule	sol88	1988	only	-	Dec	16	11:55:45s 0:04:15 -
    +Rule	sol88	1988	only	-	Dec	17	11:56:15s 0:03:45 -
    +Rule	sol88	1988	only	-	Dec	18	11:56:40s 0:03:20 -
    +Rule	sol88	1988	only	-	Dec	19	11:57:10s 0:02:50 -
    +Rule	sol88	1988	only	-	Dec	20	11:57:40s 0:02:20 -
    +Rule	sol88	1988	only	-	Dec	21	11:58:10s 0:01:50 -
    +Rule	sol88	1988	only	-	Dec	22	11:58:40s 0:01:20 -
    +Rule	sol88	1988	only	-	Dec	23	11:59:10s 0:00:50 -
    +Rule	sol88	1988	only	-	Dec	24	11:59:40s 0:00:20 -
    +Rule	sol88	1988	only	-	Dec	25	12:00:10s -0:00:10 -
    +Rule	sol88	1988	only	-	Dec	26	12:00:40s -0:00:40 -
    +Rule	sol88	1988	only	-	Dec	27	12:01:10s -0:01:10 -
    +Rule	sol88	1988	only	-	Dec	28	12:01:40s -0:01:40 -
    +Rule	sol88	1988	only	-	Dec	29	12:02:10s -0:02:10 -
    +Rule	sol88	1988	only	-	Dec	30	12:02:35s -0:02:35 -
    +Rule	sol88	1988	only	-	Dec	31	12:03:05s -0:03:05 -
    +
    +# Riyadh is at about 46 degrees 46 minutes East:  3 hrs, 7 mins, 4 secs
    +# Before and after 1988, we'll operate on local mean solar time.
    +
    +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
    +Zone	Asia/Riyadh88	3:07:04	-		zzz	1988
    +			3:07:04	sol88		zzz	1989
    +			3:07:04	-		zzz
    +# For backward compatibility...
    +Link	Asia/Riyadh88	Mideast/Riyadh88
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/solar89 b/jdk/test/sun/util/calendar/zi/tzdata/solar89
    new file mode 100644
    index 00000000000..ae2bea8876a
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/solar89
    @@ -0,0 +1,418 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# Apparent noon times below are for Riyadh; they're a bit off for other places.
    +# Times were computed using a formula provided by the U. S. Naval Observatory:
    +#	eqt = -105.8 * sin(l) + 596.2 * sin(2 * l) + 4.4 * sin(3 * l)
    +#		-12.7 * sin(4 * l) - 429.0 * cos(l) - 2.1 * cos (2 * l)
    +#		+ 19.3 * cos(3 * l);
    +# where l is the "mean longitude of the Sun" given by
    +#	l = 279.642 degrees + 0.985647 * d
    +# and d is the interval in days from January 0, 0 hours Universal Time
    +# (equaling the day of the year plus the fraction of a day from zero hours).
    +# The accuracy of the formula is plus or minus three seconds.
    +#
    +# Rounding to the nearest five seconds results in fewer than
    +# 256 different "time types"--a limit that's faced because time types are
    +# stored on disk as unsigned chars.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	sol89	1989	only	-	Jan	1	12:03:35s -0:03:35 -
    +Rule	sol89	1989	only	-	Jan	2	12:04:05s -0:04:05 -
    +Rule	sol89	1989	only	-	Jan	3	12:04:30s -0:04:30 -
    +Rule	sol89	1989	only	-	Jan	4	12:05:00s -0:05:00 -
    +Rule	sol89	1989	only	-	Jan	5	12:05:25s -0:05:25 -
    +Rule	sol89	1989	only	-	Jan	6	12:05:50s -0:05:50 -
    +Rule	sol89	1989	only	-	Jan	7	12:06:15s -0:06:15 -
    +Rule	sol89	1989	only	-	Jan	8	12:06:45s -0:06:45 -
    +Rule	sol89	1989	only	-	Jan	9	12:07:10s -0:07:10 -
    +Rule	sol89	1989	only	-	Jan	10	12:07:35s -0:07:35 -
    +Rule	sol89	1989	only	-	Jan	11	12:07:55s -0:07:55 -
    +Rule	sol89	1989	only	-	Jan	12	12:08:20s -0:08:20 -
    +Rule	sol89	1989	only	-	Jan	13	12:08:45s -0:08:45 -
    +Rule	sol89	1989	only	-	Jan	14	12:09:05s -0:09:05 -
    +Rule	sol89	1989	only	-	Jan	15	12:09:25s -0:09:25 -
    +Rule	sol89	1989	only	-	Jan	16	12:09:45s -0:09:45 -
    +Rule	sol89	1989	only	-	Jan	17	12:10:05s -0:10:05 -
    +Rule	sol89	1989	only	-	Jan	18	12:10:25s -0:10:25 -
    +Rule	sol89	1989	only	-	Jan	19	12:10:45s -0:10:45 -
    +Rule	sol89	1989	only	-	Jan	20	12:11:05s -0:11:05 -
    +Rule	sol89	1989	only	-	Jan	21	12:11:20s -0:11:20 -
    +Rule	sol89	1989	only	-	Jan	22	12:11:35s -0:11:35 -
    +Rule	sol89	1989	only	-	Jan	23	12:11:55s -0:11:55 -
    +Rule	sol89	1989	only	-	Jan	24	12:12:10s -0:12:10 -
    +Rule	sol89	1989	only	-	Jan	25	12:12:20s -0:12:20 -
    +Rule	sol89	1989	only	-	Jan	26	12:12:35s -0:12:35 -
    +Rule	sol89	1989	only	-	Jan	27	12:12:50s -0:12:50 -
    +Rule	sol89	1989	only	-	Jan	28	12:13:00s -0:13:00 -
    +Rule	sol89	1989	only	-	Jan	29	12:13:10s -0:13:10 -
    +Rule	sol89	1989	only	-	Jan	30	12:13:20s -0:13:20 -
    +Rule	sol89	1989	only	-	Jan	31	12:13:30s -0:13:30 -
    +Rule	sol89	1989	only	-	Feb	1	12:13:40s -0:13:40 -
    +Rule	sol89	1989	only	-	Feb	2	12:13:45s -0:13:45 -
    +Rule	sol89	1989	only	-	Feb	3	12:13:55s -0:13:55 -
    +Rule	sol89	1989	only	-	Feb	4	12:14:00s -0:14:00 -
    +Rule	sol89	1989	only	-	Feb	5	12:14:05s -0:14:05 -
    +Rule	sol89	1989	only	-	Feb	6	12:14:10s -0:14:10 -
    +Rule	sol89	1989	only	-	Feb	7	12:14:10s -0:14:10 -
    +Rule	sol89	1989	only	-	Feb	8	12:14:15s -0:14:15 -
    +Rule	sol89	1989	only	-	Feb	9	12:14:15s -0:14:15 -
    +Rule	sol89	1989	only	-	Feb	10	12:14:20s -0:14:20 -
    +Rule	sol89	1989	only	-	Feb	11	12:14:20s -0:14:20 -
    +Rule	sol89	1989	only	-	Feb	12	12:14:20s -0:14:20 -
    +Rule	sol89	1989	only	-	Feb	13	12:14:15s -0:14:15 -
    +Rule	sol89	1989	only	-	Feb	14	12:14:15s -0:14:15 -
    +Rule	sol89	1989	only	-	Feb	15	12:14:10s -0:14:10 -
    +Rule	sol89	1989	only	-	Feb	16	12:14:10s -0:14:10 -
    +Rule	sol89	1989	only	-	Feb	17	12:14:05s -0:14:05 -
    +Rule	sol89	1989	only	-	Feb	18	12:14:00s -0:14:00 -
    +Rule	sol89	1989	only	-	Feb	19	12:13:55s -0:13:55 -
    +Rule	sol89	1989	only	-	Feb	20	12:13:50s -0:13:50 -
    +Rule	sol89	1989	only	-	Feb	21	12:13:40s -0:13:40 -
    +Rule	sol89	1989	only	-	Feb	22	12:13:35s -0:13:35 -
    +Rule	sol89	1989	only	-	Feb	23	12:13:25s -0:13:25 -
    +Rule	sol89	1989	only	-	Feb	24	12:13:15s -0:13:15 -
    +Rule	sol89	1989	only	-	Feb	25	12:13:05s -0:13:05 -
    +Rule	sol89	1989	only	-	Feb	26	12:12:55s -0:12:55 -
    +Rule	sol89	1989	only	-	Feb	27	12:12:45s -0:12:45 -
    +Rule	sol89	1989	only	-	Feb	28	12:12:35s -0:12:35 -
    +Rule	sol89	1989	only	-	Mar	1	12:12:25s -0:12:25 -
    +Rule	sol89	1989	only	-	Mar	2	12:12:10s -0:12:10 -
    +Rule	sol89	1989	only	-	Mar	3	12:12:00s -0:12:00 -
    +Rule	sol89	1989	only	-	Mar	4	12:11:45s -0:11:45 -
    +Rule	sol89	1989	only	-	Mar	5	12:11:35s -0:11:35 -
    +Rule	sol89	1989	only	-	Mar	6	12:11:20s -0:11:20 -
    +Rule	sol89	1989	only	-	Mar	7	12:11:05s -0:11:05 -
    +Rule	sol89	1989	only	-	Mar	8	12:10:50s -0:10:50 -
    +Rule	sol89	1989	only	-	Mar	9	12:10:35s -0:10:35 -
    +Rule	sol89	1989	only	-	Mar	10	12:10:20s -0:10:20 -
    +Rule	sol89	1989	only	-	Mar	11	12:10:05s -0:10:05 -
    +Rule	sol89	1989	only	-	Mar	12	12:09:50s -0:09:50 -
    +Rule	sol89	1989	only	-	Mar	13	12:09:30s -0:09:30 -
    +Rule	sol89	1989	only	-	Mar	14	12:09:15s -0:09:15 -
    +Rule	sol89	1989	only	-	Mar	15	12:09:00s -0:09:00 -
    +Rule	sol89	1989	only	-	Mar	16	12:08:40s -0:08:40 -
    +Rule	sol89	1989	only	-	Mar	17	12:08:25s -0:08:25 -
    +Rule	sol89	1989	only	-	Mar	18	12:08:05s -0:08:05 -
    +Rule	sol89	1989	only	-	Mar	19	12:07:50s -0:07:50 -
    +Rule	sol89	1989	only	-	Mar	20	12:07:30s -0:07:30 -
    +Rule	sol89	1989	only	-	Mar	21	12:07:15s -0:07:15 -
    +Rule	sol89	1989	only	-	Mar	22	12:06:55s -0:06:55 -
    +Rule	sol89	1989	only	-	Mar	23	12:06:35s -0:06:35 -
    +Rule	sol89	1989	only	-	Mar	24	12:06:20s -0:06:20 -
    +Rule	sol89	1989	only	-	Mar	25	12:06:00s -0:06:00 -
    +Rule	sol89	1989	only	-	Mar	26	12:05:40s -0:05:40 -
    +Rule	sol89	1989	only	-	Mar	27	12:05:25s -0:05:25 -
    +Rule	sol89	1989	only	-	Mar	28	12:05:05s -0:05:05 -
    +Rule	sol89	1989	only	-	Mar	29	12:04:50s -0:04:50 -
    +Rule	sol89	1989	only	-	Mar	30	12:04:30s -0:04:30 -
    +Rule	sol89	1989	only	-	Mar	31	12:04:10s -0:04:10 -
    +Rule	sol89	1989	only	-	Apr	1	12:03:55s -0:03:55 -
    +Rule	sol89	1989	only	-	Apr	2	12:03:35s -0:03:35 -
    +Rule	sol89	1989	only	-	Apr	3	12:03:20s -0:03:20 -
    +Rule	sol89	1989	only	-	Apr	4	12:03:00s -0:03:00 -
    +Rule	sol89	1989	only	-	Apr	5	12:02:45s -0:02:45 -
    +Rule	sol89	1989	only	-	Apr	6	12:02:25s -0:02:25 -
    +Rule	sol89	1989	only	-	Apr	7	12:02:10s -0:02:10 -
    +Rule	sol89	1989	only	-	Apr	8	12:01:50s -0:01:50 -
    +Rule	sol89	1989	only	-	Apr	9	12:01:35s -0:01:35 -
    +Rule	sol89	1989	only	-	Apr	10	12:01:20s -0:01:20 -
    +Rule	sol89	1989	only	-	Apr	11	12:01:05s -0:01:05 -
    +Rule	sol89	1989	only	-	Apr	12	12:00:50s -0:00:50 -
    +Rule	sol89	1989	only	-	Apr	13	12:00:35s -0:00:35 -
    +Rule	sol89	1989	only	-	Apr	14	12:00:20s -0:00:20 -
    +Rule	sol89	1989	only	-	Apr	15	12:00:05s -0:00:05 -
    +Rule	sol89	1989	only	-	Apr	16	11:59:50s 0:00:10 -
    +Rule	sol89	1989	only	-	Apr	17	11:59:35s 0:00:25 -
    +Rule	sol89	1989	only	-	Apr	18	11:59:20s 0:00:40 -
    +Rule	sol89	1989	only	-	Apr	19	11:59:10s 0:00:50 -
    +Rule	sol89	1989	only	-	Apr	20	11:58:55s 0:01:05 -
    +Rule	sol89	1989	only	-	Apr	21	11:58:45s 0:01:15 -
    +Rule	sol89	1989	only	-	Apr	22	11:58:30s 0:01:30 -
    +Rule	sol89	1989	only	-	Apr	23	11:58:20s 0:01:40 -
    +Rule	sol89	1989	only	-	Apr	24	11:58:10s 0:01:50 -
    +Rule	sol89	1989	only	-	Apr	25	11:58:00s 0:02:00 -
    +Rule	sol89	1989	only	-	Apr	26	11:57:50s 0:02:10 -
    +Rule	sol89	1989	only	-	Apr	27	11:57:40s 0:02:20 -
    +Rule	sol89	1989	only	-	Apr	28	11:57:30s 0:02:30 -
    +Rule	sol89	1989	only	-	Apr	29	11:57:20s 0:02:40 -
    +Rule	sol89	1989	only	-	Apr	30	11:57:15s 0:02:45 -
    +Rule	sol89	1989	only	-	May	1	11:57:05s 0:02:55 -
    +Rule	sol89	1989	only	-	May	2	11:57:00s 0:03:00 -
    +Rule	sol89	1989	only	-	May	3	11:56:50s 0:03:10 -
    +Rule	sol89	1989	only	-	May	4	11:56:45s 0:03:15 -
    +Rule	sol89	1989	only	-	May	5	11:56:40s 0:03:20 -
    +Rule	sol89	1989	only	-	May	6	11:56:35s 0:03:25 -
    +Rule	sol89	1989	only	-	May	7	11:56:30s 0:03:30 -
    +Rule	sol89	1989	only	-	May	8	11:56:30s 0:03:30 -
    +Rule	sol89	1989	only	-	May	9	11:56:25s 0:03:35 -
    +Rule	sol89	1989	only	-	May	10	11:56:25s 0:03:35 -
    +Rule	sol89	1989	only	-	May	11	11:56:20s 0:03:40 -
    +Rule	sol89	1989	only	-	May	12	11:56:20s 0:03:40 -
    +Rule	sol89	1989	only	-	May	13	11:56:20s 0:03:40 -
    +Rule	sol89	1989	only	-	May	14	11:56:20s 0:03:40 -
    +Rule	sol89	1989	only	-	May	15	11:56:20s 0:03:40 -
    +Rule	sol89	1989	only	-	May	16	11:56:20s 0:03:40 -
    +Rule	sol89	1989	only	-	May	17	11:56:20s 0:03:40 -
    +Rule	sol89	1989	only	-	May	18	11:56:25s 0:03:35 -
    +Rule	sol89	1989	only	-	May	19	11:56:25s 0:03:35 -
    +Rule	sol89	1989	only	-	May	20	11:56:30s 0:03:30 -
    +Rule	sol89	1989	only	-	May	21	11:56:35s 0:03:25 -
    +Rule	sol89	1989	only	-	May	22	11:56:35s 0:03:25 -
    +Rule	sol89	1989	only	-	May	23	11:56:40s 0:03:20 -
    +Rule	sol89	1989	only	-	May	24	11:56:45s 0:03:15 -
    +Rule	sol89	1989	only	-	May	25	11:56:55s 0:03:05 -
    +Rule	sol89	1989	only	-	May	26	11:57:00s 0:03:00 -
    +Rule	sol89	1989	only	-	May	27	11:57:05s 0:02:55 -
    +Rule	sol89	1989	only	-	May	28	11:57:15s 0:02:45 -
    +Rule	sol89	1989	only	-	May	29	11:57:20s 0:02:40 -
    +Rule	sol89	1989	only	-	May	30	11:57:30s 0:02:30 -
    +Rule	sol89	1989	only	-	May	31	11:57:35s 0:02:25 -
    +Rule	sol89	1989	only	-	Jun	1	11:57:45s 0:02:15 -
    +Rule	sol89	1989	only	-	Jun	2	11:57:55s 0:02:05 -
    +Rule	sol89	1989	only	-	Jun	3	11:58:05s 0:01:55 -
    +Rule	sol89	1989	only	-	Jun	4	11:58:15s 0:01:45 -
    +Rule	sol89	1989	only	-	Jun	5	11:58:25s 0:01:35 -
    +Rule	sol89	1989	only	-	Jun	6	11:58:35s 0:01:25 -
    +Rule	sol89	1989	only	-	Jun	7	11:58:45s 0:01:15 -
    +Rule	sol89	1989	only	-	Jun	8	11:59:00s 0:01:00 -
    +Rule	sol89	1989	only	-	Jun	9	11:59:10s 0:00:50 -
    +Rule	sol89	1989	only	-	Jun	10	11:59:20s 0:00:40 -
    +Rule	sol89	1989	only	-	Jun	11	11:59:35s 0:00:25 -
    +Rule	sol89	1989	only	-	Jun	12	11:59:45s 0:00:15 -
    +Rule	sol89	1989	only	-	Jun	13	12:00:00s 0:00:00 -
    +Rule	sol89	1989	only	-	Jun	14	12:00:10s -0:00:10 -
    +Rule	sol89	1989	only	-	Jun	15	12:00:25s -0:00:25 -
    +Rule	sol89	1989	only	-	Jun	16	12:00:35s -0:00:35 -
    +Rule	sol89	1989	only	-	Jun	17	12:00:50s -0:00:50 -
    +Rule	sol89	1989	only	-	Jun	18	12:01:05s -0:01:05 -
    +Rule	sol89	1989	only	-	Jun	19	12:01:15s -0:01:15 -
    +Rule	sol89	1989	only	-	Jun	20	12:01:30s -0:01:30 -
    +Rule	sol89	1989	only	-	Jun	21	12:01:40s -0:01:40 -
    +Rule	sol89	1989	only	-	Jun	22	12:01:55s -0:01:55 -
    +Rule	sol89	1989	only	-	Jun	23	12:02:10s -0:02:10 -
    +Rule	sol89	1989	only	-	Jun	24	12:02:20s -0:02:20 -
    +Rule	sol89	1989	only	-	Jun	25	12:02:35s -0:02:35 -
    +Rule	sol89	1989	only	-	Jun	26	12:02:45s -0:02:45 -
    +Rule	sol89	1989	only	-	Jun	27	12:03:00s -0:03:00 -
    +Rule	sol89	1989	only	-	Jun	28	12:03:10s -0:03:10 -
    +Rule	sol89	1989	only	-	Jun	29	12:03:25s -0:03:25 -
    +Rule	sol89	1989	only	-	Jun	30	12:03:35s -0:03:35 -
    +Rule	sol89	1989	only	-	Jul	1	12:03:45s -0:03:45 -
    +Rule	sol89	1989	only	-	Jul	2	12:04:00s -0:04:00 -
    +Rule	sol89	1989	only	-	Jul	3	12:04:10s -0:04:10 -
    +Rule	sol89	1989	only	-	Jul	4	12:04:20s -0:04:20 -
    +Rule	sol89	1989	only	-	Jul	5	12:04:30s -0:04:30 -
    +Rule	sol89	1989	only	-	Jul	6	12:04:40s -0:04:40 -
    +Rule	sol89	1989	only	-	Jul	7	12:04:50s -0:04:50 -
    +Rule	sol89	1989	only	-	Jul	8	12:05:00s -0:05:00 -
    +Rule	sol89	1989	only	-	Jul	9	12:05:10s -0:05:10 -
    +Rule	sol89	1989	only	-	Jul	10	12:05:20s -0:05:20 -
    +Rule	sol89	1989	only	-	Jul	11	12:05:25s -0:05:25 -
    +Rule	sol89	1989	only	-	Jul	12	12:05:35s -0:05:35 -
    +Rule	sol89	1989	only	-	Jul	13	12:05:40s -0:05:40 -
    +Rule	sol89	1989	only	-	Jul	14	12:05:50s -0:05:50 -
    +Rule	sol89	1989	only	-	Jul	15	12:05:55s -0:05:55 -
    +Rule	sol89	1989	only	-	Jul	16	12:06:00s -0:06:00 -
    +Rule	sol89	1989	only	-	Jul	17	12:06:05s -0:06:05 -
    +Rule	sol89	1989	only	-	Jul	18	12:06:10s -0:06:10 -
    +Rule	sol89	1989	only	-	Jul	19	12:06:15s -0:06:15 -
    +Rule	sol89	1989	only	-	Jul	20	12:06:20s -0:06:20 -
    +Rule	sol89	1989	only	-	Jul	21	12:06:20s -0:06:20 -
    +Rule	sol89	1989	only	-	Jul	22	12:06:25s -0:06:25 -
    +Rule	sol89	1989	only	-	Jul	23	12:06:25s -0:06:25 -
    +Rule	sol89	1989	only	-	Jul	24	12:06:30s -0:06:30 -
    +Rule	sol89	1989	only	-	Jul	25	12:06:30s -0:06:30 -
    +Rule	sol89	1989	only	-	Jul	26	12:06:30s -0:06:30 -
    +Rule	sol89	1989	only	-	Jul	27	12:06:30s -0:06:30 -
    +Rule	sol89	1989	only	-	Jul	28	12:06:30s -0:06:30 -
    +Rule	sol89	1989	only	-	Jul	29	12:06:25s -0:06:25 -
    +Rule	sol89	1989	only	-	Jul	30	12:06:25s -0:06:25 -
    +Rule	sol89	1989	only	-	Jul	31	12:06:20s -0:06:20 -
    +Rule	sol89	1989	only	-	Aug	1	12:06:20s -0:06:20 -
    +Rule	sol89	1989	only	-	Aug	2	12:06:15s -0:06:15 -
    +Rule	sol89	1989	only	-	Aug	3	12:06:10s -0:06:10 -
    +Rule	sol89	1989	only	-	Aug	4	12:06:05s -0:06:05 -
    +Rule	sol89	1989	only	-	Aug	5	12:06:00s -0:06:00 -
    +Rule	sol89	1989	only	-	Aug	6	12:05:50s -0:05:50 -
    +Rule	sol89	1989	only	-	Aug	7	12:05:45s -0:05:45 -
    +Rule	sol89	1989	only	-	Aug	8	12:05:35s -0:05:35 -
    +Rule	sol89	1989	only	-	Aug	9	12:05:30s -0:05:30 -
    +Rule	sol89	1989	only	-	Aug	10	12:05:20s -0:05:20 -
    +Rule	sol89	1989	only	-	Aug	11	12:05:10s -0:05:10 -
    +Rule	sol89	1989	only	-	Aug	12	12:05:00s -0:05:00 -
    +Rule	sol89	1989	only	-	Aug	13	12:04:50s -0:04:50 -
    +Rule	sol89	1989	only	-	Aug	14	12:04:40s -0:04:40 -
    +Rule	sol89	1989	only	-	Aug	15	12:04:30s -0:04:30 -
    +Rule	sol89	1989	only	-	Aug	16	12:04:15s -0:04:15 -
    +Rule	sol89	1989	only	-	Aug	17	12:04:05s -0:04:05 -
    +Rule	sol89	1989	only	-	Aug	18	12:03:50s -0:03:50 -
    +Rule	sol89	1989	only	-	Aug	19	12:03:35s -0:03:35 -
    +Rule	sol89	1989	only	-	Aug	20	12:03:25s -0:03:25 -
    +Rule	sol89	1989	only	-	Aug	21	12:03:10s -0:03:10 -
    +Rule	sol89	1989	only	-	Aug	22	12:02:55s -0:02:55 -
    +Rule	sol89	1989	only	-	Aug	23	12:02:40s -0:02:40 -
    +Rule	sol89	1989	only	-	Aug	24	12:02:20s -0:02:20 -
    +Rule	sol89	1989	only	-	Aug	25	12:02:05s -0:02:05 -
    +Rule	sol89	1989	only	-	Aug	26	12:01:50s -0:01:50 -
    +Rule	sol89	1989	only	-	Aug	27	12:01:30s -0:01:30 -
    +Rule	sol89	1989	only	-	Aug	28	12:01:15s -0:01:15 -
    +Rule	sol89	1989	only	-	Aug	29	12:00:55s -0:00:55 -
    +Rule	sol89	1989	only	-	Aug	30	12:00:40s -0:00:40 -
    +Rule	sol89	1989	only	-	Aug	31	12:00:20s -0:00:20 -
    +Rule	sol89	1989	only	-	Sep	1	12:00:00s 0:00:00 -
    +Rule	sol89	1989	only	-	Sep	2	11:59:45s 0:00:15 -
    +Rule	sol89	1989	only	-	Sep	3	11:59:25s 0:00:35 -
    +Rule	sol89	1989	only	-	Sep	4	11:59:05s 0:00:55 -
    +Rule	sol89	1989	only	-	Sep	5	11:58:45s 0:01:15 -
    +Rule	sol89	1989	only	-	Sep	6	11:58:25s 0:01:35 -
    +Rule	sol89	1989	only	-	Sep	7	11:58:05s 0:01:55 -
    +Rule	sol89	1989	only	-	Sep	8	11:57:45s 0:02:15 -
    +Rule	sol89	1989	only	-	Sep	9	11:57:20s 0:02:40 -
    +Rule	sol89	1989	only	-	Sep	10	11:57:00s 0:03:00 -
    +Rule	sol89	1989	only	-	Sep	11	11:56:40s 0:03:20 -
    +Rule	sol89	1989	only	-	Sep	12	11:56:20s 0:03:40 -
    +Rule	sol89	1989	only	-	Sep	13	11:56:00s 0:04:00 -
    +Rule	sol89	1989	only	-	Sep	14	11:55:35s 0:04:25 -
    +Rule	sol89	1989	only	-	Sep	15	11:55:15s 0:04:45 -
    +Rule	sol89	1989	only	-	Sep	16	11:54:55s 0:05:05 -
    +Rule	sol89	1989	only	-	Sep	17	11:54:35s 0:05:25 -
    +Rule	sol89	1989	only	-	Sep	18	11:54:10s 0:05:50 -
    +Rule	sol89	1989	only	-	Sep	19	11:53:50s 0:06:10 -
    +Rule	sol89	1989	only	-	Sep	20	11:53:30s 0:06:30 -
    +Rule	sol89	1989	only	-	Sep	21	11:53:10s 0:06:50 -
    +Rule	sol89	1989	only	-	Sep	22	11:52:45s 0:07:15 -
    +Rule	sol89	1989	only	-	Sep	23	11:52:25s 0:07:35 -
    +Rule	sol89	1989	only	-	Sep	24	11:52:05s 0:07:55 -
    +Rule	sol89	1989	only	-	Sep	25	11:51:45s 0:08:15 -
    +Rule	sol89	1989	only	-	Sep	26	11:51:25s 0:08:35 -
    +Rule	sol89	1989	only	-	Sep	27	11:51:05s 0:08:55 -
    +Rule	sol89	1989	only	-	Sep	28	11:50:40s 0:09:20 -
    +Rule	sol89	1989	only	-	Sep	29	11:50:20s 0:09:40 -
    +Rule	sol89	1989	only	-	Sep	30	11:50:00s 0:10:00 -
    +Rule	sol89	1989	only	-	Oct	1	11:49:45s 0:10:15 -
    +Rule	sol89	1989	only	-	Oct	2	11:49:25s 0:10:35 -
    +Rule	sol89	1989	only	-	Oct	3	11:49:05s 0:10:55 -
    +Rule	sol89	1989	only	-	Oct	4	11:48:45s 0:11:15 -
    +Rule	sol89	1989	only	-	Oct	5	11:48:30s 0:11:30 -
    +Rule	sol89	1989	only	-	Oct	6	11:48:10s 0:11:50 -
    +Rule	sol89	1989	only	-	Oct	7	11:47:50s 0:12:10 -
    +Rule	sol89	1989	only	-	Oct	8	11:47:35s 0:12:25 -
    +Rule	sol89	1989	only	-	Oct	9	11:47:20s 0:12:40 -
    +Rule	sol89	1989	only	-	Oct	10	11:47:00s 0:13:00 -
    +Rule	sol89	1989	only	-	Oct	11	11:46:45s 0:13:15 -
    +Rule	sol89	1989	only	-	Oct	12	11:46:30s 0:13:30 -
    +Rule	sol89	1989	only	-	Oct	13	11:46:15s 0:13:45 -
    +Rule	sol89	1989	only	-	Oct	14	11:46:00s 0:14:00 -
    +Rule	sol89	1989	only	-	Oct	15	11:45:50s 0:14:10 -
    +Rule	sol89	1989	only	-	Oct	16	11:45:35s 0:14:25 -
    +Rule	sol89	1989	only	-	Oct	17	11:45:20s 0:14:40 -
    +Rule	sol89	1989	only	-	Oct	18	11:45:10s 0:14:50 -
    +Rule	sol89	1989	only	-	Oct	19	11:45:00s 0:15:00 -
    +Rule	sol89	1989	only	-	Oct	20	11:44:50s 0:15:10 -
    +Rule	sol89	1989	only	-	Oct	21	11:44:40s 0:15:20 -
    +Rule	sol89	1989	only	-	Oct	22	11:44:30s 0:15:30 -
    +Rule	sol89	1989	only	-	Oct	23	11:44:20s 0:15:40 -
    +Rule	sol89	1989	only	-	Oct	24	11:44:10s 0:15:50 -
    +Rule	sol89	1989	only	-	Oct	25	11:44:05s 0:15:55 -
    +Rule	sol89	1989	only	-	Oct	26	11:44:00s 0:16:00 -
    +Rule	sol89	1989	only	-	Oct	27	11:43:50s 0:16:10 -
    +Rule	sol89	1989	only	-	Oct	28	11:43:45s 0:16:15 -
    +Rule	sol89	1989	only	-	Oct	29	11:43:40s 0:16:20 -
    +Rule	sol89	1989	only	-	Oct	30	11:43:40s 0:16:20 -
    +Rule	sol89	1989	only	-	Oct	31	11:43:35s 0:16:25 -
    +Rule	sol89	1989	only	-	Nov	1	11:43:35s 0:16:25 -
    +Rule	sol89	1989	only	-	Nov	2	11:43:35s 0:16:25 -
    +Rule	sol89	1989	only	-	Nov	3	11:43:30s 0:16:30 -
    +Rule	sol89	1989	only	-	Nov	4	11:43:35s 0:16:25 -
    +Rule	sol89	1989	only	-	Nov	5	11:43:35s 0:16:25 -
    +Rule	sol89	1989	only	-	Nov	6	11:43:35s 0:16:25 -
    +Rule	sol89	1989	only	-	Nov	7	11:43:40s 0:16:20 -
    +Rule	sol89	1989	only	-	Nov	8	11:43:45s 0:16:15 -
    +Rule	sol89	1989	only	-	Nov	9	11:43:50s 0:16:10 -
    +Rule	sol89	1989	only	-	Nov	10	11:43:55s 0:16:05 -
    +Rule	sol89	1989	only	-	Nov	11	11:44:00s 0:16:00 -
    +Rule	sol89	1989	only	-	Nov	12	11:44:05s 0:15:55 -
    +Rule	sol89	1989	only	-	Nov	13	11:44:15s 0:15:45 -
    +Rule	sol89	1989	only	-	Nov	14	11:44:25s 0:15:35 -
    +Rule	sol89	1989	only	-	Nov	15	11:44:35s 0:15:25 -
    +Rule	sol89	1989	only	-	Nov	16	11:44:45s 0:15:15 -
    +Rule	sol89	1989	only	-	Nov	17	11:44:55s 0:15:05 -
    +Rule	sol89	1989	only	-	Nov	18	11:45:10s 0:14:50 -
    +Rule	sol89	1989	only	-	Nov	19	11:45:20s 0:14:40 -
    +Rule	sol89	1989	only	-	Nov	20	11:45:35s 0:14:25 -
    +Rule	sol89	1989	only	-	Nov	21	11:45:50s 0:14:10 -
    +Rule	sol89	1989	only	-	Nov	22	11:46:05s 0:13:55 -
    +Rule	sol89	1989	only	-	Nov	23	11:46:25s 0:13:35 -
    +Rule	sol89	1989	only	-	Nov	24	11:46:40s 0:13:20 -
    +Rule	sol89	1989	only	-	Nov	25	11:47:00s 0:13:00 -
    +Rule	sol89	1989	only	-	Nov	26	11:47:20s 0:12:40 -
    +Rule	sol89	1989	only	-	Nov	27	11:47:35s 0:12:25 -
    +Rule	sol89	1989	only	-	Nov	28	11:47:55s 0:12:05 -
    +Rule	sol89	1989	only	-	Nov	29	11:48:20s 0:11:40 -
    +Rule	sol89	1989	only	-	Nov	30	11:48:40s 0:11:20 -
    +Rule	sol89	1989	only	-	Dec	1	11:49:00s 0:11:00 -
    +Rule	sol89	1989	only	-	Dec	2	11:49:25s 0:10:35 -
    +Rule	sol89	1989	only	-	Dec	3	11:49:50s 0:10:10 -
    +Rule	sol89	1989	only	-	Dec	4	11:50:15s 0:09:45 -
    +Rule	sol89	1989	only	-	Dec	5	11:50:35s 0:09:25 -
    +Rule	sol89	1989	only	-	Dec	6	11:51:00s 0:09:00 -
    +Rule	sol89	1989	only	-	Dec	7	11:51:30s 0:08:30 -
    +Rule	sol89	1989	only	-	Dec	8	11:51:55s 0:08:05 -
    +Rule	sol89	1989	only	-	Dec	9	11:52:20s 0:07:40 -
    +Rule	sol89	1989	only	-	Dec	10	11:52:50s 0:07:10 -
    +Rule	sol89	1989	only	-	Dec	11	11:53:15s 0:06:45 -
    +Rule	sol89	1989	only	-	Dec	12	11:53:45s 0:06:15 -
    +Rule	sol89	1989	only	-	Dec	13	11:54:10s 0:05:50 -
    +Rule	sol89	1989	only	-	Dec	14	11:54:40s 0:05:20 -
    +Rule	sol89	1989	only	-	Dec	15	11:55:10s 0:04:50 -
    +Rule	sol89	1989	only	-	Dec	16	11:55:40s 0:04:20 -
    +Rule	sol89	1989	only	-	Dec	17	11:56:05s 0:03:55 -
    +Rule	sol89	1989	only	-	Dec	18	11:56:35s 0:03:25 -
    +Rule	sol89	1989	only	-	Dec	19	11:57:05s 0:02:55 -
    +Rule	sol89	1989	only	-	Dec	20	11:57:35s 0:02:25 -
    +Rule	sol89	1989	only	-	Dec	21	11:58:05s 0:01:55 -
    +Rule	sol89	1989	only	-	Dec	22	11:58:35s 0:01:25 -
    +Rule	sol89	1989	only	-	Dec	23	11:59:05s 0:00:55 -
    +Rule	sol89	1989	only	-	Dec	24	11:59:35s 0:00:25 -
    +Rule	sol89	1989	only	-	Dec	25	12:00:05s -0:00:05 -
    +Rule	sol89	1989	only	-	Dec	26	12:00:35s -0:00:35 -
    +Rule	sol89	1989	only	-	Dec	27	12:01:05s -0:01:05 -
    +Rule	sol89	1989	only	-	Dec	28	12:01:35s -0:01:35 -
    +Rule	sol89	1989	only	-	Dec	29	12:02:00s -0:02:00 -
    +Rule	sol89	1989	only	-	Dec	30	12:02:30s -0:02:30 -
    +Rule	sol89	1989	only	-	Dec	31	12:03:00s -0:03:00 -
    +
    +# Riyadh is at about 46 degrees 46 minutes East:  3 hrs, 7 mins, 4 secs
    +# Before and after 1989, we'll operate on local mean solar time.
    +
    +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
    +Zone	Asia/Riyadh89	3:07:04	-		zzz	1989
    +			3:07:04	sol89		zzz	1990
    +			3:07:04	-		zzz
    +# For backward compatibility...
    +Link	Asia/Riyadh89	Mideast/Riyadh89
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/southamerica b/jdk/test/sun/util/calendar/zi/tzdata/southamerica
    new file mode 100644
    index 00000000000..0d6797eab6b
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/southamerica
    @@ -0,0 +1,1734 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# This data is by no means authoritative; if you think you know better,
    +# go ahead and edit the file (and please send any changes to
    +# tz@elsie.nci.nih.gov for general use in the future).
    +
    +# From Paul Eggert (2006-03-22):
    +# A good source for time zone historical data outside the U.S. is
    +# Thomas G. Shanks and Rique Pottenger, The International Atlas (6th edition),
    +# San Diego: ACS Publications, Inc. (2003).
    +#
    +# Gwillim Law writes that a good source
    +# for recent time zone data is the International Air Transport
    +# Association's Standard Schedules Information Manual (IATA SSIM),
    +# published semiannually.  Law sent in several helpful summaries
    +# of the IATA's data after 1990.
    +#
    +# Except where otherwise noted, Shanks & Pottenger is the source for
    +# entries through 1990, and IATA SSIM is the source for entries afterwards.
    +#
    +# Earlier editions of these tables used the North American style (e.g. ARST and
    +# ARDT for Argentine Standard and Daylight Time), but the following quote
    +# suggests that it's better to use European style (e.g. ART and ARST).
    +#	I suggest the use of _Summer time_ instead of the more cumbersome
    +#	_daylight-saving time_.  _Summer time_ seems to be in general use
    +#	in Europe and South America.
    +#	-- E O Cutler, _New York Times_ (1937-02-14), quoted in
    +#	H L Mencken, _The American Language: Supplement I_ (1960), p 466
    +#
    +# Earlier editions of these tables also used the North American style
    +# for time zones in Brazil, but this was incorrect, as Brazilians say
    +# "summer time".  Reinaldo Goulart, a Sao Paulo businessman active in
    +# the railroad sector, writes (1999-07-06):
    +#	The subject of time zones is currently a matter of discussion/debate in
    +#	Brazil.  Let's say that "the Brasilia time" is considered the
    +#	"official time" because Brasilia is the capital city.
    +#	The other three time zones are called "Brasilia time "minus one" or
    +#	"plus one" or "plus two".  As far as I know there is no such
    +#	name/designation as "Eastern Time" or "Central Time".
    +# So I invented the following (English-language) abbreviations for now.
    +# Corrections are welcome!
    +#		std	dst
    +#	-2:00	FNT	FNST	Fernando de Noronha
    +#	-3:00	BRT	BRST	Brasilia
    +#	-4:00	AMT	AMST	Amazon
    +#	-5:00	ACT	ACST	Acre
    +
    +###############################################################################
    +
    +###############################################################################
    +
    +# Argentina
    +
    +# From Bob Devine (1988-01-28):
    +# Argentina: first Sunday in October to first Sunday in April since 1976.
    +# Double Summer time from 1969 to 1974.  Switches at midnight.
    +
    +# From U. S. Naval Observatory (1988-01-199):
    +# ARGENTINA           3 H BEHIND   UTC
    +
    +# From Hernan G. Otero (1995-06-26):
    +# I am sending modifications to the Argentine time zone table...
    +# AR was chosen because they are the ISO letters that represent Argentina.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Arg	1930	only	-	Dec	 1	0:00	1:00	S
    +Rule	Arg	1931	only	-	Apr	 1	0:00	0	-
    +Rule	Arg	1931	only	-	Oct	15	0:00	1:00	S
    +Rule	Arg	1932	1940	-	Mar	 1	0:00	0	-
    +Rule	Arg	1932	1939	-	Nov	 1	0:00	1:00	S
    +Rule	Arg	1940	only	-	Jul	 1	0:00	1:00	S
    +Rule	Arg	1941	only	-	Jun	15	0:00	0	-
    +Rule	Arg	1941	only	-	Oct	15	0:00	1:00	S
    +Rule	Arg	1943	only	-	Aug	 1	0:00	0	-
    +Rule	Arg	1943	only	-	Oct	15	0:00	1:00	S
    +Rule	Arg	1946	only	-	Mar	 1	0:00	0	-
    +Rule	Arg	1946	only	-	Oct	 1	0:00	1:00	S
    +Rule	Arg	1963	only	-	Oct	 1	0:00	0	-
    +Rule	Arg	1963	only	-	Dec	15	0:00	1:00	S
    +Rule	Arg	1964	1966	-	Mar	 1	0:00	0	-
    +Rule	Arg	1964	1966	-	Oct	15	0:00	1:00	S
    +Rule	Arg	1967	only	-	Apr	 2	0:00	0	-
    +Rule	Arg	1967	1968	-	Oct	Sun>=1	0:00	1:00	S
    +Rule	Arg	1968	1969	-	Apr	Sun>=1	0:00	0	-
    +Rule	Arg	1974	only	-	Jan	23	0:00	1:00	S
    +Rule	Arg	1974	only	-	May	 1	0:00	0	-
    +Rule	Arg	1988	only	-	Dec	 1	0:00	1:00	S
    +#
    +# From Hernan G. Otero (1995-06-26):
    +# These corrections were contributed by InterSoft Argentina S.A.,
    +# obtaining the data from the:
    +# Talleres de Hidrografia Naval Argentina
    +# (Argentine Naval Hydrography Institute)
    +Rule	Arg	1989	1993	-	Mar	Sun>=1	0:00	0	-
    +Rule	Arg	1989	1992	-	Oct	Sun>=15	0:00	1:00	S
    +#
    +# From Hernan G. Otero (1995-06-26):
    +# From this moment on, the law that mandated the daylight saving
    +# time corrections was derogated and no more modifications
    +# to the time zones (for daylight saving) are now made.
    +#
    +# From Rives McDow (2000-01-10):
    +# On October 3, 1999, 0:00 local, Argentina implemented daylight savings time,
    +# which did not result in the switch of a time zone, as they stayed 9 hours
    +# from the International Date Line.
    +Rule	Arg	1999	only	-	Oct	Sun>=1	0:00	1:00	S
    +# From Paul Eggert (2007-12-28):
    +# DST was set to expire on March 5, not March 3, but since it was converted
    +# to standard time on March 3 it's more convenient for us to pretend that
    +# it ended on March 3.
    +Rule	Arg	2000	only	-	Mar	3	0:00	0	-
    +#
    +# From Peter Gradelski via Steffen Thorsen (2000-03-01):
    +# We just checked with our Sao Paulo office and they say the government of
    +# Argentina decided not to become one of the countries that go on or off DST.
    +# So Buenos Aires should be -3 hours from GMT at all times.
    +#
    +# From Fabian L. Arce Jofre (2000-04-04):
    +# The law that claimed DST for Argentina was derogated by President Fernando
    +# de la Rua on March 2, 2000, because it would make people spend more energy
    +# in the winter time, rather than less.  The change took effect on March 3.
    +#
    +# From Mariano Absatz (2001-06-06):
    +# one of the major newspapers here in Argentina said that the 1999
    +# Timezone Law (which never was effectively applied) will (would?) be
    +# in effect.... The article is at
    +# http://ar.clarin.com/diario/2001-06-06/e-01701.htm
    +# ... The Law itself is "Ley No 25155", sanctioned on 1999-08-25, enacted
    +# 1999-09-17, and published 1999-09-21.  The official publication is at:
    +# http://www.boletin.jus.gov.ar/BON/Primera/1999/09-Septiembre/21/PDF/BO21-09-99LEG.PDF
    +# Regretfully, you have to subscribe (and pay) for the on-line version....
    +#
    +# (2001-06-12):
    +# the timezone for Argentina will not change next Sunday.
    +# Apparently it will do so on Sunday 24th....
    +# http://ar.clarin.com/diario/2001-06-12/s-03501.htm
    +#
    +# (2001-06-25):
    +# Last Friday (yes, the last working day before the date of the change), the
    +# Senate annulled the 1999 law that introduced the changes later postponed.
    +# http://www.clarin.com.ar/diario/2001-06-22/s-03601.htm
    +# It remains the vote of the Deputies..., but it will be the same....
    +# This kind of things had always been done this way in Argentina.
    +# We are still -03:00 all year round in all of the country.
    +#
    +# From Steffen Thorsen (2007-12-21):
    +# A user (Leonardo Chaim) reported that Argentina will adopt DST....
    +# all of the country (all Zone-entries) are affected.  News reports like
    +# http://www.lanacion.com.ar/opinion/nota.asp?nota_id=973037 indicate
    +# that Argentina will use DST next year as well, from October to
    +# March, although exact rules are not given.
    +#
    +# From Jesper Norgaard Welen (2007-12-26)
    +# The last hurdle of Argentina DST is over, the proposal was approved in
    +# the lower chamber too (Deputados) with a vote 192 for and 2 against.
    +# By the way thanks to Mariano Absatz and Daniel Mario Vega for the link to
    +# the original scanned proposal, where the dates and the zero hours are
    +# clear and unambiguous...This is the article about final approval:
    +# 
    +# http://www.lanacion.com.ar/politica/nota.asp?nota_id=973996
    +# 
    +#
    +# From Paul Eggert (2007-12-22):
    +# For dates after mid-2008, the following rules are my guesses and
    +# are quite possibly wrong, but are more likely than no DST at all.
    +
    +# From Alexander Krivenyshev (2008-09-05):
    +# As per message from Carlos Alberto Fonseca Arauz (Nicaragua),
    +# Argentina will start DST on Sunday October 19, 2008.
    +#
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_argentina03.html
    +# 
    +# OR
    +# 
    +# http://www.impulsobaires.com.ar/nota.php?id=57832 (in spanish)
    +# 
    +
    +# From Rodrigo Severo (2008-10-06):
    +# Here is some info available at a Gentoo bug related to TZ on Argentina's DST:
    +# ...
    +# ------- Comment #1 from [jmdocile]  2008-10-06 16:28 0000 -------
    +# Hi, there is a problem with timezone-data-2008e and maybe with
    +# timezone-data-2008f
    +# Argentinian law [Number] 25.155 is no longer valid.
    +# 
    +# http://www.infoleg.gov.ar/infolegInternet/anexos/60000-64999/60036/norma.htm
    +# 
    +# The new one is law [Number] 26.350
    +# 
    +# http://www.infoleg.gov.ar/infolegInternet/anexos/135000-139999/136191/norma.htm
    +# 
    +# So there is no summer time in Argentina for now.
    +
    +# From Mariano Absatz (2008-10-20):
    +# Decree 1693/2008 applies Law 26.350 for the summer 2008/2009 establishing DST in Argentina
    +# From 2008-10-19 until 2009-03-15
    +# 
    +# http://www.boletinoficial.gov.ar/Bora.Portal/CustomControls/PdfContent.aspx?fp=16102008&pi=3&pf=4&s=0&sec=01
    +# 
    +#
    +# Decree 1705/2008 excepting 12 Provinces from applying DST in the summer 2008/2009:
    +# Catamarca, La Rioja, Mendoza, Salta, San Juan, San Luis, La Pampa, Neuquen, Rio Negro, Chubut, Santa Cruz
    +# and Tierra del Fuego
    +# 
    +# http://www.boletinoficial.gov.ar/Bora.Portal/CustomControls/PdfContent.aspx?fp=17102008&pi=1&pf=1&s=0&sec=01
    +# 
    +#
    +# Press release 235 dated Saturday October 18th, from the Government of the Province of Jujuy saying
    +# it will not apply DST either (even when it was not included in Decree 1705/2008)
    +# 
    +# http://www.jujuy.gov.ar/index2/partes_prensa/18_10_08/235-181008.doc
    +# 
    +
    +# From fullinet (2009-10-18):
    +# As announced in
    +# 
    +# http://www.argentina.gob.ar/argentina/portal/paginas.dhtml?pagina=356
    +# 
    +# (an official .gob.ar) under title: "Sin Cambio de Hora" (english: "No hour change")
    +#
    +# "Por el momento, el Gobierno Nacional resolvio no modificar la hora
    +# oficial, decision que estaba en estudio para su implementacion el
    +# domingo 18 de octubre. Desde el Ministerio de Planificacion se anuncio
    +# que la Argentina hoy, en estas condiciones meteorologicas, no necesita
    +# la modificacion del huso horario, ya que 2009 nos encuentra con
    +# crecimiento en la produccion y distribucion energetica."
    +
    +Rule	Arg	2007	only	-	Dec	30	0:00	1:00	S
    +Rule	Arg	2008	2009	-	Mar	Sun>=15	0:00	0	-
    +Rule	Arg	2008	only	-	Oct	Sun>=15	0:00	1:00	S
    +
    +# From Mariano Absatz (2004-05-21):
    +# Today it was officially published that the Province of Mendoza is changing
    +# its timezone this winter... starting tomorrow night....
    +# http://www.gobernac.mendoza.gov.ar/boletin/pdf/20040521-27158-normas.pdf
    +# From Paul Eggert (2004-05-24):
    +# It's Law No. 7,210.  This change is due to a public power emergency, so for
    +# now we'll assume it's for this year only.
    +#
    +# From Paul Eggert (2006-03-22):
    +# 
    +# Hora de verano para la Republica Argentina (2003-06-08)
    +#  says that standard time in Argentina from 1894-10-31
    +# to 1920-05-01 was -4:16:48.25.  Go with this more-precise value
    +# over Shanks & Pottenger.
    +#
    +# From Mariano Absatz (2004-06-05):
    +# These media articles from a major newspaper mostly cover the current state:
    +# http://www.lanacion.com.ar/04/05/27/de_604825.asp
    +# http://www.lanacion.com.ar/04/05/28/de_605203.asp
    +#
    +# The following eight (8) provinces pulled clocks back to UTC-04:00 at
    +# midnight Monday May 31st. (that is, the night between 05/31 and 06/01).
    +# Apparently, all nine provinces would go back to UTC-03:00 at the same
    +# time in October 17th.
    +#
    +# Catamarca, Chubut, La Rioja, San Juan, San Luis, Santa Cruz,
    +# Tierra del Fuego, Tucuman.
    +#
    +# From Mariano Absatz (2004-06-14):
    +# ... this weekend, the Province of Tucuman decided it'd go back to UTC-03:00
    +# yesterday midnight (that is, at 24:00 Saturday 12th), since the people's
    +# annoyance with the change is much higher than the power savings obtained....
    +#
    +# From Gwillim Law (2004-06-14):
    +# http://www.lanacion.com.ar/04/06/10/de_609078.asp ...
    +#     "The time change in Tierra del Fuego was a conflicted decision from
    +#   the start.  The government had decreed that the measure would take
    +#   effect on June 1, but a normative error forced the new time to begin
    +#   three days earlier, from a Saturday to a Sunday....
    +# Our understanding was that the change was originally scheduled to take place
    +# on June 1 at 00:00 in Chubut, Santa Cruz, Tierra del Fuego (and some other
    +# provinces).  Sunday was May 30, only two days earlier.  So the article
    +# contains a contradiction.  I would give more credence to the Saturday/Sunday
    +# date than the "three days earlier" phrase, and conclude that Tierra del
    +# Fuego set its clocks back at 2004-05-30 00:00.
    +#
    +# From Steffen Thorsen (2004-10-05):
    +# The previous law 7210 which changed the province of Mendoza's time zone
    +# back in May have been modified slightly in a new law 7277, which set the
    +# new end date to 2004-09-26 (original date was 2004-10-17).
    +# http://www.gobernac.mendoza.gov.ar/boletin/pdf/20040924-27244-normas.pdf
    +#
    +# From Mariano Absatz (2004-10-05):
    +# San Juan changed from UTC-03:00 to UTC-04:00 at midnight between
    +# Sunday, May 30th and Monday, May 31st.  It changed back to UTC-03:00
    +# at midnight between Saturday, July 24th and Sunday, July 25th....
    +# http://www.sanjuan.gov.ar/prensa/archivo/000329.html
    +# http://www.sanjuan.gov.ar/prensa/archivo/000426.html
    +# http://www.sanjuan.gov.ar/prensa/archivo/000441.html
    +
    +# From Alex Krivenyshev (2008-01-17):
    +# Here are articles that Argentina Province San Luis is planning to end DST
    +# as earlier as upcoming Monday January 21, 2008 or February 2008:
    +#
    +# Provincia argentina retrasa reloj y marca diferencia con resto del pais
    +# (Argentine Province delayed clock and mark difference with the rest of the
    +# country)
    +# 
    +# http://cl.invertia.com/noticias/noticia.aspx?idNoticia=200801171849_EFE_ET4373&idtel
    +# 
    +#
    +# Es inminente que en San Luis atrasen una hora los relojes
    +# (It is imminent in San Luis clocks one hour delay)
    +# 
    +# http://www.lagaceta.com.ar/vernotae.asp?id_nota=253414
    +# 
    +#
    +# 
    +# http://www.worldtimezone.net/dst_news/dst_news_argentina02.html
    +# 
    +
    +# From Jesper Norgaard Welen (2008-01-18):
    +# The page of the San Luis provincial government
    +# 
    +# http://www.sanluis.gov.ar/notas.asp?idCanal=0&id=22812
    +# 
    +# confirms what Alex Krivenyshev has earlier sent to the tz
    +# emailing list about that San Luis plans to return to standard
    +# time much earlier than the rest of the country. It also
    +# confirms that upon request the provinces San Juan and Mendoza
    +# refused to follow San Luis in this change.
    +#
    +# The change is supposed to take place Monday the 21.st at 0:00
    +# hours. As far as I understand it if this goes ahead, we need
    +# a new timezone for San Luis (although there are also documented
    +# independent changes in the southamerica file of San Luis in
    +# 1990 and 1991 which has not been confirmed).
    +
    +# From Jesper Norgaard Welen (2008-01-25):
    +# Unfortunately the below page has become defunct, about the San Luis
    +# time change. Perhaps because it now is part of a group of pages "Most
    +# important pages of 2008."
    +#
    +# You can use
    +# 
    +# http://www.sanluis.gov.ar/notas.asp?idCanal=8141&id=22834
    +# 
    +# instead it seems. Or use "Buscador" from the main page of the San Luis
    +# government, and fill in "huso" and click OK, and you will get 3 pages
    +# from which the first one is identical to the above.
    +
    +# From Mariano Absatz (2008-01-28):
    +# I can confirm that the Province of San Luis (and so far only that
    +# province) decided to go back to UTC-3 effective midnight Jan 20th 2008
    +# (that is, Monday 21st at 0:00 is the time the clocks were delayed back
    +# 1 hour), and they intend to keep UTC-3 as their timezone all year round
    +# (that is, unless they change their mind any minute now).
    +#
    +# So we'll have to add yet another city to 'southamerica' (I think San
    +# Luis city is the mos populated city in the Province, so it'd be
    +# America/Argentina/San_Luis... of course I can't remember if San Luis's
    +# history of particular changes goes along with Mendoza or San Juan :-(
    +# (I only remember not being able to collect hard facts about San Luis
    +# back in 2004, when these provinces changed to UTC-4 for a few days, I
    +# mailed them personally and never got an answer).
    +
    +# From Paul Eggert (2008-06-30):
    +# Unless otherwise specified, data are from Shanks & Pottenger through 1992,
    +# from the IATA otherwise.  As noted below, Shanks & Pottenger say that
    +# America/Cordoba split into 6 subregions during 1991/1992, one of which
    +# was America/San_Luis, but we haven't verified this yet so for now we'll
    +# keep America/Cordoba a single region rather than splitting it into the
    +# other 5 subregions.
    +
    +# From Mariano Absatz (2009-03-13):
    +# Yesterday (with our usual 2-day notice) the Province of San Luis
    +# decided that next Sunday instead of "staying" @utc-03:00 they will go
    +# to utc-04:00 until the second Saturday in October...
    +#
    +# The press release is at
    +# 
    +# http://www.sanluis.gov.ar/SL/Paginas/NoticiaDetalle.asp?TemaId=1&InfoPrensaId=3102
    +# 
    +# (I couldn't find the decree, but
    +# 
    +# www.sanluis.gov.ar
    +# 
    +# is the official page for the Province Government).
    +#
    +# There's also a note in only one of the major national papers (La Nación) at
    +# 
    +# http://www.lanacion.com.ar/nota.asp?nota_id=1107912
    +# 
    +#
    +# The press release says:
    +#  (...) anunció que el próximo domingo a las 00:00 los puntanos deberán
    +# atrasar una hora sus relojes.
    +#
    +# A partir de entonces, San Luis establecerá el huso horario propio de
    +# la Provincia. De esta manera, durante el periodo del calendario anual
    +# 2009, el cambio horario quedará comprendido entre las 00:00 del tercer
    +# domingo de marzo y las 24:00 del segundo sábado de octubre.
    +# Quick&dirty translation
    +# (...) announced that next Sunday, at 00:00, Puntanos (the San Luis
    +# inhabitants) will have to turn back one hour their clocks
    +#
    +# Since then, San Luis will establish its own Province timezone. Thus,
    +# during 2009, this timezone change will run from 00:00 the third Sunday
    +# in March until 24:00 of the second Saturday in October.
    +
    +# From Mariano Absatz (2009-10-16):
    +# ...the Province of San Luis is a case in itself.
    +#
    +# The Law at
    +# 
    +# is ambiguous because establishes a calendar from the 2nd Sunday in
    +# October at 0:00 thru the 2nd Saturday in March at 24:00 and the
    +# complement of that starting on the 2nd Sunday of March at 0:00 and
    +# ending on the 2nd Saturday of March at 24:00.
    +#
    +# This clearly breaks every time the 1st of March or October is a Sunday.
    +#
    +# IMHO, the "spirit of the Law" is to make the changes at 0:00 on the 2nd
    +# Sunday of October and March.
    +#
    +# The problem is that the changes in the rest of the Provinces that did
    +# change in 2007/2008, were made according to the Federal Law and Decrees
    +# that did so on the 3rd Sunday of October and March.
    +#
    +# In fact, San Luis actually switched from UTC-4 to UTC-3 last Sunday
    +# (October 11th) at 0:00.
    +#
    +# So I guess a new set of rules, besides "Arg", must be made and the last
    +# America/Argentina/San_Luis entries should change to use these...
    +#
    +# I'm enclosing a patch that does what I say... regretfully, the San Luis
    +# timezone must be called "WART/WARST" even when most of the time (like,
    +# right now) WARST == ART... that is, since last Sunday, all the country
    +# is using UTC-3, but in my patch, San Luis calls it "WARST" and the rest
    +# of the country calls it "ART".
    +# ...
    +
    +# From Alexander Krivenyshev (2010-04-09):
    +# According to news reports from El Diario de la Republica Province San
    +# Luis, Argentina (standard time UTC-04) will keep Daylight Saving Time
    +# after April 11, 2010--will continue to have same time as rest of
    +# Argentina (UTC-3) (no DST).
    +#
    +# Confirmaron la prórroga del huso horario de verano (Spanish)
    +# 
    +# http://www.eldiariodelarepublica.com/index.php?option=com_content&task=view&id=29383&Itemid=9
    +# 
    +# or (some English translation):
    +# 
    +# http://www.worldtimezone.com/dst_news/dst_news_argentina08.html
    +# 
    +
    +# From Mariano Absatz (2010-04-12):
    +# yes...I can confirm this...and given that San Luis keeps calling
    +# UTC-03:00 "summer time", we should't just let San Luis go back to "Arg"
    +# rules...San Luis is still using "Western ARgentina Time" and it got
    +# stuck on Summer daylight savings time even though the summer is over.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +#
    +# Buenos Aires (BA), Capital Federal (CF),
    +Zone America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 Oct 31
    +			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
    +			-4:00	-	ART	1930 Dec
    +			-4:00	Arg	AR%sT	1969 Oct  5
    +			-3:00	Arg	AR%sT	1999 Oct  3
    +			-4:00	Arg	AR%sT	2000 Mar  3
    +			-3:00	Arg	AR%sT
    +#
    +# Cordoba (CB), Santa Fe (SF), Entre Rios (ER), Corrientes (CN), Misiones (MN),
    +# Chaco (CC), Formosa (FM), Santiago del Estero (SE)
    +#
    +# Shanks & Pottenger also make the following claims, which we haven't verified:
    +# - Formosa switched to -3:00 on 1991-01-07.
    +# - Misiones switched to -3:00 on 1990-12-29.
    +# - Chaco switched to -3:00 on 1991-01-04.
    +# - Santiago del Estero switched to -4:00 on 1991-04-01,
    +#   then to -3:00 on 1991-04-26.
    +#
    +Zone America/Argentina/Cordoba -4:16:48 - LMT	1894 Oct 31
    +			-4:16:48 -	CMT	1920 May
    +			-4:00	-	ART	1930 Dec
    +			-4:00	Arg	AR%sT	1969 Oct  5
    +			-3:00	Arg	AR%sT	1991 Mar  3
    +			-4:00	-	WART	1991 Oct 20
    +			-3:00	Arg	AR%sT	1999 Oct  3
    +			-4:00	Arg	AR%sT	2000 Mar  3
    +			-3:00	Arg	AR%sT
    +#
    +# Salta (SA), La Pampa (LP), Neuquen (NQ), Rio Negro (RN)
    +Zone America/Argentina/Salta -4:21:40 - LMT	1894 Oct 31
    +			-4:16:48 -	CMT	1920 May
    +			-4:00	-	ART	1930 Dec
    +			-4:00	Arg	AR%sT	1969 Oct  5
    +			-3:00	Arg	AR%sT	1991 Mar  3
    +			-4:00	-	WART	1991 Oct 20
    +			-3:00	Arg	AR%sT	1999 Oct  3
    +			-4:00	Arg	AR%sT	2000 Mar  3
    +			-3:00	Arg	AR%sT	2008 Oct 18
    +			-3:00	-	ART
    +#
    +# Tucuman (TM)
    +Zone America/Argentina/Tucuman -4:20:52 - LMT	1894 Oct 31
    +			-4:16:48 -	CMT	1920 May
    +			-4:00	-	ART	1930 Dec
    +			-4:00	Arg	AR%sT	1969 Oct  5
    +			-3:00	Arg	AR%sT	1991 Mar  3
    +			-4:00	-	WART	1991 Oct 20
    +			-3:00	Arg	AR%sT	1999 Oct  3
    +			-4:00	Arg	AR%sT	2000 Mar  3
    +			-3:00	-	ART	2004 Jun  1
    +			-4:00	-	WART	2004 Jun 13
    +			-3:00	Arg	AR%sT
    +#
    +# La Rioja (LR)
    +Zone America/Argentina/La_Rioja -4:27:24 - LMT	1894 Oct 31
    +			-4:16:48 -	CMT	1920 May
    +			-4:00	-	ART	1930 Dec
    +			-4:00	Arg	AR%sT	1969 Oct  5
    +			-3:00	Arg	AR%sT	1991 Mar  1
    +			-4:00	-	WART	1991 May  7
    +			-3:00	Arg	AR%sT	1999 Oct  3
    +			-4:00	Arg	AR%sT	2000 Mar  3
    +			-3:00	-	ART	2004 Jun  1
    +			-4:00	-	WART	2004 Jun 20
    +			-3:00	Arg	AR%sT	2008 Oct 18
    +			-3:00	-	ART
    +#
    +# San Juan (SJ)
    +Zone America/Argentina/San_Juan -4:34:04 - LMT	1894 Oct 31
    +			-4:16:48 -	CMT	1920 May
    +			-4:00	-	ART	1930 Dec
    +			-4:00	Arg	AR%sT	1969 Oct  5
    +			-3:00	Arg	AR%sT	1991 Mar  1
    +			-4:00	-	WART	1991 May  7
    +			-3:00	Arg	AR%sT	1999 Oct  3
    +			-4:00	Arg	AR%sT	2000 Mar  3
    +			-3:00	-	ART	2004 May 31
    +			-4:00	-	WART	2004 Jul 25
    +			-3:00	Arg	AR%sT	2008 Oct 18
    +			-3:00	-	ART
    +#
    +# Jujuy (JY)
    +Zone America/Argentina/Jujuy -4:21:12 -	LMT	1894 Oct 31
    +			-4:16:48 -	CMT	1920 May
    +			-4:00	-	ART	1930 Dec
    +			-4:00	Arg	AR%sT	1969 Oct  5
    +			-3:00	Arg	AR%sT	1990 Mar  4
    +			-4:00	-	WART	1990 Oct 28
    +			-4:00	1:00	WARST	1991 Mar 17
    +			-4:00	-	WART	1991 Oct  6
    +			-3:00	1:00	ARST	1992
    +			-3:00	Arg	AR%sT	1999 Oct  3
    +			-4:00	Arg	AR%sT	2000 Mar  3
    +			-3:00	Arg	AR%sT	2008 Oct 18
    +			-3:00	-	ART
    +#
    +# Catamarca (CT), Chubut (CH)
    +Zone America/Argentina/Catamarca -4:23:08 - LMT	1894 Oct 31
    +			-4:16:48 -	CMT	1920 May
    +			-4:00	-	ART	1930 Dec
    +			-4:00	Arg	AR%sT	1969 Oct  5
    +			-3:00	Arg	AR%sT	1991 Mar  3
    +			-4:00	-	WART	1991 Oct 20
    +			-3:00	Arg	AR%sT	1999 Oct  3
    +			-4:00	Arg	AR%sT	2000 Mar  3
    +			-3:00	-	ART	2004 Jun  1
    +			-4:00	-	WART	2004 Jun 20
    +			-3:00	Arg	AR%sT	2008 Oct 18
    +			-3:00	-	ART
    +#
    +# Mendoza (MZ)
    +Zone America/Argentina/Mendoza -4:35:16 - LMT	1894 Oct 31
    +			-4:16:48 -	CMT	1920 May
    +			-4:00	-	ART	1930 Dec
    +			-4:00	Arg	AR%sT	1969 Oct  5
    +			-3:00	Arg	AR%sT	1990 Mar  4
    +			-4:00	-	WART	1990 Oct 15
    +			-4:00	1:00	WARST	1991 Mar  1
    +			-4:00	-	WART	1991 Oct 15
    +			-4:00	1:00	WARST	1992 Mar  1
    +			-4:00	-	WART	1992 Oct 18
    +			-3:00	Arg	AR%sT	1999 Oct  3
    +			-4:00	Arg	AR%sT	2000 Mar  3
    +			-3:00	-	ART	2004 May 23
    +			-4:00	-	WART	2004 Sep 26
    +			-3:00	Arg	AR%sT	2008 Oct 18
    +			-3:00	-	ART
    +#
    +# San Luis (SL)
    +
    +Rule	SanLuis	2008	2009	-	Mar	Sun>=8	0:00	0	-
    +Rule	SanLuis	2007	2009	-	Oct	Sun>=8	0:00	1:00	S
    +
    +Zone America/Argentina/San_Luis -4:25:24 - LMT	1894 Oct 31
    +			-4:16:48 -	CMT	1920 May
    +			-4:00	-	ART	1930 Dec
    +			-4:00	Arg	AR%sT	1969 Oct  5
    +			-3:00	Arg	AR%sT	1990
    +			-3:00	1:00	ARST	1990 Mar 14
    +			-4:00	-	WART	1990 Oct 15
    +			-4:00	1:00	WARST	1991 Mar  1
    +			-4:00	-	WART	1991 Jun  1
    +			-3:00	-	ART	1999 Oct  3
    +			-4:00	1:00	WARST	2000 Mar  3
    +			-3:00	-	ART	2004 May 31
    +			-4:00	-	WART	2004 Jul 25
    +			-3:00	Arg	AR%sT	2008 Jan 21
    +			-4:00	SanLuis	WAR%sT
    +#
    +# Santa Cruz (SC)
    +Zone America/Argentina/Rio_Gallegos -4:36:52 - LMT 1894 Oct 31
    +			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
    +			-4:00	-	ART	1930 Dec
    +			-4:00	Arg	AR%sT	1969 Oct  5
    +			-3:00	Arg	AR%sT	1999 Oct  3
    +			-4:00	Arg	AR%sT	2000 Mar  3
    +			-3:00	-	ART	2004 Jun  1
    +			-4:00	-	WART	2004 Jun 20
    +			-3:00	Arg	AR%sT	2008 Oct 18
    +			-3:00	-	ART
    +#
    +# Tierra del Fuego, Antartida e Islas del Atlantico Sur (TF)
    +Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31
    +			-4:16:48 -	CMT	1920 May # Cordoba Mean Time
    +			-4:00	-	ART	1930 Dec
    +			-4:00	Arg	AR%sT	1969 Oct  5
    +			-3:00	Arg	AR%sT	1999 Oct  3
    +			-4:00	Arg	AR%sT	2000 Mar  3
    +			-3:00	-	ART	2004 May 30
    +			-4:00	-	WART	2004 Jun 20
    +			-3:00	Arg	AR%sT	2008 Oct 18
    +			-3:00	-	ART
    +
    +# Aruba
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Aruba	-4:40:24 -	LMT	1912 Feb 12	# Oranjestad
    +			-4:30	-	ANT	1965 # Netherlands Antilles Time
    +			-4:00	-	AST
    +
    +# Bolivia
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/La_Paz	-4:32:36 -	LMT	1890
    +			-4:32:36 -	CMT	1931 Oct 15 # Calamarca MT
    +			-4:32:36 1:00	BOST	1932 Mar 21 # Bolivia ST
    +			-4:00	-	BOT	# Bolivia Time
    +
    +# Brazil
    +
    +# From Paul Eggert (1993-11-18):
    +# The mayor of Rio recently attempted to change the time zone rules
    +# just in his city, in order to leave more summer time for the tourist trade.
    +# The rule change lasted only part of the day;
    +# the federal government refused to follow the city's rules, and business
    +# was in a chaos, so the mayor backed down that afternoon.
    +
    +# From IATA SSIM (1996-02):
    +# _Only_ the following states in BR1 observe DST: Rio Grande do Sul (RS),
    +# Santa Catarina (SC), Parana (PR), Sao Paulo (SP), Rio de Janeiro (RJ),
    +# Espirito Santo (ES), Minas Gerais (MG), Bahia (BA), Goias (GO),
    +# Distrito Federal (DF), Tocantins (TO), Sergipe [SE] and Alagoas [AL].
    +# [The last three states are new to this issue of the IATA SSIM.]
    +
    +# From Gwillim Law (1996-10-07):
    +# Geography, history (Tocantins was part of Goias until 1989), and other
    +# sources of time zone information lead me to believe that AL, SE, and TO were
    +# always in BR1, and so the only change was whether or not they observed DST....
    +# The earliest issue of the SSIM I have is 2/91.  Each issue from then until
    +# 9/95 says that DST is observed only in the ten states I quoted from 9/95,
    +# along with Mato Grosso (MT) and Mato Grosso do Sul (MS), which are in BR2
    +# (UTC-4)....  The other two time zones given for Brazil are BR3, which is
    +# UTC-5, no DST, and applies only in the state of Acre (AC); and BR4, which is
    +# UTC-2, and applies to Fernando de Noronha (formerly FN, but I believe it's
    +# become part of the state of Pernambuco).  The boundary between BR1 and BR2
    +# has never been clearly stated.  They've simply been called East and West.
    +# However, some conclusions can be drawn from another IATA manual: the Airline
    +# Coding Directory, which lists close to 400 airports in Brazil.  For each
    +# airport it gives a time zone which is coded to the SSIM.  From that
    +# information, I'm led to conclude that the states of Amapa (AP), Ceara (CE),
    +# Maranhao (MA), Paraiba (PR), Pernambuco (PE), Piaui (PI), and Rio Grande do
    +# Norte (RN), and the eastern part of Para (PA) are all in BR1 without DST.
    +
    +# From Marcos Tadeu (1998-09-27):
    +# 
    +# Brazilian official page
    +# 
    +
    +# From Jesper Norgaard (2000-11-03):
    +# [For an official list of which regions in Brazil use which time zones, see:]
    +# http://pcdsh01.on.br/Fusbr.htm
    +# http://pcdsh01.on.br/Fusbrhv.htm
    +
    +# From Celso Doria via David Madeo (2002-10-09):
    +# The reason for the delay this year has to do with elections in Brazil.
    +#
    +# Unlike in the United States, elections in Brazil are 100% computerized and
    +# the results are known almost immediately.  Yesterday, it was the first
    +# round of the elections when 115 million Brazilians voted for President,
    +# Governor, Senators, Federal Deputies, and State Deputies.  Nobody is
    +# counting (or re-counting) votes anymore and we know there will be a second
    +# round for the Presidency and also for some Governors.  The 2nd round will
    +# take place on October 27th.
    +#
    +# The reason why the DST will only begin November 3rd is that the thousands
    +# of electoral machines used cannot have their time changed, and since the
    +# Constitution says the elections must begin at 8:00 AM and end at 5:00 PM,
    +# the Government decided to postpone DST, instead of changing the Constitution
    +# (maybe, for the next elections, it will be possible to change the clock)...
    +
    +# From Rodrigo Severo (2004-10-04):
    +# It's just the biannual change made necessary by the much hyped, supposedly
    +# modern Brazilian eletronic voting machines which, apparently, can't deal
    +# with a time change between the first and the second rounds of the elections.
    +
    +# From Steffen Thorsen (2007-09-20):
    +# Brazil will start DST on 2007-10-14 00:00 and end on 2008-02-17 00:00:
    +# http://www.mme.gov.br/site/news/detail.do;jsessionid=BBA06811AFCAAC28F0285210913513DA?newsId=13975
    +
    +# From Paul Schulze (2008-06-24):
    +# ...by law number 11.662 of April 24, 2008 (published in the "Diario
    +# Oficial da Uniao"...) in Brazil there are changes in the timezones,
    +# effective today (00:00am at June 24, 2008) as follows:
    +#
    +# a) The timezone UTC+5 is e[x]tinguished, with all the Acre state and the
    +# part of the Amazonas state that had this timezone now being put to the
    +# timezone UTC+4
    +# b) The whole Para state now is put at timezone UTC+3, instead of just
    +# part of it, as was before.
    +#
    +# This change follows a proposal of senator Tiao Viana of Acre state, that
    +# proposed it due to concerns about open television channels displaying
    +# programs inappropriate to youths in the states that had the timezone
    +# UTC+5 too early in the night. In the occasion, some more corrections
    +# were proposed, trying to unify the timezones of any given state. This
    +# change modifies timezone rules defined in decree 2.784 of 18 June,
    +# 1913.
    +
    +# From Rodrigo Severo (2008-06-24):
    +# Just correcting the URL:
    +# 
    +# https://www.in.gov.br/imprensa/visualiza/index.jsp?jornal=do&secao=1&pagina=1&data=25/04/2008
    +# 
    +#
    +# As a result of the above Decree I believe the America/Rio_Branco
    +# timezone shall be modified from UTC-5 to UTC-4 and a new timezone shall
    +# be created to represent the...west side of the Para State. I
    +# suggest this new timezone be called Santarem as the most
    +# important/populated city in the affected area.
    +#
    +# This new timezone would be the same as the Rio_Branco timezone up to
    +# the 2008/06/24 change which would be to UTC-3 instead of UTC-4.
    +
    +# From Alex Krivenyshev (2008-06-24):
    +# This is a quick reference page for New and Old Brazil Time Zones map.
    +# 
    +# http://www.worldtimezone.com/brazil-time-new-old.php
    +# 
    +#
    +# - 4 time zones replaced by 3 time zones-eliminating time zone UTC- 05
    +# (state Acre and the part of the Amazonas will be UTC/GMT- 04) - western
    +# part of Par state is moving to one timezone UTC- 03 (from UTC -04).
    +
    +# From Paul Eggert (2002-10-10):
    +# The official decrees referenced below are mostly taken from
    +# 
    +# Decretos sobre o Horario de Verao no Brasil
    +# .
    +
    +# From Steffen Thorsen (2008-08-29):
    +# As announced by the government and many newspapers in Brazil late
    +# yesterday, Brazil will start DST on 2008-10-19 (need to change rule) and
    +# it will end on 2009-02-15 (current rule for Brazil is fine). Based on
    +# past years experience with the elections, there was a good chance that
    +# the start was postponed to November, but it did not happen this year.
    +#
    +# It has not yet been posted to http://pcdsh01.on.br/DecHV.html
    +#
    +# An official page about it:
    +# 
    +# http://www.mme.gov.br/site/news/detail.do?newsId=16722
    +# 
    +# Note that this link does not always work directly, but must be accessed
    +# by going to
    +# 
    +# http://www.mme.gov.br/first
    +# 
    +#
    +# One example link that works directly:
    +# 
    +# http://jornale.com.br/index.php?option=com_content&task=view&id=13530&Itemid=54
    +# (Portuguese)
    +# 
    +#
    +# We have a written a short article about it as well:
    +# 
    +# http://www.timeanddate.com/news/time/brazil-dst-2008-2009.html
    +# 
    +#
    +# From Alexander Krivenyshev (2011-10-04):
    +# State Bahia will return to Daylight savings time this year after 8 years off.
    +# The announcement was made by Governor Jaques Wagner in an interview to a
    +# television station in Salvador.
    +
    +# In Portuguese:
    +# 
    +# http://g1.globo.com/bahia/noticia/2011/10/governador-jaques-wagner-confirma-horario-de-verao-na-bahia.html
    +#  and
    +# 
    +# http://noticias.terra.com.br/brasil/noticias/0,,OI5390887-EI8139,00-Bahia+volta+a+ter+horario+de+verao+apos+oito+anos.html
    +# 
    +
    +# From Guilherme Bernardes Rodrigues (2011-10-07):
    +# There is news in the media, however there is still no decree about it.
    +# I just send a e-mail to Zulmira Brandão at
    +# http://pcdsh01.on.br/ the
    +# oficial agency about time in Brazil, and she confirmed that the old rule is
    +# still in force.
    +
    +# From Guilherme Bernardes Rodrigues (2011-10-14)
    +# It's official, the President signed a decree that includes Bahia in summer
    +# time.
    +#	 [ and in a second message (same day): ]
    +# I found the decree.
    +#
    +# DECRETO No- 7.584, DE 13 DE OUTUBRO DE 2011
    +# Link :
    +# 
    +# http://www.in.gov.br/visualiza/index.jsp?data=13/10/2011&jornal=1000&pagina=6&totalArquivos=6
    +# 
    +
    +# From Kelley Cook (2012-10-16):
    +# The governor of state of Bahia in Brazil announced on Thursday that
    +# due to public pressure, he is reversing the DST policy they implemented
    +# last year and will not be going to Summer Time on October 21st....
    +# http://www.correio24horas.com.br/r/artigo/apos-pressoes-wagner-suspende-horario-de-verao-na-bahia
    +
    +# From Rodrigo Severo (2012-10-16):
    +# Tocantins state will have DST.
    +# http://noticias.terra.com.br/brasil/noticias/0,,OI6232536-EI306.html
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +# Decree 20,466 (1931-10-01)
    +# Decree 21,896 (1932-01-10)
    +Rule	Brazil	1931	only	-	Oct	 3	11:00	1:00	S
    +Rule	Brazil	1932	1933	-	Apr	 1	 0:00	0	-
    +Rule	Brazil	1932	only	-	Oct	 3	 0:00	1:00	S
    +# Decree 23,195 (1933-10-10)
    +# revoked DST.
    +# Decree 27,496 (1949-11-24)
    +# Decree 27,998 (1950-04-13)
    +Rule	Brazil	1949	1952	-	Dec	 1	 0:00	1:00	S
    +Rule	Brazil	1950	only	-	Apr	16	 1:00	0	-
    +Rule	Brazil	1951	1952	-	Apr	 1	 0:00	0	-
    +# Decree 32,308 (1953-02-24)
    +Rule	Brazil	1953	only	-	Mar	 1	 0:00	0	-
    +# Decree 34,724 (1953-11-30)
    +# revoked DST.
    +# Decree 52,700 (1963-10-18)
    +# established DST from 1963-10-23 00:00 to 1964-02-29 00:00
    +# in SP, RJ, GB, MG, ES, due to the prolongation of the drought.
    +# Decree 53,071 (1963-12-03)
    +# extended the above decree to all of the national territory on 12-09.
    +Rule	Brazil	1963	only	-	Dec	 9	 0:00	1:00	S
    +# Decree 53,604 (1964-02-25)
    +# extended summer time by one day to 1964-03-01 00:00 (start of school).
    +Rule	Brazil	1964	only	-	Mar	 1	 0:00	0	-
    +# Decree 55,639 (1965-01-27)
    +Rule	Brazil	1965	only	-	Jan	31	 0:00	1:00	S
    +Rule	Brazil	1965	only	-	Mar	31	 0:00	0	-
    +# Decree 57,303 (1965-11-22)
    +Rule	Brazil	1965	only	-	Dec	 1	 0:00	1:00	S
    +# Decree 57,843 (1966-02-18)
    +Rule	Brazil	1966	1968	-	Mar	 1	 0:00	0	-
    +Rule	Brazil	1966	1967	-	Nov	 1	 0:00	1:00	S
    +# Decree 63,429 (1968-10-15)
    +# revoked DST.
    +# Decree 91,698 (1985-09-27)
    +Rule	Brazil	1985	only	-	Nov	 2	 0:00	1:00	S
    +# Decree 92,310 (1986-01-21)
    +# Decree 92,463 (1986-03-13)
    +Rule	Brazil	1986	only	-	Mar	15	 0:00	0	-
    +# Decree 93,316 (1986-10-01)
    +Rule	Brazil	1986	only	-	Oct	25	 0:00	1:00	S
    +Rule	Brazil	1987	only	-	Feb	14	 0:00	0	-
    +# Decree 94,922 (1987-09-22)
    +Rule	Brazil	1987	only	-	Oct	25	 0:00	1:00	S
    +Rule	Brazil	1988	only	-	Feb	 7	 0:00	0	-
    +# Decree 96,676 (1988-09-12)
    +# except for the states of AC, AM, PA, RR, RO, and AP (then a territory)
    +Rule	Brazil	1988	only	-	Oct	16	 0:00	1:00	S
    +Rule	Brazil	1989	only	-	Jan	29	 0:00	0	-
    +# Decree 98,077 (1989-08-21)
    +# with the same exceptions
    +Rule	Brazil	1989	only	-	Oct	15	 0:00	1:00	S
    +Rule	Brazil	1990	only	-	Feb	11	 0:00	0	-
    +# Decree 99,530 (1990-09-17)
    +# adopted by RS, SC, PR, SP, RJ, ES, MG, GO, MS, DF.
    +# Decree 99,629 (1990-10-19) adds BA, MT.
    +Rule	Brazil	1990	only	-	Oct	21	 0:00	1:00	S
    +Rule	Brazil	1991	only	-	Feb	17	 0:00	0	-
    +# Unnumbered decree (1991-09-25)
    +# adopted by RS, SC, PR, SP, RJ, ES, MG, BA, GO, MT, MS, DF.
    +Rule	Brazil	1991	only	-	Oct	20	 0:00	1:00	S
    +Rule	Brazil	1992	only	-	Feb	 9	 0:00	0	-
    +# Unnumbered decree (1992-10-16)
    +# adopted by same states.
    +Rule	Brazil	1992	only	-	Oct	25	 0:00	1:00	S
    +Rule	Brazil	1993	only	-	Jan	31	 0:00	0	-
    +# Decree 942 (1993-09-28)
    +# adopted by same states, plus AM.
    +# Decree 1,252 (1994-09-22;
    +# web page corrected 2004-01-07) adopted by same states, minus AM.
    +# Decree 1,636 (1995-09-14)
    +# adopted by same states, plus MT and TO.
    +# Decree 1,674 (1995-10-13)
    +# adds AL, SE.
    +Rule	Brazil	1993	1995	-	Oct	Sun>=11	 0:00	1:00	S
    +Rule	Brazil	1994	1995	-	Feb	Sun>=15	 0:00	0	-
    +Rule	Brazil	1996	only	-	Feb	11	 0:00	0	-
    +# Decree 2,000 (1996-09-04)
    +# adopted by same states, minus AL, SE.
    +Rule	Brazil	1996	only	-	Oct	 6	 0:00	1:00	S
    +Rule	Brazil	1997	only	-	Feb	16	 0:00	0	-
    +# From Daniel C. Sobral (1998-02-12):
    +# In 1997, the DS began on October 6. The stated reason was that
    +# because international television networks ignored Brazil's policy on DS,
    +# they bought the wrong times on satellite for coverage of Pope's visit.
    +# This year, the ending date of DS was postponed to March 1
    +# to help dealing with the shortages of electric power.
    +#
    +# Decree 2,317 (1997-09-04), adopted by same states.
    +Rule	Brazil	1997	only	-	Oct	 6	 0:00	1:00	S
    +# Decree 2,495
    +# (1998-02-10)
    +Rule	Brazil	1998	only	-	Mar	 1	 0:00	0	-
    +# Decree 2,780 (1998-09-11)
    +# adopted by the same states as before.
    +Rule	Brazil	1998	only	-	Oct	11	 0:00	1:00	S
    +Rule	Brazil	1999	only	-	Feb	21	 0:00	0	-
    +# Decree 3,150
    +# (1999-08-23) adopted by same states.
    +# Decree 3,188 (1999-09-30)
    +# adds SE, AL, PB, PE, RN, CE, PI, MA and RR.
    +Rule	Brazil	1999	only	-	Oct	 3	 0:00	1:00	S
    +Rule	Brazil	2000	only	-	Feb	27	 0:00	0	-
    +# Decree 3,592 (2000-09-06)
    +# adopted by the same states as before.
    +# Decree 3,630 (2000-10-13)
    +# repeals DST in PE and RR, effective 2000-10-15 00:00.
    +# Decree 3,632 (2000-10-17)
    +# repeals DST in SE, AL, PB, RN, CE, PI and MA, effective 2000-10-22 00:00.
    +# Decree 3,916
    +# (2001-09-13) reestablishes DST in AL, CE, MA, PB, PE, PI, RN, SE.
    +Rule	Brazil	2000	2001	-	Oct	Sun>=8	 0:00	1:00	S
    +Rule	Brazil	2001	2006	-	Feb	Sun>=15	 0:00	0	-
    +# Decree 4,399 (2002-10-01) repeals DST in AL, CE, MA, PB, PE, PI, RN, SE.
    +# 4,399
    +Rule	Brazil	2002	only	-	Nov	 3	 0:00	1:00	S
    +# Decree 4,844 (2003-09-24; corrected 2003-09-26) repeals DST in BA, MT, TO.
    +# 4,844
    +Rule	Brazil	2003	only	-	Oct	19	 0:00	1:00	S
    +# Decree 5,223 (2004-10-01) reestablishes DST in MT.
    +# 5,223
    +Rule	Brazil	2004	only	-	Nov	 2	 0:00	1:00	S
    +# Decree 5,539 (2005-09-19),
    +# adopted by the same states as before.
    +Rule	Brazil	2005	only	-	Oct	16	 0:00	1:00	S
    +# Decree 5,920 (2006-10-03),
    +# adopted by the same states as before.
    +Rule	Brazil	2006	only	-	Nov	 5	 0:00	1:00	S
    +Rule	Brazil	2007	only	-	Feb	25	 0:00	0	-
    +# Decree 6,212 (2007-09-26),
    +# adopted by the same states as before.
    +Rule	Brazil	2007	only	-	Oct	Sun>=8	 0:00	1:00	S
    +# From Frederico A. C. Neves (2008-09-10):
    +# Acording to this decree
    +# 
    +# http://www.planalto.gov.br/ccivil_03/_Ato2007-2010/2008/Decreto/D6558.htm
    +# 
    +# [t]he DST period in Brazil now on will be from the 3rd Oct Sunday to the
    +# 3rd Feb Sunday. There is an exception on the return date when this is
    +# the Carnival Sunday then the return date will be the next Sunday...
    +Rule	Brazil	2008	max	-	Oct	Sun>=15	0:00	1:00	S
    +Rule	Brazil	2008	2011	-	Feb	Sun>=15	0:00	0	-
    +Rule	Brazil	2012	only	-	Feb	Sun>=22	0:00	0	-
    +Rule	Brazil	2013	2014	-	Feb	Sun>=15	0:00	0	-
    +Rule	Brazil	2015	only	-	Feb	Sun>=22	0:00	0	-
    +Rule	Brazil	2016	2022	-	Feb	Sun>=15	0:00	0	-
    +Rule	Brazil	2023	only	-	Feb	Sun>=22	0:00	0	-
    +Rule	Brazil	2024	2025	-	Feb	Sun>=15	0:00	0	-
    +Rule	Brazil	2026	only	-	Feb	Sun>=22	0:00	0	-
    +Rule	Brazil	2027	2033	-	Feb	Sun>=15	0:00	0	-
    +Rule	Brazil	2034	only	-	Feb	Sun>=22	0:00	0	-
    +Rule	Brazil	2035	2036	-	Feb	Sun>=15	0:00	0	-
    +Rule	Brazil	2037	only	-	Feb	Sun>=22	0:00	0	-
    +# From Arthur David Olson (2008-09-29):
    +# The next is wrong in some years but is better than nothing.
    +Rule	Brazil	2038	max	-	Feb	Sun>=15	0:00	0	-
    +
    +# The latest ruleset listed above says that the following states observe DST:
    +# DF, ES, GO, MG, MS, MT, PR, RJ, RS, SC, SP.
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +#
    +# Fernando de Noronha (administratively part of PE)
    +Zone America/Noronha	-2:09:40 -	LMT	1914
    +			-2:00	Brazil	FN%sT	1990 Sep 17
    +			-2:00	-	FNT	1999 Sep 30
    +			-2:00	Brazil	FN%sT	2000 Oct 15
    +			-2:00	-	FNT	2001 Sep 13
    +			-2:00	Brazil	FN%sT	2002 Oct  1
    +			-2:00	-	FNT
    +# Other Atlantic islands have no permanent settlement.
    +# These include Trindade and Martin Vaz (administratively part of ES),
    +# Atol das Rocas (RN), and Penedos de Sao Pedro e Sao Paulo (PE).
    +# Fernando de Noronha was a separate territory from 1942-09-02 to 1989-01-01;
    +# it also included the Penedos.
    +#
    +# Amapa (AP), east Para (PA)
    +# East Para includes Belem, Maraba, Serra Norte, and Sao Felix do Xingu.
    +# The division between east and west Para is the river Xingu.
    +# In the north a very small part from the river Javary (now Jari I guess,
    +# the border with Amapa) to the Amazon, then to the Xingu.
    +Zone America/Belem	-3:13:56 -	LMT	1914
    +			-3:00	Brazil	BR%sT	1988 Sep 12
    +			-3:00	-	BRT
    +#
    +# west Para (PA)
    +# West Para includes Altamira, Oribidos, Prainha, Oriximina, and Santarem.
    +Zone America/Santarem	-3:38:48 -	LMT	1914
    +			-4:00	Brazil	AM%sT	1988 Sep 12
    +			-4:00	-	AMT	2008 Jun 24 00:00
    +			-3:00	-	BRT
    +#
    +# Maranhao (MA), Piaui (PI), Ceara (CE), Rio Grande do Norte (RN),
    +# Paraiba (PB)
    +Zone America/Fortaleza	-2:34:00 -	LMT	1914
    +			-3:00	Brazil	BR%sT	1990 Sep 17
    +			-3:00	-	BRT	1999 Sep 30
    +			-3:00	Brazil	BR%sT	2000 Oct 22
    +			-3:00	-	BRT	2001 Sep 13
    +			-3:00	Brazil	BR%sT	2002 Oct  1
    +			-3:00	-	BRT
    +#
    +# Pernambuco (PE) (except Atlantic islands)
    +Zone America/Recife	-2:19:36 -	LMT	1914
    +			-3:00	Brazil	BR%sT	1990 Sep 17
    +			-3:00	-	BRT	1999 Sep 30
    +			-3:00	Brazil	BR%sT	2000 Oct 15
    +			-3:00	-	BRT	2001 Sep 13
    +			-3:00	Brazil	BR%sT	2002 Oct  1
    +			-3:00	-	BRT
    +#
    +# Tocantins (TO)
    +Zone America/Araguaina	-3:12:48 -	LMT	1914
    +			-3:00	Brazil	BR%sT	1990 Sep 17
    +			-3:00	-	BRT	1995 Sep 14
    +			-3:00	Brazil	BR%sT	2003 Sep 24
    +			-3:00	-	BRT	2012 Oct 21
    +			-3:00	Brazil	BR%sT
    +#
    +# Alagoas (AL), Sergipe (SE)
    +Zone America/Maceio	-2:22:52 -	LMT	1914
    +			-3:00	Brazil	BR%sT	1990 Sep 17
    +			-3:00	-	BRT	1995 Oct 13
    +			-3:00	Brazil	BR%sT	1996 Sep  4
    +			-3:00	-	BRT	1999 Sep 30
    +			-3:00	Brazil	BR%sT	2000 Oct 22
    +			-3:00	-	BRT	2001 Sep 13
    +			-3:00	Brazil	BR%sT	2002 Oct  1
    +			-3:00	-	BRT
    +#
    +# Bahia (BA)
    +# There are too many Salvadors elsewhere, so use America/Bahia instead
    +# of America/Salvador.
    +Zone America/Bahia	-2:34:04 -	LMT	1914
    +			-3:00	Brazil	BR%sT	2003 Sep 24
    +			-3:00	-	BRT	2011 Oct 16
    +			-3:00	Brazil	BR%sT	2012 Oct 21
    +			-3:00	-	BRT
    +#
    +# Goias (GO), Distrito Federal (DF), Minas Gerais (MG),
    +# Espirito Santo (ES), Rio de Janeiro (RJ), Sao Paulo (SP), Parana (PR),
    +# Santa Catarina (SC), Rio Grande do Sul (RS)
    +Zone America/Sao_Paulo	-3:06:28 -	LMT	1914
    +			-3:00	Brazil	BR%sT	1963 Oct 23 00:00
    +			-3:00	1:00	BRST	1964
    +			-3:00	Brazil	BR%sT
    +#
    +# Mato Grosso do Sul (MS)
    +Zone America/Campo_Grande -3:38:28 -	LMT	1914
    +			-4:00	Brazil	AM%sT
    +#
    +# Mato Grosso (MT)
    +Zone America/Cuiaba	-3:44:20 -	LMT	1914
    +			-4:00	Brazil	AM%sT	2003 Sep 24
    +			-4:00	-	AMT	2004 Oct  1
    +			-4:00	Brazil	AM%sT
    +#
    +# Rondonia (RO)
    +Zone America/Porto_Velho -4:15:36 -	LMT	1914
    +			-4:00	Brazil	AM%sT	1988 Sep 12
    +			-4:00	-	AMT
    +#
    +# Roraima (RR)
    +Zone America/Boa_Vista	-4:02:40 -	LMT	1914
    +			-4:00	Brazil	AM%sT	1988 Sep 12
    +			-4:00	-	AMT	1999 Sep 30
    +			-4:00	Brazil	AM%sT	2000 Oct 15
    +			-4:00	-	AMT
    +#
    +# east Amazonas (AM): Boca do Acre, Jutai, Manaus, Floriano Peixoto
    +# The great circle line from Tabatinga to Porto Acre divides
    +# east from west Amazonas.
    +Zone America/Manaus	-4:00:04 -	LMT	1914
    +			-4:00	Brazil	AM%sT	1988 Sep 12
    +			-4:00	-	AMT	1993 Sep 28
    +			-4:00	Brazil	AM%sT	1994 Sep 22
    +			-4:00	-	AMT
    +#
    +# west Amazonas (AM): Atalaia do Norte, Boca do Maoco, Benjamin Constant,
    +#	Eirunepe, Envira, Ipixuna
    +Zone America/Eirunepe	-4:39:28 -	LMT	1914
    +			-5:00	Brazil	AC%sT	1988 Sep 12
    +			-5:00	-	ACT	1993 Sep 28
    +			-5:00	Brazil	AC%sT	1994 Sep 22
    +			-5:00	-	ACT	2008 Jun 24 00:00
    +			-4:00	-	AMT
    +#
    +# Acre (AC)
    +Zone America/Rio_Branco	-4:31:12 -	LMT	1914
    +			-5:00	Brazil	AC%sT	1988 Sep 12
    +			-5:00	-	ACT	2008 Jun 24 00:00
    +			-4:00	-	AMT
    +
    +# Chile
    +
    +# From Eduardo Krell (1995-10-19):
    +# The law says to switch to DST at midnight [24:00] on the second SATURDAY
    +# of October....  The law is the same for March and October.
    +# (1998-09-29):
    +# Because of the drought this year, the government decided to go into
    +# DST earlier (saturday 9/26 at 24:00). This is a one-time change only ...
    +# (unless there's another dry season next year, I guess).
    +
    +# From Julio I. Pacheco Troncoso (1999-03-18):
    +# Because of the same drought, the government decided to end DST later,
    +# on April 3, (one-time change).
    +
    +# From Oscar van Vlijmen (2006-10-08):
    +# http://www.horaoficial.cl/cambio.htm
    +
    +# From Jesper Norgaard Welen (2006-10-08):
    +# I think that there are some obvious mistakes in the suggested link
    +# from Oscar van Vlijmen,... for instance entry 66 says that GMT-4
    +# ended 1990-09-12 while entry 67 only begins GMT-3 at 1990-09-15
    +# (they should have been 1990-09-15 and 1990-09-16 respectively), but
    +# anyhow it clears up some doubts too.
    +
    +# From Paul Eggert (2006-12-27):
    +# The following data for Chile and America/Santiago are from
    +#  (2006-09-20), transcribed by
    +# Jesper Norgaard Welen.  The data for Pacific/Easter are from Shanks
    +# & Pottenger, except with DST transitions after 1932 cloned from
    +# America/Santiago.  The pre-1980 Pacific/Easter data are dubious,
    +# but we have no other source.
    +
    +# From German Poo-Caaman~o (2008-03-03):
    +# Due to drought, Chile extends Daylight Time in three weeks.  This
    +# is one-time change (Saturday 3/29 at 24:00 for America/Santiago
    +# and Saturday 3/29 at 22:00 for Pacific/Easter)
    +# The Supreme Decree is located at
    +# 
    +# http://www.shoa.cl/servicios/supremo316.pdf
    +# 
    +# and the instructions for 2008 are located in:
    +# 
    +# http://www.horaoficial.cl/cambio.htm
    +# .
    +
    +# From Jose Miguel Garrido (2008-03-05):
    +# ...
    +# You could see the announces of the change on
    +# 
    +# http://www.shoa.cl/noticias/2008/04hora/hora.htm
    +# .
    +
    +# From Angel Chiang (2010-03-04):
    +# Subject: DST in Chile exceptionally extended to 3 April due to earthquake
    +# 
    +# http://www.gobiernodechile.cl/viewNoticia.aspx?idArticulo=30098
    +# 
    +# (in Spanish, last paragraph).
    +#
    +# This is breaking news. There should be more information available later.
    +
    +# From Arthur Daivd Olson (2010-03-06):
    +# Angel Chiang's message confirmed by Julio Pacheco; Julio provided a patch.
    +
    +# From Glenn Eychaner (2011-03-02): [geychaner@mac.com]
    +# It appears that the Chilean government has decided to postpone the
    +# change from summer time to winter time again, by three weeks to April
    +# 2nd:
    +# 
    +# http://www.emol.com/noticias/nacional/detalle/detallenoticias.asp?idnoticia=467651
    +# 
    +#
    +# This is not yet reflected in the offical "cambio de hora" site, but
    +# probably will be soon:
    +# 
    +# http://www.horaoficial.cl/cambio.htm
    +# 
    +
    +# From Arthur David Olson (2011-03-02):
    +# The emol.com article mentions a water shortage as the cause of the
    +# postponement, which may mean that it's not a permanent change.
    +
    +# From Glenn Eychaner (2011-03-28):
    +# The article:
    +# 
    +# http://diario.elmercurio.com/2011/03/28/_portada/_portada/noticias/7565897A-CA86-49E6-9E03-660B21A4883E.htm?id=3D{7565897A-CA86-49E6-9E03-660B21A4883E}
    +# 
    +#
    +# In English:
    +# Chile's clocks will go back an hour this year on the 7th of May instead
    +# of this Saturday. They will go forward again the 3rd Saturday in
    +# August, not in October as they have since 1968. This is a pilot plan
    +# which will be reevaluated in 2012.
    +
    +# From Mauricio Parada (2012-02-22), translated by Glenn Eychaner (2012-02-23):
    +# As stated in the website of the Chilean Energy Ministry
    +# http://www.minenergia.cl/ministerio/noticias/generales/gobierno-anuncia-fechas-de-cambio-de.html
    +# The Chilean Government has decided to postpone the entrance into winter time
    +# (to leave DST) from March 11 2012 to April 28th 2012. The decision has not
    +# been yet formalized but it will within the next days.
    +# Quote from the website communication:
    +#
    +# 6. For the year 2012, the dates of entry into winter time will be as follows:
    +# a. Saturday April 28, 2012, clocks should go back 60 minutes; that is, at
    +# 23:59:59, instead of passing to 0:00, the time should be adjusted to be 23:00
    +# of the same day.
    +# b. Saturday, September 1, 2012, clocks should go forward 60 minutes; that is,
    +# at 23:59:59, instead of passing to 0:00, the time should be adjusted to be
    +# 01:00 on September 2.
    +#
    +# Note that...this is yet another "temporary" change that will be reevaluated
    +# AGAIN in 2013.
    +
    +# NOTE: ChileAQ rules for Antarctic bases are stored separately in the
    +# 'antarctica' file.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Chile	1927	1932	-	Sep	 1	0:00	1:00	S
    +Rule	Chile	1928	1932	-	Apr	 1	0:00	0	-
    +Rule	Chile	1942	only	-	Jun	 1	4:00u	0	-
    +Rule	Chile	1942	only	-	Aug	 1	5:00u	1:00	S
    +Rule	Chile	1946	only	-	Jul	15	4:00u	1:00	S
    +Rule	Chile	1946	only	-	Sep	 1	3:00u	0:00	-
    +Rule	Chile	1947	only	-	Apr	 1	4:00u	0	-
    +Rule	Chile	1968	only	-	Nov	 3	4:00u	1:00	S
    +Rule	Chile	1969	only	-	Mar	30	3:00u	0	-
    +Rule	Chile	1969	only	-	Nov	23	4:00u	1:00	S
    +Rule	Chile	1970	only	-	Mar	29	3:00u	0	-
    +Rule	Chile	1971	only	-	Mar	14	3:00u	0	-
    +Rule	Chile	1970	1972	-	Oct	Sun>=9	4:00u	1:00	S
    +Rule	Chile	1972	1986	-	Mar	Sun>=9	3:00u	0	-
    +Rule	Chile	1973	only	-	Sep	30	4:00u	1:00	S
    +Rule	Chile	1974	1987	-	Oct	Sun>=9	4:00u	1:00	S
    +Rule	Chile	1987	only	-	Apr	12	3:00u	0	-
    +Rule	Chile	1988	1989	-	Mar	Sun>=9	3:00u	0	-
    +Rule	Chile	1988	only	-	Oct	Sun>=1	4:00u	1:00	S
    +Rule	Chile	1989	only	-	Oct	Sun>=9	4:00u	1:00	S
    +Rule	Chile	1990	only	-	Mar	18	3:00u	0	-
    +Rule	Chile	1990	only	-	Sep	16	4:00u	1:00	S
    +Rule	Chile	1991	1996	-	Mar	Sun>=9	3:00u	0	-
    +Rule	Chile	1991	1997	-	Oct	Sun>=9	4:00u	1:00	S
    +Rule	Chile	1997	only	-	Mar	30	3:00u	0	-
    +Rule	Chile	1998	only	-	Mar	Sun>=9	3:00u	0	-
    +Rule	Chile	1998	only	-	Sep	27	4:00u	1:00	S
    +Rule	Chile	1999	only	-	Apr	 4	3:00u	0	-
    +Rule	Chile	1999	2010	-	Oct	Sun>=9	4:00u	1:00	S
    +Rule	Chile	2000	2007	-	Mar	Sun>=9	3:00u	0	-
    +# N.B.: the end of March 29 in Chile is March 30 in Universal time,
    +# which is used below in specifying the transition.
    +Rule	Chile	2008	only	-	Mar	30	3:00u	0	-
    +Rule	Chile	2009	only	-	Mar	Sun>=9	3:00u	0	-
    +Rule	Chile	2010	only	-	Apr	Sun>=1	3:00u	0	-
    +Rule	Chile	2011	only	-	May	Sun>=2	3:00u	0	-
    +Rule	Chile	2011	only	-	Aug	Sun>=16	4:00u	1:00	S
    +Rule	Chile	2012	only	-	Apr	Sun>=23	3:00u	0	-
    +Rule	Chile	2012	only	-	Sep	Sun>=2	4:00u	1:00	S
    +Rule	Chile	2013	max	-	Mar	Sun>=9	3:00u	0	-
    +Rule	Chile	2013	max	-	Oct	Sun>=9	4:00u	1:00	S
    +# IATA SSIM anomalies: (1992-02) says 1992-03-14;
    +# (1996-09) says 1998-03-08.  Ignore these.
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Santiago	-4:42:46 -	LMT	1890
    +			-4:42:46 -	SMT	1910 	    # Santiago Mean Time
    +			-5:00	-	CLT	1916 Jul  1 # Chile Time
    +			-4:42:46 -	SMT	1918 Sep  1 # Santiago Mean Time
    +			-4:00	-	CLT	1919 Jul  1 # Chile Time
    +			-4:42:46 -	SMT	1927 Sep  1 # Santiago Mean Time
    +			-5:00	Chile	CL%sT	1947 May 22 # Chile Time
    +			-4:00	Chile	CL%sT
    +Zone Pacific/Easter	-7:17:44 -	LMT	1890
    +			-7:17:28 -	EMT	1932 Sep    # Easter Mean Time
    +			-7:00	Chile	EAS%sT	1982 Mar 13 21:00 # Easter I Time
    +			-6:00	Chile	EAS%sT
    +#
    +# Sala y Gomez Island is like Pacific/Easter.
    +# Other Chilean locations, including Juan Fernandez Is, San Ambrosio,
    +# San Felix, and Antarctic bases, are like America/Santiago.
    +
    +# Colombia
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	CO	1992	only	-	May	 3	0:00	1:00	S
    +Rule	CO	1993	only	-	Apr	 4	0:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Bogota	-4:56:20 -	LMT	1884 Mar 13
    +			-4:56:20 -	BMT	1914 Nov 23 # Bogota Mean Time
    +			-5:00	CO	CO%sT	# Colombia Time
    +# Malpelo, Providencia, San Andres
    +# no information; probably like America/Bogota
    +
    +# Curacao
    +#
    +# From Paul Eggert (2006-03-22):
    +# Shanks & Pottenger say that The Bottom and Philipsburg have been at
    +# -4:00 since standard time was introduced on 1912-03-02; and that
    +# Kralendijk and Rincon used Kralendijk Mean Time (-4:33:08) from
    +# 1912-02-02 to 1965-01-01.  The former is dubious, since S&P also say
    +# Saba Island has been like Curacao.
    +# This all predates our 1970 cutoff, though.
    +#
    +# By July 2007 Curacao and St Maarten are planned to become
    +# associated states within the Netherlands, much like Aruba;
    +# Bonaire, Saba and St Eustatius would become directly part of the
    +# Netherlands as Kingdom Islands.  This won't affect their time zones
    +# though, as far as we know.
    +#
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Curacao	-4:35:44 -	LMT	1912 Feb 12	# Willemstad
    +			-4:30	-	ANT	1965 # Netherlands Antilles Time
    +			-4:00	-	AST
    +
    +# From Arthur David Olson (2011-06-15):
    +# At least for now, use links for places with new iso3166 codes.
    +# The name "Lower Prince's Quarter" is both longer than fourteen charaters
    +# and contains an apostrophe; use "Lower_Princes" below.
    +
    +Link	America/Curacao	America/Lower_Princes # Sint Maarten
    +Link	America/Curacao	America/Kralendijk # Bonaire, Sint Estatius and Saba
    +
    +# Ecuador
    +#
    +# From Paul Eggert (2007-03-04):
    +# Apparently Ecuador had a failed experiment with DST in 1992.
    +#  (2007-02-27) and
    +#  (2006-11-06) both
    +# talk about "hora Sixto".  Leave this alone for now, as we have no data.
    +#
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Guayaquil	-5:19:20 -	LMT	1890
    +			-5:14:00 -	QMT	1931 # Quito Mean Time
    +			-5:00	-	ECT	     # Ecuador Time
    +Zone Pacific/Galapagos	-5:58:24 -	LMT	1931 # Puerto Baquerizo Moreno
    +			-5:00	-	ECT	1986
    +			-6:00	-	GALT	     # Galapagos Time
    +
    +# Falklands
    +
    +# From Paul Eggert (2006-03-22):
    +# Between 1990 and 2000 inclusive, Shanks & Pottenger and the IATA agree except
    +# the IATA gives 1996-09-08.  Go with Shanks & Pottenger.
    +
    +# From Falkland Islands Government Office, London (2001-01-22)
    +# via Jesper Norgaard:
    +# ... the clocks revert back to Local Mean Time at 2 am on Sunday 15
    +# April 2001 and advance one hour to summer time at 2 am on Sunday 2
    +# September.  It is anticipated that the clocks will revert back at 2
    +# am on Sunday 21 April 2002 and advance to summer time at 2 am on
    +# Sunday 1 September.
    +
    +# From Rives McDow (2001-02-13):
    +#
    +# I have communicated several times with people there, and the last
    +# time I had communications that was helpful was in 1998.  Here is
    +# what was said then:
    +#
    +# "The general rule was that Stanley used daylight saving and the Camp
    +# did not. However for various reasons many people in the Camp have
    +# started to use daylight saving (known locally as 'Stanley Time')
    +# There is no rule as to who uses daylight saving - it is a matter of
    +# personal choice and so it is impossible to draw a map showing who
    +# uses it and who does not. Any list would be out of date as soon as
    +# it was produced. This year daylight saving ended on April 18/19th
    +# and started again on September 12/13th.  I do not know what the rule
    +# is, but can find out if you like.  We do not change at the same time
    +# as UK or Chile."
    +#
    +# I did have in my notes that the rule was "Second Saturday in Sep at
    +# 0:00 until third Saturday in Apr at 0:00".  I think that this does
    +# not agree in some cases with Shanks; is this true?
    +#
    +# Also, there is no mention in the list that some areas in the
    +# Falklands do not use DST.  I have found in my communications there
    +# that these areas are on the western half of East Falkland and all of
    +# West Falkland.  Stanley is the only place that consistently observes
    +# DST.  Again, as in other places in the world, the farmers don't like
    +# it.  West Falkland is almost entirely sheep farmers.
    +#
    +# I know one lady there that keeps a list of which farm keeps DST and
    +# which doesn't each year.  She runs a shop in Stanley, and says that
    +# the list changes each year.  She uses it to communicate to her
    +# customers, catching them when they are home for lunch or dinner.
    +
    +# From Paul Eggert (2001-03-05):
    +# For now, we'll just record the time in Stanley, since we have no
    +# better info.
    +
    +# From Steffen Thorsen (2011-04-01):
    +# The Falkland Islands will not turn back clocks this winter, but stay on
    +# daylight saving time.
    +#
    +# One source:
    +# 
    +# http://www.falklandnews.com/public/story.cfm?get=5914&source=3
    +# 
    +#
    +# We have gotten this confirmed by a clerk of the legislative assembly:
    +# Normally the clocks revert to Local Mean Time (UTC/GMT -4 hours) on the
    +# third Sunday of April at 0200hrs and advance to Summer Time (UTC/GMT -3
    +# hours) on the first Sunday of September at 0200hrs.
    +#
    +# IMPORTANT NOTE: During 2011, on a trial basis, the Falkland Islands
    +# will not revert to local mean time, but clocks will remain on Summer
    +# time (UTC/GMT - 3 hours) throughout the whole of 2011.  Any long term
    +# change to local time following the trial period will be notified.
    +#
    +# From Andrew Newman (2012-02-24)
    +# A letter from Justin McPhee, Chief Executive,
    +# Cable & Wireless Falkland Islands (dated 2012-02-22)
    +# states...
    +#   The current Atlantic/Stanley entry under South America expects the
    +#   clocks to go back to standard Falklands Time (FKT) on the 15th April.
    +#   The database entry states that in 2011 Stanley was staying on fixed
    +#   summer time on a trial basis only.  FIG need to contact IANA and/or
    +#   the maintainers of the database to inform them we're adopting
    +#   the same policy this year and suggest recommendations for future years.
    +#
    +# For now we will assume permanent summer time for the Falklands
    +# until advised differently (to apply for 2012 and beyond, after the 2011
    +# experiment was apparently successful.)
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Falk	1937	1938	-	Sep	lastSun	0:00	1:00	S
    +Rule	Falk	1938	1942	-	Mar	Sun>=19	0:00	0	-
    +Rule	Falk	1939	only	-	Oct	1	0:00	1:00	S
    +Rule	Falk	1940	1942	-	Sep	lastSun	0:00	1:00	S
    +Rule	Falk	1943	only	-	Jan	1	0:00	0	-
    +Rule	Falk	1983	only	-	Sep	lastSun	0:00	1:00	S
    +Rule	Falk	1984	1985	-	Apr	lastSun	0:00	0	-
    +Rule	Falk	1984	only	-	Sep	16	0:00	1:00	S
    +Rule	Falk	1985	2000	-	Sep	Sun>=9	0:00	1:00	S
    +Rule	Falk	1986	2000	-	Apr	Sun>=16	0:00	0	-
    +Rule	Falk	2001	2010	-	Apr	Sun>=15	2:00	0	-
    +Rule	Falk	2001	2010	-	Sep	Sun>=1	2:00	1:00	S
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Atlantic/Stanley	-3:51:24 -	LMT	1890
    +			-3:51:24 -	SMT	1912 Mar 12  # Stanley Mean Time
    +			-4:00	Falk	FK%sT	1983 May     # Falkland Is Time
    +			-3:00	Falk	FK%sT	1985 Sep 15
    +			-4:00	Falk	FK%sT	2010 Sep 5 02:00
    +			-3:00	-	FKST
    +
    +# French Guiana
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Cayenne	-3:29:20 -	LMT	1911 Jul
    +			-4:00	-	GFT	1967 Oct # French Guiana Time
    +			-3:00	-	GFT
    +
    +# Guyana
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Guyana	-3:52:40 -	LMT	1915 Mar	# Georgetown
    +			-3:45	-	GBGT	1966 May 26 # Br Guiana Time
    +			-3:45	-	GYT	1975 Jul 31 # Guyana Time
    +			-3:00	-	GYT	1991
    +# IATA SSIM (1996-06) says -4:00.  Assume a 1991 switch.
    +			-4:00	-	GYT
    +
    +# Paraguay
    +# From Paul Eggert (2006-03-22):
    +# Shanks & Pottenger say that spring transitions are from 01:00 -> 02:00,
    +# and autumn transitions are from 00:00 -> 23:00.  Go with pre-1999
    +# editions of Shanks, and with the IATA, who say transitions occur at 00:00.
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Para	1975	1988	-	Oct	 1	0:00	1:00	S
    +Rule	Para	1975	1978	-	Mar	 1	0:00	0	-
    +Rule	Para	1979	1991	-	Apr	 1	0:00	0	-
    +Rule	Para	1989	only	-	Oct	22	0:00	1:00	S
    +Rule	Para	1990	only	-	Oct	 1	0:00	1:00	S
    +Rule	Para	1991	only	-	Oct	 6	0:00	1:00	S
    +Rule	Para	1992	only	-	Mar	 1	0:00	0	-
    +Rule	Para	1992	only	-	Oct	 5	0:00	1:00	S
    +Rule	Para	1993	only	-	Mar	31	0:00	0	-
    +Rule	Para	1993	1995	-	Oct	 1	0:00	1:00	S
    +Rule	Para	1994	1995	-	Feb	lastSun	0:00	0	-
    +Rule	Para	1996	only	-	Mar	 1	0:00	0	-
    +# IATA SSIM (2000-02) says 1999-10-10; ignore this for now.
    +# From Steffen Thorsen (2000-10-02):
    +# I have three independent reports that Paraguay changed to DST this Sunday
    +# (10-01).
    +#
    +# Translated by Gwillim Law (2001-02-27) from
    +# 
    +# Noticias, a daily paper in Asuncion, Paraguay (2000-10-01)
    +# :
    +# Starting at 0:00 today, the clock will be set forward 60 minutes, in
    +# fulfillment of Decree No. 7,273 of the Executive Power....  The time change
    +# system has been operating for several years.  Formerly there was a separate
    +# decree each year; the new law has the same effect, but permanently.  Every
    +# year, the time will change on the first Sunday of October; likewise, the
    +# clock will be set back on the first Sunday of March.
    +#
    +Rule	Para	1996	2001	-	Oct	Sun>=1	0:00	1:00	S
    +# IATA SSIM (1997-09) says Mar 1; go with Shanks & Pottenger.
    +Rule	Para	1997	only	-	Feb	lastSun	0:00	0	-
    +# Shanks & Pottenger say 1999-02-28; IATA SSIM (1999-02) says 1999-02-27, but
    +# (1999-09) reports no date; go with above sources and Gerd Knops (2001-02-27).
    +Rule	Para	1998	2001	-	Mar	Sun>=1	0:00	0	-
    +# From Rives McDow (2002-02-28):
    +# A decree was issued in Paraguay (no. 16350) on 2002-02-26 that changed the
    +# dst method to be from the first Sunday in September to the first Sunday in
    +# April.
    +Rule	Para	2002	2004	-	Apr	Sun>=1	0:00	0	-
    +Rule	Para	2002	2003	-	Sep	Sun>=1	0:00	1:00	S
    +#
    +# From Jesper Norgaard Welen (2005-01-02):
    +# There are several sources that claim that Paraguay made
    +# a timezone rule change in autumn 2004.
    +# From Steffen Thorsen (2005-01-05):
    +# Decree 1,867 (2004-03-05)
    +# From Carlos Raul Perasso via Jesper Norgaard Welen (2006-10-13)
    +# 
    +Rule	Para	2004	2009	-	Oct	Sun>=15	0:00	1:00	S
    +Rule	Para	2005	2009	-	Mar	Sun>=8	0:00	0	-
    +# From Carlos Raul Perasso (2010-02-18):
    +# By decree number 3958 issued yesterday (
    +# 
    +# http://www.presidencia.gov.py/v1/wp-content/uploads/2010/02/decreto3958.pdf
    +# 
    +# )
    +# Paraguay changes its DST schedule, postponing the March rule to April and
    +# modifying the October date. The decree reads:
    +# ...
    +# Art. 1. It is hereby established that from the second Sunday of the month of
    +# April of this year (2010), the official time is to be set back 60 minutes,
    +# and that on the first Sunday of the month of October, it is to be set
    +# forward 60 minutes, in all the territory of the Paraguayan Republic.
    +# ...
    +Rule	Para	2010	max	-	Oct	Sun>=1	0:00	1:00	S
    +Rule	Para	2010	max	-	Apr	Sun>=8	0:00	0	-
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Asuncion	-3:50:40 -	LMT	1890
    +			-3:50:40 -	AMT	1931 Oct 10 # Asuncion Mean Time
    +			-4:00	-	PYT	1972 Oct # Paraguay Time
    +			-3:00	-	PYT	1974 Apr
    +			-4:00	Para	PY%sT
    +
    +# Peru
    +#
    +# 
    +# From Evelyn C. Leeper via Mark Brader (2003-10-26):
    +# When we were in Peru in 1985-1986, they apparently switched over
    +# sometime between December 29 and January 3 while we were on the Amazon.
    +#
    +# From Paul Eggert (2006-03-22):
    +# Shanks & Pottenger don't have this transition.  Assume 1986 was like 1987.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	Peru	1938	only	-	Jan	 1	0:00	1:00	S
    +Rule	Peru	1938	only	-	Apr	 1	0:00	0	-
    +Rule	Peru	1938	1939	-	Sep	lastSun	0:00	1:00	S
    +Rule	Peru	1939	1940	-	Mar	Sun>=24	0:00	0	-
    +Rule	Peru	1986	1987	-	Jan	 1	0:00	1:00	S
    +Rule	Peru	1986	1987	-	Apr	 1	0:00	0	-
    +Rule	Peru	1990	only	-	Jan	 1	0:00	1:00	S
    +Rule	Peru	1990	only	-	Apr	 1	0:00	0	-
    +# IATA is ambiguous for 1993/1995; go with Shanks & Pottenger.
    +Rule	Peru	1994	only	-	Jan	 1	0:00	1:00	S
    +Rule	Peru	1994	only	-	Apr	 1	0:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Lima	-5:08:12 -	LMT	1890
    +			-5:08:36 -	LMT	1908 Jul 28 # Lima Mean Time?
    +			-5:00	Peru	PE%sT	# Peru Time
    +
    +# South Georgia
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone Atlantic/South_Georgia -2:26:08 -	LMT	1890		# Grytviken
    +			-2:00	-	GST	# South Georgia Time
    +
    +# South Sandwich Is
    +# uninhabited; scientific personnel have wintered
    +
    +# Suriname
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Paramaribo	-3:40:40 -	LMT	1911
    +			-3:40:52 -	PMT	1935     # Paramaribo Mean Time
    +			-3:40:36 -	PMT	1945 Oct # The capital moved?
    +			-3:30	-	NEGT	1975 Nov 20 # Dutch Guiana Time
    +			-3:30	-	SRT	1984 Oct # Suriname Time
    +			-3:00	-	SRT
    +
    +# Trinidad and Tobago
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Port_of_Spain -4:06:04 -	LMT	1912 Mar 2
    +			-4:00	-	AST
    +
    +# Uruguay
    +# From Paul Eggert (1993-11-18):
    +# Uruguay wins the prize for the strangest peacetime manipulation of the rules.
    +# From Shanks & Pottenger:
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +# Whitman gives 1923 Oct 1; go with Shanks & Pottenger.
    +Rule	Uruguay	1923	only	-	Oct	 2	 0:00	0:30	HS
    +Rule	Uruguay	1924	1926	-	Apr	 1	 0:00	0	-
    +Rule	Uruguay	1924	1925	-	Oct	 1	 0:00	0:30	HS
    +Rule	Uruguay	1933	1935	-	Oct	lastSun	 0:00	0:30	HS
    +# Shanks & Pottenger give 1935 Apr 1 0:00 & 1936 Mar 30 0:00; go with Whitman.
    +Rule	Uruguay	1934	1936	-	Mar	Sat>=25	23:30s	0	-
    +Rule	Uruguay	1936	only	-	Nov	 1	 0:00	0:30	HS
    +Rule	Uruguay	1937	1941	-	Mar	lastSun	 0:00	0	-
    +# Whitman gives 1937 Oct 3; go with Shanks & Pottenger.
    +Rule	Uruguay	1937	1940	-	Oct	lastSun	 0:00	0:30	HS
    +# Whitman gives 1941 Oct 24 - 1942 Mar 27, 1942 Dec 14 - 1943 Apr 13,
    +# and 1943 Apr 13 ``to present time''; go with Shanks & Pottenger.
    +Rule	Uruguay	1941	only	-	Aug	 1	 0:00	0:30	HS
    +Rule	Uruguay	1942	only	-	Jan	 1	 0:00	0	-
    +Rule	Uruguay	1942	only	-	Dec	14	 0:00	1:00	S
    +Rule	Uruguay	1943	only	-	Mar	14	 0:00	0	-
    +Rule	Uruguay	1959	only	-	May	24	 0:00	1:00	S
    +Rule	Uruguay	1959	only	-	Nov	15	 0:00	0	-
    +Rule	Uruguay	1960	only	-	Jan	17	 0:00	1:00	S
    +Rule	Uruguay	1960	only	-	Mar	 6	 0:00	0	-
    +Rule	Uruguay	1965	1967	-	Apr	Sun>=1	 0:00	1:00	S
    +Rule	Uruguay	1965	only	-	Sep	26	 0:00	0	-
    +Rule	Uruguay	1966	1967	-	Oct	31	 0:00	0	-
    +Rule	Uruguay	1968	1970	-	May	27	 0:00	0:30	HS
    +Rule	Uruguay	1968	1970	-	Dec	 2	 0:00	0	-
    +Rule	Uruguay	1972	only	-	Apr	24	 0:00	1:00	S
    +Rule	Uruguay	1972	only	-	Aug	15	 0:00	0	-
    +Rule	Uruguay	1974	only	-	Mar	10	 0:00	0:30	HS
    +Rule	Uruguay	1974	only	-	Dec	22	 0:00	1:00	S
    +Rule	Uruguay	1976	only	-	Oct	 1	 0:00	0	-
    +Rule	Uruguay	1977	only	-	Dec	 4	 0:00	1:00	S
    +Rule	Uruguay	1978	only	-	Apr	 1	 0:00	0	-
    +Rule	Uruguay	1979	only	-	Oct	 1	 0:00	1:00	S
    +Rule	Uruguay	1980	only	-	May	 1	 0:00	0	-
    +Rule	Uruguay	1987	only	-	Dec	14	 0:00	1:00	S
    +Rule	Uruguay	1988	only	-	Mar	14	 0:00	0	-
    +Rule	Uruguay	1988	only	-	Dec	11	 0:00	1:00	S
    +Rule	Uruguay	1989	only	-	Mar	12	 0:00	0	-
    +Rule	Uruguay	1989	only	-	Oct	29	 0:00	1:00	S
    +# Shanks & Pottenger say no DST was observed in 1990/1 and 1991/2,
    +# and that 1992/3's DST was from 10-25 to 03-01.  Go with IATA.
    +Rule	Uruguay	1990	1992	-	Mar	Sun>=1	 0:00	0	-
    +Rule	Uruguay	1990	1991	-	Oct	Sun>=21	 0:00	1:00	S
    +Rule	Uruguay	1992	only	-	Oct	18	 0:00	1:00	S
    +Rule	Uruguay	1993	only	-	Feb	28	 0:00	0	-
    +# From Eduardo Cota (2004-09-20):
    +# The uruguayan government has decreed a change in the local time....
    +# http://www.presidencia.gub.uy/decretos/2004091502.htm
    +Rule	Uruguay	2004	only	-	Sep	19	 0:00	1:00	S
    +# From Steffen Thorsen (2005-03-11):
    +# Uruguay's DST was scheduled to end on Sunday, 2005-03-13, but in order to
    +# save energy ... it was postponed two weeks....
    +# http://www.presidencia.gub.uy/_Web/noticias/2005/03/2005031005.htm
    +Rule	Uruguay	2005	only	-	Mar	27	 2:00	0	-
    +# From Eduardo Cota (2005-09-27):
    +# http://www.presidencia.gub.uy/_Web/decretos/2005/09/CM%20119_09%2009%202005_00001.PDF
    +# This means that from 2005-10-09 at 02:00 local time, until 2006-03-12 at
    +# 02:00 local time, official time in Uruguay will be at GMT -2.
    +Rule	Uruguay	2005	only	-	Oct	 9	 2:00	1:00	S
    +Rule	Uruguay	2006	only	-	Mar	12	 2:00	0	-
    +# From Jesper Norgaard Welen (2006-09-06):
    +# http://www.presidencia.gub.uy/_web/decretos/2006/09/CM%20210_08%2006%202006_00001.PDF
    +Rule	Uruguay	2006	max	-	Oct	Sun>=1	 2:00	1:00	S
    +Rule	Uruguay	2007	max	-	Mar	Sun>=8	 2:00	0	-
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone America/Montevideo	-3:44:44 -	LMT	1898 Jun 28
    +			-3:44:44 -	MMT	1920 May  1	# Montevideo MT
    +			-3:30	Uruguay	UY%sT	1942 Dec 14	# Uruguay Time
    +			-3:00	Uruguay	UY%sT
    +
    +# Venezuela
    +#
    +# From John Stainforth (2007-11-28):
    +# ... the change for Venezuela originally expected for 2007-12-31 has
    +# been brought forward to 2007-12-09.  The official announcement was
    +# published today in the "Gaceta Oficial de la Republica Bolivariana
    +# de Venezuela, numero 38.819" (official document for all laws or
    +# resolution publication)
    +# http://www.globovision.com/news.php?nid=72208
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	America/Caracas	-4:27:44 -	LMT	1890
    +			-4:27:40 -	CMT	1912 Feb 12 # Caracas Mean Time?
    +			-4:30	-	VET	1965	     # Venezuela Time
    +			-4:00	-	VET	2007 Dec  9 03:00
    +			-4:30	-	VET
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/systemv b/jdk/test/sun/util/calendar/zi/tzdata/systemv
    new file mode 100644
    index 00000000000..0b0a2665654
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/systemv
    @@ -0,0 +1,61 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +
    +# Old rules, should the need arise.
    +# No attempt is made to handle Newfoundland, since it cannot be expressed
    +# using the System V "TZ" scheme (half-hour offset), or anything outside
    +# North America (no support for non-standard DST start/end dates), nor
    +# the changes in the DST rules in the US after 1976 (which occurred after
    +# the old rules were written).
    +#
    +# If you need the old rules, uncomment ## lines.
    +# Compile this *without* leap second correction for true conformance.
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	SystemV	min	1973	-	Apr	lastSun	2:00	1:00	D
    +Rule	SystemV	min	1973	-	Oct	lastSun	2:00	0	S
    +Rule	SystemV	1974	only	-	Jan	6	2:00	1:00	D
    +Rule	SystemV	1974	only	-	Nov	lastSun	2:00	0	S
    +Rule	SystemV	1975	only	-	Feb	23	2:00	1:00	D
    +Rule	SystemV	1975	only	-	Oct	lastSun	2:00	0	S
    +Rule	SystemV	1976	max	-	Apr	lastSun	2:00	1:00	D
    +Rule	SystemV	1976	max	-	Oct	lastSun	2:00	0	S
    +
    +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
    +## Zone	SystemV/AST4ADT	-4:00	SystemV		A%sT
    +## Zone	SystemV/EST5EDT	-5:00	SystemV		E%sT
    +## Zone	SystemV/CST6CDT	-6:00	SystemV		C%sT
    +## Zone	SystemV/MST7MDT	-7:00	SystemV		M%sT
    +## Zone	SystemV/PST8PDT	-8:00	SystemV		P%sT
    +## Zone	SystemV/YST9YDT	-9:00	SystemV		Y%sT
    +## Zone	SystemV/AST4	-4:00	-		AST
    +## Zone	SystemV/EST5	-5:00	-		EST
    +## Zone	SystemV/CST6	-6:00	-		CST
    +## Zone	SystemV/MST7	-7:00	-		MST
    +## Zone	SystemV/PST8	-8:00	-		PST
    +## Zone	SystemV/YST9	-9:00	-		YST
    +## Zone	SystemV/HST10	-10:00	-		HST
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata/zone.tab b/jdk/test/sun/util/calendar/zi/tzdata/zone.tab
    new file mode 100644
    index 00000000000..ef380cd19fb
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata/zone.tab
    @@ -0,0 +1,464 @@
    +#
    +# 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#  
    +# 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 file is in the public domain, so clarified as of
    +# 2009-05-17 by Arthur David Olson.
    +#
    +# TZ zone descriptions
    +#
    +# From Paul Eggert (1996-08-05):
    +#
    +# This file contains a table with the following columns:
    +# 1.  ISO 3166 2-character country code.  See the file `iso3166.tab'.
    +# 2.  Latitude and longitude of the zone's principal location
    +#     in ISO 6709 sign-degrees-minutes-seconds format,
    +#     either +-DDMM+-DDDMM or +-DDMMSS+-DDDMMSS,
    +#     first latitude (+ is north), then longitude (+ is east).
    +# 3.  Zone name used in value of TZ environment variable.
    +# 4.  Comments; present if and only if the country has multiple rows.
    +#
    +# Columns are separated by a single tab.
    +# The table is sorted first by country, then an order within the country that
    +# (1) makes some geographical sense, and
    +# (2) puts the most populous zones first, where that does not contradict (1).
    +#
    +# Lines beginning with `#' are comments.
    +#
    +#country-
    +#code	coordinates	TZ			comments
    +AD	+4230+00131	Europe/Andorra
    +AE	+2518+05518	Asia/Dubai
    +AF	+3431+06912	Asia/Kabul
    +AG	+1703-06148	America/Antigua
    +AI	+1812-06304	America/Anguilla
    +AL	+4120+01950	Europe/Tirane
    +AM	+4011+04430	Asia/Yerevan
    +AO	-0848+01314	Africa/Luanda
    +AQ	-7750+16636	Antarctica/McMurdo	McMurdo Station, Ross Island
    +AQ	-9000+00000	Antarctica/South_Pole	Amundsen-Scott Station, South Pole
    +AQ	-6734-06808	Antarctica/Rothera	Rothera Station, Adelaide Island
    +AQ	-6448-06406	Antarctica/Palmer	Palmer Station, Anvers Island
    +AQ	-6736+06253	Antarctica/Mawson	Mawson Station, Holme Bay
    +AQ	-6835+07758	Antarctica/Davis	Davis Station, Vestfold Hills
    +AQ	-6617+11031	Antarctica/Casey	Casey Station, Bailey Peninsula
    +AQ	-7824+10654	Antarctica/Vostok	Vostok Station, Lake Vostok
    +AQ	-6640+14001	Antarctica/DumontDUrville	Dumont-d'Urville Station, Terre Adelie
    +AQ	-690022+0393524	Antarctica/Syowa	Syowa Station, E Ongul I
    +AQ	-5430+15857	Antarctica/Macquarie	Macquarie Island Station, Macquarie Island
    +AR	-3436-05827	America/Argentina/Buenos_Aires	Buenos Aires (BA, CF)
    +AR	-3124-06411	America/Argentina/Cordoba	most locations (CB, CC, CN, ER, FM, MN, SE, SF)
    +AR	-2447-06525	America/Argentina/Salta	(SA, LP, NQ, RN)
    +AR	-2411-06518	America/Argentina/Jujuy	Jujuy (JY)
    +AR	-2649-06513	America/Argentina/Tucuman	Tucuman (TM)
    +AR	-2828-06547	America/Argentina/Catamarca	Catamarca (CT), Chubut (CH)
    +AR	-2926-06651	America/Argentina/La_Rioja	La Rioja (LR)
    +AR	-3132-06831	America/Argentina/San_Juan	San Juan (SJ)
    +AR	-3253-06849	America/Argentina/Mendoza	Mendoza (MZ)
    +AR	-3319-06621	America/Argentina/San_Luis	San Luis (SL)
    +AR	-5138-06913	America/Argentina/Rio_Gallegos	Santa Cruz (SC)
    +AR	-5448-06818	America/Argentina/Ushuaia	Tierra del Fuego (TF)
    +AS	-1416-17042	Pacific/Pago_Pago
    +AT	+4813+01620	Europe/Vienna
    +AU	-3133+15905	Australia/Lord_Howe	Lord Howe Island
    +AU	-4253+14719	Australia/Hobart	Tasmania - most locations
    +AU	-3956+14352	Australia/Currie	Tasmania - King Island
    +AU	-3749+14458	Australia/Melbourne	Victoria
    +AU	-3352+15113	Australia/Sydney	New South Wales - most locations
    +AU	-3157+14127	Australia/Broken_Hill	New South Wales - Yancowinna
    +AU	-2728+15302	Australia/Brisbane	Queensland - most locations
    +AU	-2016+14900	Australia/Lindeman	Queensland - Holiday Islands
    +AU	-3455+13835	Australia/Adelaide	South Australia
    +AU	-1228+13050	Australia/Darwin	Northern Territory
    +AU	-3157+11551	Australia/Perth	Western Australia - most locations
    +AU	-3143+12852	Australia/Eucla	Western Australia - Eucla area
    +AW	+1230-06958	America/Aruba
    +AX	+6006+01957	Europe/Mariehamn
    +AZ	+4023+04951	Asia/Baku
    +BA	+4352+01825	Europe/Sarajevo
    +BB	+1306-05937	America/Barbados
    +BD	+2343+09025	Asia/Dhaka
    +BE	+5050+00420	Europe/Brussels
    +BF	+1222-00131	Africa/Ouagadougou
    +BG	+4241+02319	Europe/Sofia
    +BH	+2623+05035	Asia/Bahrain
    +BI	-0323+02922	Africa/Bujumbura
    +BJ	+0629+00237	Africa/Porto-Novo
    +BL	+1753-06251	America/St_Barthelemy
    +BM	+3217-06446	Atlantic/Bermuda
    +BN	+0456+11455	Asia/Brunei
    +BO	-1630-06809	America/La_Paz
    +BQ	+120903-0681636	America/Kralendijk
    +BR	-0351-03225	America/Noronha	Atlantic islands
    +BR	-0127-04829	America/Belem	Amapa, E Para
    +BR	-0343-03830	America/Fortaleza	NE Brazil (MA, PI, CE, RN, PB)
    +BR	-0803-03454	America/Recife	Pernambuco
    +BR	-0712-04812	America/Araguaina	Tocantins
    +BR	-0940-03543	America/Maceio	Alagoas, Sergipe
    +BR	-1259-03831	America/Bahia	Bahia
    +BR	-2332-04637	America/Sao_Paulo	S & SE Brazil (GO, DF, MG, ES, RJ, SP, PR, SC, RS)
    +BR	-2027-05437	America/Campo_Grande	Mato Grosso do Sul
    +BR	-1535-05605	America/Cuiaba	Mato Grosso
    +BR	-0226-05452	America/Santarem	W Para
    +BR	-0846-06354	America/Porto_Velho	Rondonia
    +BR	+0249-06040	America/Boa_Vista	Roraima
    +BR	-0308-06001	America/Manaus	E Amazonas
    +BR	-0640-06952	America/Eirunepe	W Amazonas
    +BR	-0958-06748	America/Rio_Branco	Acre
    +BS	+2505-07721	America/Nassau
    +BT	+2728+08939	Asia/Thimphu
    +BW	-2439+02555	Africa/Gaborone
    +BY	+5354+02734	Europe/Minsk
    +BZ	+1730-08812	America/Belize
    +CA	+4734-05243	America/St_Johns	Newfoundland Time, including SE Labrador
    +CA	+4439-06336	America/Halifax	Atlantic Time - Nova Scotia (most places), PEI
    +CA	+4612-05957	America/Glace_Bay	Atlantic Time - Nova Scotia - places that did not observe DST 1966-1971
    +CA	+4606-06447	America/Moncton	Atlantic Time - New Brunswick
    +CA	+5320-06025	America/Goose_Bay	Atlantic Time - Labrador - most locations
    +CA	+5125-05707	America/Blanc-Sablon	Atlantic Standard Time - Quebec - Lower North Shore
    +CA	+4531-07334	America/Montreal	Eastern Time - Quebec - most locations
    +CA	+4339-07923	America/Toronto	Eastern Time - Ontario - most locations
    +CA	+4901-08816	America/Nipigon	Eastern Time - Ontario & Quebec - places that did not observe DST 1967-1973
    +CA	+4823-08915	America/Thunder_Bay	Eastern Time - Thunder Bay, Ontario
    +CA	+6344-06828	America/Iqaluit	Eastern Time - east Nunavut - most locations
    +CA	+6608-06544	America/Pangnirtung	Eastern Time - Pangnirtung, Nunavut
    +CA	+744144-0944945	America/Resolute	Central Standard Time - Resolute, Nunavut
    +CA	+484531-0913718	America/Atikokan	Eastern Standard Time - Atikokan, Ontario and Southampton I, Nunavut
    +CA	+624900-0920459	America/Rankin_Inlet	Central Time - central Nunavut
    +CA	+4953-09709	America/Winnipeg	Central Time - Manitoba & west Ontario
    +CA	+4843-09434	America/Rainy_River	Central Time - Rainy River & Fort Frances, Ontario
    +CA	+5024-10439	America/Regina	Central Standard Time - Saskatchewan - most locations
    +CA	+5017-10750	America/Swift_Current	Central Standard Time - Saskatchewan - midwest
    +CA	+5333-11328	America/Edmonton	Mountain Time - Alberta, east British Columbia & west Saskatchewan
    +CA	+690650-1050310	America/Cambridge_Bay	Mountain Time - west Nunavut
    +CA	+6227-11421	America/Yellowknife	Mountain Time - central Northwest Territories
    +CA	+682059-1334300	America/Inuvik	Mountain Time - west Northwest Territories
    +CA	+4906-11631	America/Creston	Mountain Standard Time - Creston, British Columbia
    +CA	+5946-12014	America/Dawson_Creek	Mountain Standard Time - Dawson Creek & Fort Saint John, British Columbia
    +CA	+4916-12307	America/Vancouver	Pacific Time - west British Columbia
    +CA	+6043-13503	America/Whitehorse	Pacific Time - south Yukon
    +CA	+6404-13925	America/Dawson	Pacific Time - north Yukon
    +CC	-1210+09655	Indian/Cocos
    +CD	-0418+01518	Africa/Kinshasa	west Dem. Rep. of Congo
    +CD	-1140+02728	Africa/Lubumbashi	east Dem. Rep. of Congo
    +CF	+0422+01835	Africa/Bangui
    +CG	-0416+01517	Africa/Brazzaville
    +CH	+4723+00832	Europe/Zurich
    +CI	+0519-00402	Africa/Abidjan
    +CK	-2114-15946	Pacific/Rarotonga
    +CL	-3327-07040	America/Santiago	most locations
    +CL	-2709-10926	Pacific/Easter	Easter Island & Sala y Gomez
    +CM	+0403+00942	Africa/Douala
    +CN	+3114+12128	Asia/Shanghai	east China - Beijing, Guangdong, Shanghai, etc.
    +CN	+4545+12641	Asia/Harbin	Heilongjiang (except Mohe), Jilin
    +CN	+2934+10635	Asia/Chongqing	central China - Sichuan, Yunnan, Guangxi, Shaanxi, Guizhou, etc.
    +CN	+4348+08735	Asia/Urumqi	most of Tibet & Xinjiang
    +CN	+3929+07559	Asia/Kashgar	west Tibet & Xinjiang
    +CO	+0436-07405	America/Bogota
    +CR	+0956-08405	America/Costa_Rica
    +CU	+2308-08222	America/Havana
    +CV	+1455-02331	Atlantic/Cape_Verde
    +CW	+1211-06900	America/Curacao
    +CX	-1025+10543	Indian/Christmas
    +CY	+3510+03322	Asia/Nicosia
    +CZ	+5005+01426	Europe/Prague
    +DE	+5230+01322	Europe/Berlin
    +DJ	+1136+04309	Africa/Djibouti
    +DK	+5540+01235	Europe/Copenhagen
    +DM	+1518-06124	America/Dominica
    +DO	+1828-06954	America/Santo_Domingo
    +DZ	+3647+00303	Africa/Algiers
    +EC	-0210-07950	America/Guayaquil	mainland
    +EC	-0054-08936	Pacific/Galapagos	Galapagos Islands
    +EE	+5925+02445	Europe/Tallinn
    +EG	+3003+03115	Africa/Cairo
    +EH	+2709-01312	Africa/El_Aaiun
    +ER	+1520+03853	Africa/Asmara
    +ES	+4024-00341	Europe/Madrid	mainland
    +ES	+3553-00519	Africa/Ceuta	Ceuta & Melilla
    +ES	+2806-01524	Atlantic/Canary	Canary Islands
    +ET	+0902+03842	Africa/Addis_Ababa
    +FI	+6010+02458	Europe/Helsinki
    +FJ	-1808+17825	Pacific/Fiji
    +FK	-5142-05751	Atlantic/Stanley
    +FM	+0725+15147	Pacific/Chuuk	Chuuk (Truk) and Yap
    +FM	+0658+15813	Pacific/Pohnpei	Pohnpei (Ponape)
    +FM	+0519+16259	Pacific/Kosrae	Kosrae
    +FO	+6201-00646	Atlantic/Faroe
    +FR	+4852+00220	Europe/Paris
    +GA	+0023+00927	Africa/Libreville
    +GB	+513030-0000731	Europe/London
    +GD	+1203-06145	America/Grenada
    +GE	+4143+04449	Asia/Tbilisi
    +GF	+0456-05220	America/Cayenne
    +GG	+4927-00232	Europe/Guernsey
    +GH	+0533-00013	Africa/Accra
    +GI	+3608-00521	Europe/Gibraltar
    +GL	+6411-05144	America/Godthab	most locations
    +GL	+7646-01840	America/Danmarkshavn	east coast, north of Scoresbysund
    +GL	+7029-02158	America/Scoresbysund	Scoresbysund / Ittoqqortoormiit
    +GL	+7634-06847	America/Thule	Thule / Pituffik
    +GM	+1328-01639	Africa/Banjul
    +GN	+0931-01343	Africa/Conakry
    +GP	+1614-06132	America/Guadeloupe
    +GQ	+0345+00847	Africa/Malabo
    +GR	+3758+02343	Europe/Athens
    +GS	-5416-03632	Atlantic/South_Georgia
    +GT	+1438-09031	America/Guatemala
    +GU	+1328+14445	Pacific/Guam
    +GW	+1151-01535	Africa/Bissau
    +GY	+0648-05810	America/Guyana
    +HK	+2217+11409	Asia/Hong_Kong
    +HN	+1406-08713	America/Tegucigalpa
    +HR	+4548+01558	Europe/Zagreb
    +HT	+1832-07220	America/Port-au-Prince
    +HU	+4730+01905	Europe/Budapest
    +ID	-0610+10648	Asia/Jakarta	Java & Sumatra
    +ID	-0002+10920	Asia/Pontianak	west & central Borneo
    +ID	-0507+11924	Asia/Makassar	east & south Borneo, Sulawesi (Celebes), Bali, Nusa Tengarra, west Timor
    +ID	-0232+14042	Asia/Jayapura	west New Guinea (Irian Jaya) & Malukus (Moluccas)
    +IE	+5320-00615	Europe/Dublin
    +IL	+3146+03514	Asia/Jerusalem
    +IM	+5409-00428	Europe/Isle_of_Man
    +IN	+2232+08822	Asia/Kolkata
    +IO	-0720+07225	Indian/Chagos
    +IQ	+3321+04425	Asia/Baghdad
    +IR	+3540+05126	Asia/Tehran
    +IS	+6409-02151	Atlantic/Reykjavik
    +IT	+4154+01229	Europe/Rome
    +JE	+4912-00207	Europe/Jersey
    +JM	+1800-07648	America/Jamaica
    +JO	+3157+03556	Asia/Amman
    +JP	+353916+1394441	Asia/Tokyo
    +KE	-0117+03649	Africa/Nairobi
    +KG	+4254+07436	Asia/Bishkek
    +KH	+1133+10455	Asia/Phnom_Penh
    +KI	+0125+17300	Pacific/Tarawa	Gilbert Islands
    +KI	-0308-17105	Pacific/Enderbury	Phoenix Islands
    +KI	+0152-15720	Pacific/Kiritimati	Line Islands
    +KM	-1141+04316	Indian/Comoro
    +KN	+1718-06243	America/St_Kitts
    +KP	+3901+12545	Asia/Pyongyang
    +KR	+3733+12658	Asia/Seoul
    +KW	+2920+04759	Asia/Kuwait
    +KY	+1918-08123	America/Cayman
    +KZ	+4315+07657	Asia/Almaty	most locations
    +KZ	+4448+06528	Asia/Qyzylorda	Qyzylorda (Kyzylorda, Kzyl-Orda)
    +KZ	+5017+05710	Asia/Aqtobe	Aqtobe (Aktobe)
    +KZ	+4431+05016	Asia/Aqtau	Atyrau (Atirau, Gur'yev), Mangghystau (Mankistau)
    +KZ	+5113+05121	Asia/Oral	West Kazakhstan
    +LA	+1758+10236	Asia/Vientiane
    +LB	+3353+03530	Asia/Beirut
    +LC	+1401-06100	America/St_Lucia
    +LI	+4709+00931	Europe/Vaduz
    +LK	+0656+07951	Asia/Colombo
    +LR	+0618-01047	Africa/Monrovia
    +LS	-2928+02730	Africa/Maseru
    +LT	+5441+02519	Europe/Vilnius
    +LU	+4936+00609	Europe/Luxembourg
    +LV	+5657+02406	Europe/Riga
    +LY	+3254+01311	Africa/Tripoli
    +MA	+3339-00735	Africa/Casablanca
    +MC	+4342+00723	Europe/Monaco
    +MD	+4700+02850	Europe/Chisinau
    +ME	+4226+01916	Europe/Podgorica
    +MF	+1804-06305	America/Marigot
    +MG	-1855+04731	Indian/Antananarivo
    +MH	+0709+17112	Pacific/Majuro	most locations
    +MH	+0905+16720	Pacific/Kwajalein	Kwajalein
    +MK	+4159+02126	Europe/Skopje
    +ML	+1239-00800	Africa/Bamako
    +MM	+1647+09610	Asia/Rangoon
    +MN	+4755+10653	Asia/Ulaanbaatar	most locations
    +MN	+4801+09139	Asia/Hovd	Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan
    +MN	+4804+11430	Asia/Choibalsan	Dornod, Sukhbaatar
    +MO	+2214+11335	Asia/Macau
    +MP	+1512+14545	Pacific/Saipan
    +MQ	+1436-06105	America/Martinique
    +MR	+1806-01557	Africa/Nouakchott
    +MS	+1643-06213	America/Montserrat
    +MT	+3554+01431	Europe/Malta
    +MU	-2010+05730	Indian/Mauritius
    +MV	+0410+07330	Indian/Maldives
    +MW	-1547+03500	Africa/Blantyre
    +MX	+1924-09909	America/Mexico_City	Central Time - most locations
    +MX	+2105-08646	America/Cancun	Central Time - Quintana Roo
    +MX	+2058-08937	America/Merida	Central Time - Campeche, Yucatan
    +MX	+2540-10019	America/Monterrey	Mexican Central Time - Coahuila, Durango, Nuevo Leon, Tamaulipas away from US border
    +MX	+2550-09730	America/Matamoros	US Central Time - Coahuila, Durango, Nuevo Leon, Tamaulipas near US border
    +MX	+2313-10625	America/Mazatlan	Mountain Time - S Baja, Nayarit, Sinaloa
    +MX	+2838-10605	America/Chihuahua	Mexican Mountain Time - Chihuahua away from US border
    +MX	+2934-10425	America/Ojinaga	US Mountain Time - Chihuahua near US border
    +MX	+2904-11058	America/Hermosillo	Mountain Standard Time - Sonora
    +MX	+3232-11701	America/Tijuana	US Pacific Time - Baja California near US border
    +MX	+3018-11452	America/Santa_Isabel	Mexican Pacific Time - Baja California away from US border
    +MX	+2048-10515	America/Bahia_Banderas	Mexican Central Time - Bahia de Banderas
    +MY	+0310+10142	Asia/Kuala_Lumpur	peninsular Malaysia
    +MY	+0133+11020	Asia/Kuching	Sabah & Sarawak
    +MZ	-2558+03235	Africa/Maputo
    +NA	-2234+01706	Africa/Windhoek
    +NC	-2216+16627	Pacific/Noumea
    +NE	+1331+00207	Africa/Niamey
    +NF	-2903+16758	Pacific/Norfolk
    +NG	+0627+00324	Africa/Lagos
    +NI	+1209-08617	America/Managua
    +NL	+5222+00454	Europe/Amsterdam
    +NO	+5955+01045	Europe/Oslo
    +NP	+2743+08519	Asia/Kathmandu
    +NR	-0031+16655	Pacific/Nauru
    +NU	-1901-16955	Pacific/Niue
    +NZ	-3652+17446	Pacific/Auckland	most locations
    +NZ	-4357-17633	Pacific/Chatham	Chatham Islands
    +OM	+2336+05835	Asia/Muscat
    +PA	+0858-07932	America/Panama
    +PE	-1203-07703	America/Lima
    +PF	-1732-14934	Pacific/Tahiti	Society Islands
    +PF	-0900-13930	Pacific/Marquesas	Marquesas Islands
    +PF	-2308-13457	Pacific/Gambier	Gambier Islands
    +PG	-0930+14710	Pacific/Port_Moresby
    +PH	+1435+12100	Asia/Manila
    +PK	+2452+06703	Asia/Karachi
    +PL	+5215+02100	Europe/Warsaw
    +PM	+4703-05620	America/Miquelon
    +PN	-2504-13005	Pacific/Pitcairn
    +PR	+182806-0660622	America/Puerto_Rico
    +PS	+3130+03428	Asia/Gaza	Gaza Strip
    +PS	+313200+0350542	Asia/Hebron	West Bank
    +PT	+3843-00908	Europe/Lisbon	mainland
    +PT	+3238-01654	Atlantic/Madeira	Madeira Islands
    +PT	+3744-02540	Atlantic/Azores	Azores
    +PW	+0720+13429	Pacific/Palau
    +PY	-2516-05740	America/Asuncion
    +QA	+2517+05132	Asia/Qatar
    +RE	-2052+05528	Indian/Reunion
    +RO	+4426+02606	Europe/Bucharest
    +RS	+4450+02030	Europe/Belgrade
    +RU	+5443+02030	Europe/Kaliningrad	Moscow-01 - Kaliningrad
    +RU	+5545+03735	Europe/Moscow	Moscow+00 - west Russia
    +RU	+4844+04425	Europe/Volgograd	Moscow+00 - Caspian Sea
    +RU	+5312+05009	Europe/Samara	Moscow+00 - Samara, Udmurtia
    +RU	+5651+06036	Asia/Yekaterinburg	Moscow+02 - Urals
    +RU	+5500+07324	Asia/Omsk	Moscow+03 - west Siberia
    +RU	+5502+08255	Asia/Novosibirsk	Moscow+03 - Novosibirsk
    +RU	+5345+08707	Asia/Novokuznetsk	Moscow+03 - Novokuznetsk
    +RU	+5601+09250	Asia/Krasnoyarsk	Moscow+04 - Yenisei River
    +RU	+5216+10420	Asia/Irkutsk	Moscow+05 - Lake Baikal
    +RU	+6200+12940	Asia/Yakutsk	Moscow+06 - Lena River
    +RU	+4310+13156	Asia/Vladivostok	Moscow+07 - Amur River
    +RU	+4658+14242	Asia/Sakhalin	Moscow+07 - Sakhalin Island
    +RU	+5934+15048	Asia/Magadan	Moscow+08 - Magadan
    +RU	+5301+15839	Asia/Kamchatka	Moscow+08 - Kamchatka
    +RU	+6445+17729	Asia/Anadyr	Moscow+08 - Bering Sea
    +RW	-0157+03004	Africa/Kigali
    +SA	+2438+04643	Asia/Riyadh
    +SB	-0932+16012	Pacific/Guadalcanal
    +SC	-0440+05528	Indian/Mahe
    +SD	+1536+03232	Africa/Khartoum
    +SE	+5920+01803	Europe/Stockholm
    +SG	+0117+10351	Asia/Singapore
    +SH	-1555-00542	Atlantic/St_Helena
    +SI	+4603+01431	Europe/Ljubljana
    +SJ	+7800+01600	Arctic/Longyearbyen
    +SK	+4809+01707	Europe/Bratislava
    +SL	+0830-01315	Africa/Freetown
    +SM	+4355+01228	Europe/San_Marino
    +SN	+1440-01726	Africa/Dakar
    +SO	+0204+04522	Africa/Mogadishu
    +SR	+0550-05510	America/Paramaribo
    +SS	+0451+03136	Africa/Juba
    +ST	+0020+00644	Africa/Sao_Tome
    +SV	+1342-08912	America/El_Salvador
    +SX	+180305-0630250	America/Lower_Princes
    +SY	+3330+03618	Asia/Damascus
    +SZ	-2618+03106	Africa/Mbabane
    +TC	+2128-07108	America/Grand_Turk
    +TD	+1207+01503	Africa/Ndjamena
    +TF	-492110+0701303	Indian/Kerguelen
    +TG	+0608+00113	Africa/Lome
    +TH	+1345+10031	Asia/Bangkok
    +TJ	+3835+06848	Asia/Dushanbe
    +TK	-0922-17114	Pacific/Fakaofo
    +TL	-0833+12535	Asia/Dili
    +TM	+3757+05823	Asia/Ashgabat
    +TN	+3648+01011	Africa/Tunis
    +TO	-2110-17510	Pacific/Tongatapu
    +TR	+4101+02858	Europe/Istanbul
    +TT	+1039-06131	America/Port_of_Spain
    +TV	-0831+17913	Pacific/Funafuti
    +TW	+2503+12130	Asia/Taipei
    +TZ	-0648+03917	Africa/Dar_es_Salaam
    +UA	+5026+03031	Europe/Kiev	most locations
    +UA	+4837+02218	Europe/Uzhgorod	Ruthenia
    +UA	+4750+03510	Europe/Zaporozhye	Zaporozh'ye, E Lugansk / Zaporizhia, E Luhansk
    +UA	+4457+03406	Europe/Simferopol	central Crimea
    +UG	+0019+03225	Africa/Kampala
    +UM	+1645-16931	Pacific/Johnston	Johnston Atoll
    +UM	+2813-17722	Pacific/Midway	Midway Islands
    +UM	+1917+16637	Pacific/Wake	Wake Island
    +US	+404251-0740023	America/New_York	Eastern Time
    +US	+421953-0830245	America/Detroit	Eastern Time - Michigan - most locations
    +US	+381515-0854534	America/Kentucky/Louisville	Eastern Time - Kentucky - Louisville area
    +US	+364947-0845057	America/Kentucky/Monticello	Eastern Time - Kentucky - Wayne County
    +US	+394606-0860929	America/Indiana/Indianapolis	Eastern Time - Indiana - most locations
    +US	+384038-0873143	America/Indiana/Vincennes	Eastern Time - Indiana - Daviess, Dubois, Knox & Martin Counties
    +US	+410305-0863611	America/Indiana/Winamac	Eastern Time - Indiana - Pulaski County
    +US	+382232-0862041	America/Indiana/Marengo	Eastern Time - Indiana - Crawford County
    +US	+382931-0871643	America/Indiana/Petersburg	Eastern Time - Indiana - Pike County
    +US	+384452-0850402	America/Indiana/Vevay	Eastern Time - Indiana - Switzerland County
    +US	+415100-0873900	America/Chicago	Central Time
    +US	+375711-0864541	America/Indiana/Tell_City	Central Time - Indiana - Perry County
    +US	+411745-0863730	America/Indiana/Knox	Central Time - Indiana - Starke County
    +US	+450628-0873651	America/Menominee	Central Time - Michigan - Dickinson, Gogebic, Iron & Menominee Counties
    +US	+470659-1011757	America/North_Dakota/Center	Central Time - North Dakota - Oliver County
    +US	+465042-1012439	America/North_Dakota/New_Salem	Central Time - North Dakota - Morton County (except Mandan area)
    +US	+471551-1014640	America/North_Dakota/Beulah	Central Time - North Dakota - Mercer County
    +US	+394421-1045903	America/Denver	Mountain Time
    +US	+433649-1161209	America/Boise	Mountain Time - south Idaho & east Oregon
    +US	+364708-1084111	America/Shiprock	Mountain Time - Navajo
    +US	+332654-1120424	America/Phoenix	Mountain Standard Time - Arizona
    +US	+340308-1181434	America/Los_Angeles	Pacific Time
    +US	+611305-1495401	America/Anchorage	Alaska Time
    +US	+581807-1342511	America/Juneau	Alaska Time - Alaska panhandle
    +US	+571035-1351807	America/Sitka	Alaska Time - southeast Alaska panhandle
    +US	+593249-1394338	America/Yakutat	Alaska Time - Alaska panhandle neck
    +US	+643004-1652423	America/Nome	Alaska Time - west Alaska
    +US	+515248-1763929	America/Adak	Aleutian Islands
    +US	+550737-1313435	America/Metlakatla	Metlakatla Time - Annette Island
    +US	+211825-1575130	Pacific/Honolulu	Hawaii
    +UY	-3453-05611	America/Montevideo
    +UZ	+3940+06648	Asia/Samarkand	west Uzbekistan
    +UZ	+4120+06918	Asia/Tashkent	east Uzbekistan
    +VA	+415408+0122711	Europe/Vatican
    +VC	+1309-06114	America/St_Vincent
    +VE	+1030-06656	America/Caracas
    +VG	+1827-06437	America/Tortola
    +VI	+1821-06456	America/St_Thomas
    +VN	+1045+10640	Asia/Ho_Chi_Minh
    +VU	-1740+16825	Pacific/Efate
    +WF	-1318-17610	Pacific/Wallis
    +WS	-1350-17144	Pacific/Apia
    +YE	+1245+04512	Asia/Aden
    +YT	-1247+04514	Indian/Mayotte
    +ZA	-2615+02800	Africa/Johannesburg
    +ZM	-1525+02817	Africa/Lusaka
    +ZW	-1750+03103	Africa/Harare
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata_jdk/gmt b/jdk/test/sun/util/calendar/zi/tzdata_jdk/gmt
    new file mode 100644
    index 00000000000..0be31797d7f
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata_jdk/gmt
    @@ -0,0 +1,27 @@
    +#
    +# Copyright (c) 2000, 2005, 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#
    +# 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.
    +#
    +
    +# Zone	NAME		GMTOFF	RULES	FORMAT	[UNTIL]
    +Zone	GMT		0:00	-	GMT
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata_jdk/jdk11_backward b/jdk/test/sun/util/calendar/zi/tzdata_jdk/jdk11_backward
    new file mode 100644
    index 00000000000..4869516f8dc
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata_jdk/jdk11_backward
    @@ -0,0 +1,80 @@
    +#
    +# Copyright (c) 2000, 2006, 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#
    +# 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.
    +#
    +# JDK 1.1.x compatible time zone IDs
    +#
    +
    +Link Australia/Darwin ACT
    +Link Australia/Sydney AET
    +Link America/Argentina/Buenos_Aires AGT
    +Link Africa/Cairo ART
    +Link America/Anchorage AST
    +Link America/Sao_Paulo BET
    +Link Asia/Dhaka BST
    +Link Africa/Harare CAT
    +Link America/St_Johns CNT
    +Link America/Chicago CST
    +Link Asia/Shanghai CTT
    +Link Africa/Addis_Ababa EAT
    +Link Europe/Paris ECT
    +Link America/New_York EST
    +Link Pacific/Honolulu HST
    +Link America/Indianapolis IET
    +Link Asia/Calcutta IST
    +Link Asia/Tokyo JST
    +Link Pacific/Apia MIT
    +Link America/Denver MST
    +Link Asia/Yerevan NET
    +Link Pacific/Auckland NST
    +Link Asia/Karachi PLT
    +Link America/Phoenix PNT
    +Link America/Puerto_Rico PRT
    +Link America/Los_Angeles PST
    +Link Pacific/Guadalcanal SST
    +Link Asia/Saigon VST
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	SystemV	min	1973	-	Apr	lastSun	2:00	1:00	D
    +Rule	SystemV	min	1973	-	Oct	lastSun	2:00	0	S
    +Rule	SystemV	1974	only	-	Jan	6	2:00	1:00	D
    +Rule	SystemV	1974	only	-	Nov	lastSun	2:00	0	S
    +Rule	SystemV	1975	only	-	Feb	23	2:00	1:00	D
    +Rule	SystemV	1975	only	-	Oct	lastSun	2:00	0	S
    +Rule	SystemV	1976	max	-	Apr	lastSun	2:00	1:00	D
    +Rule	SystemV	1976	max	-	Oct	lastSun	2:00	0	S
    +
    +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
    +Zone	SystemV/AST4ADT	-4:00	SystemV		A%sT
    +Zone	SystemV/EST5EDT	-5:00	SystemV		E%sT
    +Zone	SystemV/CST6CDT	-6:00	SystemV		C%sT
    +Zone	SystemV/MST7MDT	-7:00	SystemV		M%sT
    +Zone	SystemV/PST8PDT	-8:00	SystemV		P%sT
    +Zone	SystemV/YST9YDT	-9:00	SystemV		Y%sT
    +Zone	SystemV/AST4	-4:00	-		AST
    +Zone	SystemV/EST5	-5:00	-		EST
    +Zone	SystemV/CST6	-6:00	-		CST
    +Zone	SystemV/MST7	-7:00	-		MST
    +Zone	SystemV/PST8	-8:00	-		PST
    +Zone	SystemV/YST9	-9:00	-		YST
    +Zone	SystemV/HST10	-10:00	-		HST
    diff --git a/jdk/test/sun/util/calendar/zi/tzdata_jdk/jdk11_full_backward b/jdk/test/sun/util/calendar/zi/tzdata_jdk/jdk11_full_backward
    new file mode 100644
    index 00000000000..321180aa100
    --- /dev/null
    +++ b/jdk/test/sun/util/calendar/zi/tzdata_jdk/jdk11_full_backward
    @@ -0,0 +1,93 @@
    +#
    +# Copyright (c) 2001, 2006, 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.  Oracle designates this
    +# particular file as subject to the "Classpath" exception as provided
    +# by Oracle in the LICENSE file that accompanied this code.
    +#
    +# 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.
    +#
    +# JDK 1.1.x compatible time zone IDs
    +#
    +
    +Link Australia/Darwin ACT
    +Link Australia/Sydney AET
    +Link America/Argentina/Buenos_Aires AGT
    +Link Africa/Cairo ART
    +Link America/Anchorage AST
    +Link America/Sao_Paulo BET
    +Link Asia/Dhaka BST
    +Link Africa/Harare CAT
    +Link America/St_Johns CNT
    +Link America/Chicago CST
    +Link Asia/Shanghai CTT
    +Link Africa/Addis_Ababa EAT
    +Link Europe/Paris ECT
    +Link America/New_York EST
    +Link Pacific/Honolulu HST
    +Link America/Indiana/Indianapolis IET
    +Link Asia/Calcutta IST
    +Link Asia/Tokyo JST
    +Link Pacific/Apia MIT
    +Link America/Denver MST
    +Link Asia/Yerevan NET
    +Link Pacific/Auckland NST
    +Link Asia/Karachi PLT
    +Link America/Phoenix PNT
    +Link America/Puerto_Rico PRT
    +Link America/Los_Angeles PST
    +Link Pacific/Guadalcanal SST
    +Link Asia/Saigon VST
    +
    +# The follwong link is required to generate JDK 1.2.x and 1.3.x
    +# compatible zones. In the Olson public source, MET is defined as
    +# GMT+1:00 with the C-Eur rules. In JDK, MET is defined as an alias
    +# of Asia/Tehran. This line must be removed if a full set of Olson
    +# zones is generated. Otherwise, MET appears twice in the
    +# ZoneInfoMappings.IDs table.
    +Link Asia/Tehran MET
    +
    +# Rule	NAME	FROM	TO	TYPE	IN	ON	AT	SAVE	LETTER/S
    +Rule	SystemV	min	1973	-	Apr	lastSun	2:00	1:00	D
    +Rule	SystemV	min	1973	-	Oct	lastSun	2:00	0	S
    +Rule	SystemV	1974	only	-	Jan	6	2:00	1:00	D
    +Rule	SystemV	1974	only	-	Nov	lastSun	2:00	0	S
    +Rule	SystemV	1975	only	-	Feb	23	2:00	1:00	D
    +Rule	SystemV	1975	only	-	Oct	lastSun	2:00	0	S
    +Rule	SystemV	1976	max	-	Apr	lastSun	2:00	1:00	D
    +Rule	SystemV	1976	max	-	Oct	lastSun	2:00	0	S
    +
    +# Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
    +Zone	SystemV/AST4ADT	-4:00	SystemV		A%sT
    +Zone	SystemV/EST5EDT	-5:00	SystemV		E%sT
    +Zone	SystemV/CST6CDT	-6:00	SystemV		C%sT
    +Zone	SystemV/MST7MDT	-7:00	SystemV		M%sT
    +Zone	SystemV/PST8PDT	-8:00	SystemV		P%sT
    +Zone	SystemV/YST9YDT	-9:00	SystemV		Y%sT
    +Zone	SystemV/AST4	-4:00	-		AST
    +Zone	SystemV/EST5	-5:00	-		EST
    +Zone	SystemV/CST6	-6:00	-		CST
    +Zone	SystemV/MST7	-7:00	-		MST
    +Zone	SystemV/PST8	-8:00	-		PST
    +Zone	SystemV/YST9	-9:00	-		YST
    +Zone	SystemV/HST10	-10:00	-		HST
    +
    +#
    +# For the UTC change in Mustang
    +#
    +Link GMT UTC
    
    From 7ca3c9dd848ea25f514f6debd3518f58cc6d4fae Mon Sep 17 00:00:00 2001
    From: Phil Race 
    Date: Tue, 12 Feb 2013 09:58:21 -0800
    Subject: [PATCH 23/39] 8007748: MacOSX build error : cast of type 'SEL' to
     'uintptr_t' (aka 'unsigned long') is deprecated; use sel_getName instead
    
    Reviewed-by: anthony
    ---
     jdk/src/macosx/native/jobjc/src/core/native/SEL.m | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/jdk/src/macosx/native/jobjc/src/core/native/SEL.m b/jdk/src/macosx/native/jobjc/src/core/native/SEL.m
    index 970a5d30bcf..ebbcf254082 100644
    --- a/jdk/src/macosx/native/jobjc/src/core/native/SEL.m
    +++ b/jdk/src/macosx/native/jobjc/src/core/native/SEL.m
    @@ -34,7 +34,7 @@ JNIEXPORT jlong JNICALL Java_com_apple_jobjc_SEL_getSelectorPtr
         const char *selNameAsChars = (*env)->GetStringUTFChars(env, selName, JNI_FALSE);
         const SEL sel = sel_registerName(selNameAsChars);
         (*env)->ReleaseStringUTFChars(env, selName, selNameAsChars);
    -    return ptr_to_jlong(sel);
    +    return ptr_to_jlong((void*)sel);
     }
     
     JNIEXPORT jstring JNICALL Java_com_apple_jobjc_SEL_getSelectorName
    
    From 4e7de85e4d6522f40ef392874e9e79173df3f457 Mon Sep 17 00:00:00 2001
    From: Zhengyu Gu 
    Date: Tue, 12 Feb 2013 14:47:36 -0500
    Subject: [PATCH 24/39] 8006691: Remove jvm_version_info->is_kernel_jvm field
    
    Remove is_kernel_jvm field in jvm_version_info structure, as kernel VM has been deprecated
    
    Reviewed-by: mchung
    ---
     jdk/src/share/javavm/export/jvm.h | 3 +--
     1 file changed, 1 insertion(+), 2 deletions(-)
    
    diff --git a/jdk/src/share/javavm/export/jvm.h b/jdk/src/share/javavm/export/jvm.h
    index 56a8abb03cc..1f785f1a108 100644
    --- a/jdk/src/share/javavm/export/jvm.h
    +++ b/jdk/src/share/javavm/export/jvm.h
    @@ -1401,8 +1401,7 @@ typedef struct {
          * the new bit is also added in the main/baseline.
          */
         unsigned int is_attach_supported : 1;
    -    unsigned int is_kernel_jvm : 1;
    -    unsigned int : 30;
    +    unsigned int : 31;
         unsigned int : 32;
         unsigned int : 32;
     } jvm_version_info;
    
    From e0eba88c1b4264060cb1f36758fab06cfdf2458d Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?Joel=20Borggr=C3=A9n-Franck?= 
    Date: Wed, 13 Feb 2013 10:36:36 +0100
    Subject: [PATCH 25/39] 8007278: Rename
     j.l.r.AnnotatedElement.getAnnotations(Class) to getAnnotationsByType(Class)
    
    Reviewed-by: darcy, abuckley
    ---
     jdk/src/share/classes/java/lang/Class.java    |  7 +-
     jdk/src/share/classes/java/lang/Package.java  | 11 ++-
     .../java/lang/reflect/AccessibleObject.java   | 15 ++--
     .../java/lang/reflect/AnnotatedElement.java   | 87 +++++++++++++------
     .../classes/java/lang/reflect/Executable.java |  3 +-
     .../classes/java/lang/reflect/Field.java      |  3 +-
     .../classes/java/lang/reflect/Parameter.java  |  8 +-
     .../annotation/AnnotatedTypeFactory.java      |  6 +-
     .../reflectiveObjects/TypeVariableImpl.java   |  8 +-
     .../lang/annotation/TypeParamAnnotation.java  |  4 +-
     .../RepeatedUnitTest.java                     | 40 ++++-----
     11 files changed, 120 insertions(+), 72 deletions(-)
    
    diff --git a/jdk/src/share/classes/java/lang/Class.java b/jdk/src/share/classes/java/lang/Class.java
    index dab6c98e47a..671d04a65c7 100644
    --- a/jdk/src/share/classes/java/lang/Class.java
    +++ b/jdk/src/share/classes/java/lang/Class.java
    @@ -3087,7 +3087,8 @@ public final
          * @throws NullPointerException {@inheritDoc}
          * @since 1.8
          */
    -    public  A[] getAnnotations(Class annotationClass) {
    +    @Override
    +    public  A[] getAnnotationsByType(Class annotationClass) {
             Objects.requireNonNull(annotationClass);
     
             initAnnotationsIfNecessary();
    @@ -3106,6 +3107,7 @@ public final
          * @throws NullPointerException {@inheritDoc}
          * @since 1.8
          */
    +    @Override
         @SuppressWarnings("unchecked")
         public  A getDeclaredAnnotation(Class annotationClass) {
             Objects.requireNonNull(annotationClass);
    @@ -3118,7 +3120,8 @@ public final
          * @throws NullPointerException {@inheritDoc}
          * @since 1.8
          */
    -    public  A[] getDeclaredAnnotations(Class annotationClass) {
    +    @Override
    +    public  A[] getDeclaredAnnotationsByType(Class annotationClass) {
             Objects.requireNonNull(annotationClass);
     
             initAnnotationsIfNecessary();
    diff --git a/jdk/src/share/classes/java/lang/Package.java b/jdk/src/share/classes/java/lang/Package.java
    index 234f807181a..b9776f478db 100644
    --- a/jdk/src/share/classes/java/lang/Package.java
    +++ b/jdk/src/share/classes/java/lang/Package.java
    @@ -389,8 +389,9 @@ public class Package implements java.lang.reflect.AnnotatedElement {
          * @throws NullPointerException {@inheritDoc}
          * @since 1.8
          */
    -    public   A[] getAnnotations(Class annotationClass) {
    -        return getPackageInfo().getAnnotations(annotationClass);
    +    @Override
    +    public   A[] getAnnotationsByType(Class annotationClass) {
    +        return getPackageInfo().getAnnotationsByType(annotationClass);
         }
     
         /**
    @@ -404,6 +405,7 @@ public class Package implements java.lang.reflect.AnnotatedElement {
          * @throws NullPointerException {@inheritDoc}
          * @since 1.8
          */
    +    @Override
         public  A getDeclaredAnnotation(Class annotationClass) {
             return getPackageInfo().getDeclaredAnnotation(annotationClass);
         }
    @@ -412,8 +414,9 @@ public class Package implements java.lang.reflect.AnnotatedElement {
          * @throws NullPointerException {@inheritDoc}
          * @since 1.8
          */
    -    public  A[] getDeclaredAnnotations(Class annotationClass) {
    -        return getPackageInfo().getDeclaredAnnotations(annotationClass);
    +    @Override
    +    public  A[] getDeclaredAnnotationsByType(Class annotationClass) {
    +        return getPackageInfo().getDeclaredAnnotationsByType(annotationClass);
         }
     
         /**
    diff --git a/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java
    index 9986aef6cf7..d198d939d4b 100644
    --- a/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java
    +++ b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java
    @@ -1,5 +1,5 @@
     /*
    - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
    + * Copyright (c) 1997, 2013, 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
    @@ -184,7 +184,8 @@ public class AccessibleObject implements AnnotatedElement {
          * @throws NullPointerException {@inheritDoc}
          * @since 1.8
          */
    -    public  T[] getAnnotations(Class annotationClass) {
    +    @Override
    +    public  T[] getAnnotationsByType(Class annotationClass) {
             throw new AssertionError("All subclasses should override this method");
         }
     
    @@ -199,6 +200,7 @@ public class AccessibleObject implements AnnotatedElement {
          * @throws NullPointerException {@inheritDoc}
          * @since 1.8
          */
    +    @Override
         public  T getDeclaredAnnotation(Class annotationClass) {
             // Only annotations on classes are inherited, for all other
             // objects getDeclaredAnnotation is the same as
    @@ -210,11 +212,12 @@ public class AccessibleObject implements AnnotatedElement {
          * @throws NullPointerException {@inheritDoc}
          * @since 1.8
          */
    -    public  T[] getDeclaredAnnotations(Class annotationClass) {
    +    @Override
    +    public  T[] getDeclaredAnnotationsByType(Class annotationClass) {
             // Only annotations on classes are inherited, for all other
    -        // objects getDeclaredAnnotations is the same as
    -        // getAnnotations.
    -        return getAnnotations(annotationClass);
    +        // objects getDeclaredAnnotationsByType is the same as
    +        // getAnnotationsByType.
    +        return getAnnotationsByType(annotationClass);
         }
     
         /**
    diff --git a/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java b/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java
    index 85472ff5b00..d6cffec2f28 100644
    --- a/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java
    +++ b/jdk/src/share/classes/java/lang/reflect/AnnotatedElement.java
    @@ -35,22 +35,43 @@ import java.lang.annotation.Annotation;
      * arrays returned by accessors for array-valued enum members; it will
      * have no affect on the arrays returned to other callers.
      *
    - * 

    An annotation A is directly present on an element E if the - * RuntimeVisibleAnnotations or RuntimeVisibleParameterAnnotations attribute - * associated with E either: + *

    The {@link #getAnnotationsByType(Class)} and {@link + * #getDeclaredAnnotationsByType(Class)} methods support multiple + * annotations of the same type on an element. If the argument to either method + * is a repeatable annotation type (JLS 9.6), then the method will "look + * through" a container annotation (JLS 9.7) which was generated at + * compile-time to wrap multiple annotations of the argument type. + * + *

    The terms directly present and present are used + * throughout this interface to describe precisely which annotations are + * returned by methods: + * *

      - *
    • contains A; or - *
    • for invocations of get[Declared]Annotations(Class), - * contains A or exactly one annotation C whose type is the containing - * annotation type of A's type (JLS 9.6) and whose value element contains A + *
    • An annotation A is directly present on an element E if E is + * associated with a RuntimeVisibleAnnotations or + * RuntimeVisibleParameterAnnotations attribute, and: + * + *
        + *
      • for an invocation of {@code get[Declared]Annotation(Class)} or + * {@code get[Declared]Annotations()}, the attribute contains A. + * + *
      • for an invocation of {@code get[Declared]AnnotationsByType(Class)}, the + * attribute either contains A or, if the type of A is repeatable, contains + * exactly one annotation whose value element contains A and whose type is the + * containing annotation type of A's type (JLS 9.6). *
      * - *

      An annotation A is present on an element E if either: + *

      + *

    • An annotation A is present on an element E if either: + * *
        *
      • A is directly present on E; or - *
      • There are no annotations of A's type which are directly present - * on E, and E is a class, and A's type is inheritable (JLS 9.6.3.3), and A is - * present on the superclass of E + * + *
      • A is not directly present on E, and E is a class, and A's type + * is inheritable (JLS 9.6.3.3), and A is present on the superclass of + * E. + *
      + * *
    * *

    If an annotation returned by a method in this interface contains @@ -119,12 +140,19 @@ public interface AnnotatedElement { T getAnnotation(Class annotationClass); /** - * Returns an array of all this element's annotations for the - * specified type if one or more of such annotation is present, - * else an array of length zero. + * Returns annotations that are present on this element. * - * The caller of this method is free to modify the returned array; - * it will have no effect on the arrays returned to other callers. + * If there are no annotations present on this element, the return + * value is an array of length 0. + * + * The difference between this method and {@link #getAnnotation(Class)} + * is that this method detects if its argument is a repeatable + * annotation type (JLS 9.6), and if so, attempts to find one or + * more annotations of that type by "looking through" a container + * annotation. + * + * The caller of this method is free to modify the returned array; it will + * have no effect on the arrays returned to other callers. * * @param annotationClass the Class object corresponding to the * annotation type @@ -133,7 +161,7 @@ public interface AnnotatedElement { * @throws NullPointerException if the given annotation class is null * @since 1.8 */ - T[] getAnnotations(Class annotationClass); + T[] getAnnotationsByType(Class annotationClass); /** * Returns annotations that are present on this element. @@ -165,16 +193,21 @@ public interface AnnotatedElement { */ T getDeclaredAnnotation(Class annotationClass); - /** - * Returns an array of all this element's annotations for the - * specified type if one or more of such annotation is directly - * present, else an array of length zero. + /** + * Returns annotations that are directly present on this element. + * This method ignores inherited annotations. * - * This method ignores inherited annotations. (Returns - * an array of length zero if no annotations are directly present - * on this element.) The caller of this method is free to modify - * the returned array; it will have no effect on the arrays - * returned to other callers. + * If there are no annotations directly present on this element, + * the return value is an array of length 0. + * + * The difference between this method and {@link + * #getDeclaredAnnotation(Class)} is that this method detects if its + * argument is a repeatable annotation type (JLS 9.6), and if so, + * attempts to find one or more annotations of that type by "looking + * through" a container annotation. + * + * The caller of this method is free to modify the returned array; it will + * have no effect on the arrays returned to other callers. * * @param annotationClass the Class object corresponding to the * annotation type @@ -183,7 +216,7 @@ public interface AnnotatedElement { * @throws NullPointerException if the given annotation class is null * @since 1.8 */ - T[] getDeclaredAnnotations(Class annotationClass); + T[] getDeclaredAnnotationsByType(Class annotationClass); /** * Returns annotations that are directly present on this element. diff --git a/jdk/src/share/classes/java/lang/reflect/Executable.java b/jdk/src/share/classes/java/lang/reflect/Executable.java index 4c785e3e87f..83b5e9c87a4 100644 --- a/jdk/src/share/classes/java/lang/reflect/Executable.java +++ b/jdk/src/share/classes/java/lang/reflect/Executable.java @@ -449,7 +449,8 @@ public abstract class Executable extends AccessibleObject * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public T[] getAnnotations(Class annotationClass) { + @Override + public T[] getAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); return AnnotationSupport.getMultipleAnnotations(declaredAnnotations(), annotationClass); diff --git a/jdk/src/share/classes/java/lang/reflect/Field.java b/jdk/src/share/classes/java/lang/reflect/Field.java index df38832eb15..be13b076832 100644 --- a/jdk/src/share/classes/java/lang/reflect/Field.java +++ b/jdk/src/share/classes/java/lang/reflect/Field.java @@ -1029,7 +1029,8 @@ class Field extends AccessibleObject implements Member { * @throws NullPointerException {@inheritDoc} * @since 1.8 */ - public T[] getAnnotations(Class annotationClass) { + @Override + public T[] getAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); return AnnotationSupport.getMultipleAnnotations(declaredAnnotations(), annotationClass); diff --git a/jdk/src/share/classes/java/lang/reflect/Parameter.java b/jdk/src/share/classes/java/lang/reflect/Parameter.java index 3ecd7c674ea..9c808310c0c 100644 --- a/jdk/src/share/classes/java/lang/reflect/Parameter.java +++ b/jdk/src/share/classes/java/lang/reflect/Parameter.java @@ -258,7 +258,8 @@ public final class Parameter implements AnnotatedElement { * {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ - public T[] getAnnotations(Class annotationClass) { + @Override + public T[] getAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); return AnnotationSupport.getMultipleAnnotations(declaredAnnotations(), annotationClass); @@ -284,11 +285,12 @@ public final class Parameter implements AnnotatedElement { /** * @throws NullPointerException {@inheritDoc} */ - public T[] getDeclaredAnnotations(Class annotationClass) { + @Override + public T[] getDeclaredAnnotationsByType(Class annotationClass) { // Only annotations on classes are inherited, for all other // objects getDeclaredAnnotations is the same as // getAnnotations. - return getAnnotations(annotationClass); + return getAnnotationsByType(annotationClass); } /** diff --git a/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java b/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java index e0524e849dc..e9f3f957c09 100644 --- a/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java +++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java @@ -148,8 +148,8 @@ public class AnnotatedTypeFactory { } @Override - public final T[] getAnnotations(Class annotation) { - return getDeclaredAnnotations(annotation); + public final T[] getAnnotationsByType(Class annotation) { + return getDeclaredAnnotationsByType(annotation); } @Override @@ -164,7 +164,7 @@ public class AnnotatedTypeFactory { } @Override - public T[] getDeclaredAnnotations(Class annotation) { + public T[] getDeclaredAnnotationsByType(Class annotation) { return AnnotationSupport.getMultipleAnnotations(annotations, annotation); } diff --git a/jdk/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java b/jdk/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java index 528658d0d16..0b1a13ee74e 100644 --- a/jdk/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java +++ b/jdk/src/share/classes/sun/reflect/generics/reflectiveObjects/TypeVariableImpl.java @@ -200,14 +200,16 @@ public class TypeVariableImpl return getAnnotation(annotationClass); } - public T[] getAnnotations(Class annotationClass) { + @Override + public T[] getAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); return AnnotationSupport.getMultipleAnnotations(mapAnnotations(getAnnotations()), annotationClass); } - public T[] getDeclaredAnnotations(Class annotationClass) { + @Override + public T[] getDeclaredAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); - return getAnnotations(annotationClass); + return getAnnotationsByType(annotationClass); } public Annotation[] getAnnotations() { diff --git a/jdk/test/java/lang/annotation/TypeParamAnnotation.java b/jdk/test/java/lang/annotation/TypeParamAnnotation.java index 50457ec46b1..694d83dcd35 100644 --- a/jdk/test/java/lang/annotation/TypeParamAnnotation.java +++ b/jdk/test/java/lang/annotation/TypeParamAnnotation.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8004698 + * @bug 8004698 8007278 * @summary Unit test for annotations on TypeVariables */ @@ -93,7 +93,7 @@ public class TypeParamAnnotation { private static void testGetAnnos() throws Exception { TypeVariable[] ts = TypeParam.class.getDeclaredMethod("foo").getTypeParameters(); ParamAnno2[] as; - as = ts[0].getAnnotations(ParamAnno2.class); + as = ts[0].getAnnotationsByType(ParamAnno2.class); check(as.length == 1); check(as[0].value() == 3); } diff --git a/jdk/test/java/lang/annotation/repeatingAnnotations/RepeatedUnitTest.java b/jdk/test/java/lang/annotation/repeatingAnnotations/RepeatedUnitTest.java index 10e3d746261..674f37fbb56 100644 --- a/jdk/test/java/lang/annotation/repeatingAnnotations/RepeatedUnitTest.java +++ b/jdk/test/java/lang/annotation/repeatingAnnotations/RepeatedUnitTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7154390 8005712 + * @bug 7154390 8005712 8007278 * @summary Unit test for repeated annotation reflection * * @compile RepeatedUnitTest.java subpackage/package-info.java subpackage/Container.java subpackage/Containee.java subpackage/NonRepeated.java subpackage/InheritedContainee.java subpackage/InheritedContainer.java subpackage/InheritedNonRepeated.java @@ -76,7 +76,7 @@ public class RepeatedUnitTest { check(1 == countAnnotation(e, NonRepeated.class)); - nr = e.getAnnotations(NonRepeated.class)[0]; + nr = e.getAnnotationsByType(NonRepeated.class)[0]; check(nr.value() == 10); check(1 == containsAnnotationOfType(e.getAnnotations(), NonRepeated.class)); @@ -87,9 +87,9 @@ public class RepeatedUnitTest { check(c == null); check(2 == countAnnotation(e, Containee.class)); - c = e.getAnnotations(Containee.class)[0]; + c = e.getAnnotationsByType(Containee.class)[0]; check(c.value() == 1); - c = e.getAnnotations(Containee.class)[1]; + c = e.getAnnotationsByType(Containee.class)[1]; check(c.value() == 2); check(0 == containsAnnotationOfType(e.getAnnotations(), Containee.class)); @@ -98,7 +98,7 @@ public class RepeatedUnitTest { static void packageContainer(AnnotatedElement e) { Container cr = e.getAnnotation(Container.class); check(null != cr); - check(1 == containsAnnotationOfType(e.getAnnotations(Container.class), Container.class)); + check(1 == containsAnnotationOfType(e.getAnnotationsByType(Container.class), Container.class)); check(1 == countAnnotation(e, Container.class)); } @@ -123,10 +123,10 @@ public class RepeatedUnitTest { check(1 == countAnnotation(e, NonRepeated.class)); check(1 == countAnnotation(e, InheritedNonRepeated.class)); - check(e.getAnnotations(Containee.class)[2].value() == 300); - check(e.getAnnotations(InheritedContainee.class)[2].value() == 300); - check(e.getAnnotations(InheritedNonRepeated.class)[0].value() == 200); - check(e.getAnnotations(NonRepeated.class)[0].value() == 100); + check(e.getAnnotationsByType(Containee.class)[2].value() == 300); + check(e.getAnnotationsByType(InheritedContainee.class)[2].value() == 300); + check(e.getAnnotationsByType(InheritedNonRepeated.class)[0].value() == 200); + check(e.getAnnotationsByType(NonRepeated.class)[0].value() == 100); } static void inheritedMe3() { @@ -138,8 +138,8 @@ public class RepeatedUnitTest { check(0 == countAnnotation(e, Container.class)); check(1 == countAnnotation(e, InheritedContainer.class)); - check(e.getAnnotations(InheritedContainee.class)[2].value() == 350); - check(e.getAnnotations(InheritedNonRepeated.class)[0].value() == 15); + check(e.getAnnotationsByType(InheritedContainee.class)[2].value() == 350); + check(e.getAnnotationsByType(InheritedNonRepeated.class)[0].value() == 15); } static void inheritedMe4() { @@ -153,24 +153,24 @@ public class RepeatedUnitTest { check(1 == countAnnotation(e, NonRepeated.class)); check(1 == countAnnotation(e, InheritedNonRepeated.class)); - check(e.getAnnotations(Containee.class)[2].value() == 3000); - check(e.getAnnotations(InheritedContainee.class)[2].value() == 3000); - check(e.getAnnotations(InheritedNonRepeated.class)[0].value() == 2000); - check(e.getAnnotations(NonRepeated.class)[0].value() == 1000); + check(e.getAnnotationsByType(Containee.class)[2].value() == 3000); + check(e.getAnnotationsByType(InheritedContainee.class)[2].value() == 3000); + check(e.getAnnotationsByType(InheritedNonRepeated.class)[0].value() == 2000); + check(e.getAnnotationsByType(NonRepeated.class)[0].value() == 1000); } static void checkMultiplier(AnnotatedElement e, int m) { // Basic sanity of non-repeating getAnnotation(Class) check(e.getAnnotation(NonRepeated.class).value() == 5 * m); - // Check count of annotations returned from getAnnotations(Class) + // Check count of annotations returned from getAnnotationsByType(Class) check(4 == countAnnotation(e, Containee.class)); check(1 == countAnnotation(e, Container.class)); check(1 == countAnnotation(e, NonRepeated.class)); - // Check contents of array returned from getAnnotations(Class) - check(e.getAnnotations(Containee.class)[2].value() == 3 * m); - check(e.getAnnotations(NonRepeated.class)[0].value() == 5 * m); + // Check contents of array returned from getAnnotationsByType(Class) + check(e.getAnnotationsByType(Containee.class)[2].value() == 3 * m); + check(e.getAnnotationsByType(NonRepeated.class)[0].value() == 5 * m); // Check getAnnotation(Class) check(e.getAnnotation(Containee.class) == null); @@ -187,7 +187,7 @@ public class RepeatedUnitTest { } static int countAnnotation(AnnotatedElement e, Class c) { - return containsAnnotationOfType(e.getAnnotations(c), c); + return containsAnnotationOfType(e.getAnnotationsByType(c), c); } static int containsAnnotationOfType(A[] l, Class a) { From 30a25e41d228e7b26787b538268dee7796efcd72 Mon Sep 17 00:00:00 2001 From: Vera Akulova Date: Wed, 13 Feb 2013 18:01:18 +0400 Subject: [PATCH 26/39] 7161759: TEST_BUG: java/awt/Frame/WindowDragTest/WindowDragTest.java fails to compile, should be modified Added @build Util jtreg tag Reviewed-by: serb, alexsch --- jdk/test/java/awt/Frame/WindowDragTest/WindowDragTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jdk/test/java/awt/Frame/WindowDragTest/WindowDragTest.java b/jdk/test/java/awt/Frame/WindowDragTest/WindowDragTest.java index 127a49e607d..e7b0970b0fc 100644 --- a/jdk/test/java/awt/Frame/WindowDragTest/WindowDragTest.java +++ b/jdk/test/java/awt/Frame/WindowDragTest/WindowDragTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2013, 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 @@ -23,10 +23,11 @@ /* @test - @bug 7128738 + @bug 7128738 7161759 @summary dragged dialog freezes system on dispose @author Oleg Pekhovskiy: area=awt.toplevel @library ../../regtesthelpers + @build Util @run main WindowDragTest */ From dfdd79f3eee03868cccdbb84f2159a7fa42a598f Mon Sep 17 00:00:00 2001 From: Vera Akulova Date: Wed, 13 Feb 2013 19:06:31 +0400 Subject: [PATCH 27/39] 7132383: [macosx] bug6596966.java should be adapted for Mac Reviewed-by: serb, alexsch --- .../swing/JLabel/6596966/bug6596966.java | 24 +++++++++----- jdk/test/javax/swing/regtesthelpers/Util.java | 33 ++++++++++++++++++- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/jdk/test/javax/swing/JLabel/6596966/bug6596966.java b/jdk/test/javax/swing/JLabel/6596966/bug6596966.java index 5e94459bcb7..361cebcd24f 100644 --- a/jdk/test/javax/swing/JLabel/6596966/bug6596966.java +++ b/jdk/test/javax/swing/JLabel/6596966/bug6596966.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, 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 @@ -24,16 +24,17 @@ /* @test @bug 6596966 @summary Some JFileChooser mnemonics do not work with sticky keys + @library ../../regtesthelpers + @build Util @run main bug6596966 @author Pavel Porvatov */ - -import sun.awt.SunToolkit; - -import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; +import java.util.ArrayList; +import javax.swing.*; +import sun.awt.SunToolkit; public class bug6596966 { private static JFrame frame; @@ -71,11 +72,14 @@ public class bug6596966 { toolkit.realSync(); - robot.keyPress(KeyEvent.VK_ALT); + ArrayList keys = Util.getSystemMnemonicKeyCodes(); + for (int i = 0; i < keys.size(); ++i) { + robot.keyPress(keys.get(i)); + } + robot.keyPress(KeyEvent.VK_L); toolkit.realSync(); - toolkit.getSystemEventQueue().postEvent(new KeyEvent(label, KeyEvent.KEY_RELEASED, EventQueue.getMostRecentEventTime(), 0, KeyEvent.VK_L, 'L')); @@ -90,7 +94,11 @@ public class bug6596966 { } }); } finally { - robot.keyRelease(KeyEvent.VK_ALT); + robot.keyRelease(KeyEvent.VK_L); + for (int i = 0; i < keys.size(); ++i) { + robot.keyRelease(keys.get(i)); + } + toolkit.realSync(); } } } diff --git a/jdk/test/javax/swing/regtesthelpers/Util.java b/jdk/test/javax/swing/regtesthelpers/Util.java index a9df4934583..df7ab7ade80 100644 --- a/jdk/test/javax/swing/regtesthelpers/Util.java +++ b/jdk/test/javax/swing/regtesthelpers/Util.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2013, 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 @@ -23,11 +23,13 @@ import javax.swing.*; import java.awt.*; +import java.awt.event.*; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.concurrent.Callable; +import sun.swing.*; /** *

    This class contains utilities useful for regression testing. @@ -212,4 +214,33 @@ public class Util { return result.get(0); } + /** + * Gets key codes from system mnemonic key mask + * @return key codes list + */ + public static ArrayList getSystemMnemonicKeyCodes() { + return Util.getKeyCodesFromKeyMask(SwingUtilities2.getSystemMnemonicKeyMask()); + } + + /** + * Gets the key codes list from modifiers + * @param modifiers an integer combination of the modifier constants + * @return key codes list + */ + public static ArrayList getKeyCodesFromKeyMask(int modifiers) { + ArrayList result = new ArrayList<>(); + if ((modifiers & InputEvent.CTRL_MASK) != 0) { + result.add(KeyEvent.VK_CONTROL); + } + if ((modifiers & InputEvent.ALT_MASK) != 0) { + result.add(KeyEvent.VK_ALT); + } + if ((modifiers & InputEvent.SHIFT_MASK) != 0) { + result.add(KeyEvent.VK_SHIFT); + } + if ((modifiers & InputEvent.META_MASK) != 0) { + result.add(KeyEvent.VK_META); + } + return result; + } } From f44592861ca62ec51148e93cf130662840540edd Mon Sep 17 00:00:00 2001 From: Vladislav Karnaukhov Date: Wed, 13 Feb 2013 19:23:09 +0400 Subject: [PATCH 28/39] 4199622: RFE: JComboBox shouldn't sending ActionEvents for keyboard navigation Reviewed-by: alexp, alexsch --- .../swing/plaf/basic/BasicComboBoxUI.java | 63 +++-- .../swing/plaf/basic/BasicLookAndFeel.java | 3 +- .../swing/JComboBox/4199622/bug4199622.java | 243 ++++++++++++++++++ 3 files changed, 290 insertions(+), 19 deletions(-) create mode 100644 jdk/test/javax/swing/JComboBox/4199622/bug4199622.java diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java index 269bd34afc3..b31f7606b8e 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, 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 @@ -1120,7 +1120,9 @@ public class BasicComboBoxUI extends ComboBoxUI { listBox.setSelectedIndex( si + 1 ); listBox.ensureIndexIsVisible( si + 1 ); if ( !isTableCellEditor ) { - comboBox.setSelectedIndex(si+1); + if (!(UIManager.getBoolean("ComboBox.noActionOnKeyNavigation") && comboBox.isPopupVisible())) { + comboBox.setSelectedIndex(si+1); + } } comboBox.repaint(); } @@ -1144,7 +1146,9 @@ public class BasicComboBoxUI extends ComboBoxUI { listBox.setSelectedIndex( si - 1 ); listBox.ensureIndexIsVisible( si - 1 ); if ( !isTableCellEditor ) { - comboBox.setSelectedIndex(si-1); + if (!(UIManager.getBoolean("ComboBox.noActionOnKeyNavigation") && comboBox.isPopupVisible())) { + comboBox.setSelectedIndex(si-1); + } } comboBox.repaint(); } @@ -1490,7 +1494,13 @@ public class BasicComboBoxUI extends ComboBoxUI { key == HOME || key == END) { int index = getNextIndex(comboBox, key); if (index >= 0 && index < comboBox.getItemCount()) { - comboBox.setSelectedIndex(index); + if (UIManager.getBoolean("ComboBox.noActionOnKeyNavigation") && comboBox.isPopupVisible()) { + ui.listBox.setSelectedIndex(index); + ui.listBox.ensureIndexIsVisible(index); + comboBox.repaint(); + } else { + comboBox.setSelectedIndex(index); + } } } else if (key == DOWN) { @@ -1558,22 +1568,33 @@ public class BasicComboBoxUI extends ComboBoxUI { else if (key == ENTER) { if (comboBox.isPopupVisible()) { - // Forces the selection of the list item - boolean isEnterSelectablePopup = - UIManager.getBoolean("ComboBox.isEnterSelectablePopup"); - if (!comboBox.isEditable() || isEnterSelectablePopup - || ui.isTableCellEditor) { + // If ComboBox.noActionOnKeyNavigation is set, + // forse selection of list item + if (UIManager.getBoolean("ComboBox.noActionOnKeyNavigation")) { Object listItem = ui.popup.getList().getSelectedValue(); if (listItem != null) { - // Use the selected value from popup - // to set the selected item in combo box, - // but ensure before that JComboBox.actionPerformed() - // won't use editor's value to set the selected item comboBox.getEditor().setItem(listItem); comboBox.setSelectedItem(listItem); } + comboBox.setPopupVisible(false); + } else { + // Forces the selection of the list item + boolean isEnterSelectablePopup = + UIManager.getBoolean("ComboBox.isEnterSelectablePopup"); + if (!comboBox.isEditable() || isEnterSelectablePopup + || ui.isTableCellEditor) { + Object listItem = ui.popup.getList().getSelectedValue(); + if (listItem != null) { + // Use the selected value from popup + // to set the selected item in combo box, + // but ensure before that JComboBox.actionPerformed() + // won't use editor's value to set the selected item + comboBox.getEditor().setItem(listItem); + comboBox.setSelectedItem(listItem); + } + } + comboBox.setPopupVisible(false); } - comboBox.setPopupVisible(false); } else { // Hide combo box if it is a table cell editor @@ -1604,14 +1625,20 @@ public class BasicComboBoxUI extends ComboBoxUI { } private int getNextIndex(JComboBox comboBox, String key) { + int listHeight = comboBox.getMaximumRowCount(); + + int selectedIndex = comboBox.getSelectedIndex(); + if (UIManager.getBoolean("ComboBox.noActionOnKeyNavigation") + && (comboBox.getUI() instanceof BasicComboBoxUI)) { + selectedIndex = ((BasicComboBoxUI) comboBox.getUI()).listBox.getSelectedIndex(); + } + if (key == PAGE_UP) { - int listHeight = comboBox.getMaximumRowCount(); - int index = comboBox.getSelectedIndex() - listHeight; + int index = selectedIndex - listHeight; return (index < 0 ? 0: index); } else if (key == PAGE_DOWN) { - int listHeight = comboBox.getMaximumRowCount(); - int index = comboBox.getSelectedIndex() + listHeight; + int index = selectedIndex + listHeight; int max = comboBox.getItemCount(); return (index < max ? index: max-1); } diff --git a/jdk/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java b/jdk/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java index 5a9135844bc..2e808c4b566 100644 --- a/jdk/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/jdk/src/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, 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 @@ -861,6 +861,7 @@ public abstract class BasicLookAndFeel extends LookAndFeel implements Serializab "END", "endPassThrough", "ENTER", "enterPressed" }), + "ComboBox.noActionOnKeyNavigation", Boolean.FALSE, // *** FileChooser diff --git a/jdk/test/javax/swing/JComboBox/4199622/bug4199622.java b/jdk/test/javax/swing/JComboBox/4199622/bug4199622.java new file mode 100644 index 00000000000..2c7deddb31b --- /dev/null +++ b/jdk/test/javax/swing/JComboBox/4199622/bug4199622.java @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2013, 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 4199622 + @summary RFE: JComboBox shouldn't send ActionEvents for keyboard navigation + @author Vladislav Karnaukhov + @run main bug4199622 +*/ + +import com.sun.java.swing.plaf.windows.WindowsLookAndFeel; +import sun.awt.OSInfo; +import sun.awt.SunToolkit; + +import javax.swing.*; +import javax.swing.plaf.metal.MetalLookAndFeel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; +import java.lang.reflect.InvocationTargetException; + +public class bug4199622 extends JFrame implements ActionListener { + + static final int nElems = 20; + static JComboBox cb = null; + + bug4199622(LookAndFeel laf) { + super(); + + try { + UIManager.setLookAndFeel(laf); + } catch (UnsupportedLookAndFeelException e) { + throw new RuntimeException("Test failed", e); + } + + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + cb = new JComboBox<>(); + for (int i = 0; i < nElems; i++) { + cb.addItem(String.valueOf(i + 1)); + } + cb.addActionListener(this); + add(cb); + + setSize(300, 300); + pack(); + } + + @Override + public void actionPerformed(ActionEvent e) { + if (UIManager.getBoolean("ComboBox.noActionOnKeyNavigation") && cb.isPopupVisible()) { + throw new RuntimeException("Test failed. actionPerformed generated"); + } + } + + static Robot robot = null; + static SunToolkit toolkit = null; + + static void doTest() { + if (robot == null) { + try { + robot = new Robot(); + robot.setAutoDelay(20); + } catch (AWTException e) { + throw new RuntimeException("Can't create robot. Test failed", e); + } + } + + toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + if (toolkit == null) { + throw new RuntimeException("Can't get the toolkit. Test failed"); + } + toolkit.realSync(); + + doActualTest(); + + try { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + cb.hidePopup(); + cb.setEditable(true); + cb.updateUI(); + } + }); + } catch (InterruptedException e) { + throw new RuntimeException("Test failed", e); + } catch (InvocationTargetException e) { + throw new RuntimeException("Test failed", e); + } + + toolkit.realSync(); + doActualTest(); + } + + static void doActualTest() { + UIManager.put("ComboBox.noActionOnKeyNavigation", true); + doTestUpDown(); + UIManager.put("ComboBox.noActionOnKeyNavigation", false); + doTestUpDown(); + + UIManager.put("ComboBox.noActionOnKeyNavigation", true); + doTestPgUpDown(); + UIManager.put("ComboBox.noActionOnKeyNavigation", false); + doTestPgUpDown(); + + UIManager.put("ComboBox.noActionOnKeyNavigation", true); + doTestHomeEnd(); + UIManager.put("ComboBox.noActionOnKeyNavigation", false); + doTestHomeEnd(); + } + + static void doTestHomeEnd() { + try { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + cb.hidePopup(); + cb.setSelectedIndex(0); + } + }); + } catch (InterruptedException e) { + throw new RuntimeException("Test failed", e); + } catch (InvocationTargetException e) { + throw new RuntimeException("Test failed", e); + } + toolkit.realSync(); + + robot.keyPress(KeyEvent.VK_END); + toolkit.realSync(); + robot.keyPress(KeyEvent.VK_HOME); + toolkit.realSync(); + } + + static void doTestUpDown() { + try { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + cb.hidePopup(); + cb.setSelectedIndex(0); + } + }); + } catch (InterruptedException e) { + throw new RuntimeException("Test failed", e); + } catch (InvocationTargetException e) { + throw new RuntimeException("Test failed", e); + } + toolkit.realSync(); + + for (int i = 0; i < nElems; i++) { + robot.keyPress(KeyEvent.VK_DOWN); + toolkit.realSync(); + } + + for (int i = 0; i < nElems; i++) { + robot.keyPress(KeyEvent.VK_UP); + toolkit.realSync(); + } + } + + static void doTestPgUpDown() { + try { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + cb.hidePopup(); + cb.setSelectedIndex(0); + } + }); + } catch (InterruptedException e) { + throw new RuntimeException("Test failed", e); + } catch (InvocationTargetException e) { + throw new RuntimeException("Test failed", e); + } + toolkit.realSync(); + + int listHeight = cb.getMaximumRowCount(); + for (int i = 0; i < nElems; i += listHeight) { + robot.keyPress(KeyEvent.VK_PAGE_DOWN); + toolkit.realSync(); + } + + for (int i = 0; i < nElems; i += listHeight) { + robot.keyPress(KeyEvent.VK_PAGE_UP); + toolkit.realSync(); + } + } + + public static void main(String[] args) { + try { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + bug4199622 test = new bug4199622(new MetalLookAndFeel()); + test.setVisible(true); + } + }); + } catch (InterruptedException e) { + throw new RuntimeException("Test failed", e); + } catch (InvocationTargetException e) { + throw new RuntimeException("Test failed", e); + } + doTest(); + + if (OSInfo.getOSType() == OSInfo.OSType.WINDOWS) { + try { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + bug4199622 test = new bug4199622(new WindowsLookAndFeel()); + test.setVisible(true); + } + }); + } catch (InterruptedException e) { + throw new RuntimeException("Test failed", e); + } catch (InvocationTargetException e) { + throw new RuntimeException("Test failed", e); + } + doTest(); + } + } +} From 42b8720beff94cc6d87975d08ff2e5c77d294dab Mon Sep 17 00:00:00 2001 From: Petr Pchelko Date: Wed, 13 Feb 2013 15:27:29 +0000 Subject: [PATCH 29/39] 7079260: InputContext leaks memory Replaced strong refs with weak refs Reviewed-by: art, serb --- .../sun/awt/im/CompositionAreaHandler.java | 15 ++- .../classes/sun/awt/X11InputMethod.java | 13 +- .../InputContextMemoryLeakTest.java | 112 ++++++++++++++++++ jdk/test/java/awt/regtesthelpers/Util.java | 7 ++ 4 files changed, 135 insertions(+), 12 deletions(-) create mode 100644 jdk/test/java/awt/im/memoryleak/InputContextMemoryLeakTest.java diff --git a/jdk/src/share/classes/sun/awt/im/CompositionAreaHandler.java b/jdk/src/share/classes/sun/awt/im/CompositionAreaHandler.java index 6ae4a957ce2..1d661c4b9ba 100644 --- a/jdk/src/share/classes/sun/awt/im/CompositionAreaHandler.java +++ b/jdk/src/share/classes/sun/awt/im/CompositionAreaHandler.java @@ -33,6 +33,7 @@ import java.awt.event.InputMethodListener; import java.awt.font.TextAttribute; import java.awt.font.TextHitInfo; import java.awt.im.InputMethodRequests; +import java.lang.ref.WeakReference; import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator.Attribute; import java.text.AttributedString; @@ -55,7 +56,7 @@ class CompositionAreaHandler implements InputMethodListener, private AttributedCharacterIterator composedText; private TextHitInfo caret = null; - private Component clientComponent = null; + private WeakReference clientComponent = new WeakReference<>(null); private InputMethodContext inputMethodContext; /** @@ -76,8 +77,9 @@ class CompositionAreaHandler implements InputMethodListener, } // If the client component is an active client using below-the-spot style, then // make the composition window undecorated without a title bar. - if(clientComponent!=null){ - InputMethodRequests req = clientComponent.getInputMethodRequests(); + Component client = clientComponent.get(); + if(client != null){ + InputMethodRequests req = client.getInputMethodRequests(); if (req != null && inputMethodContext.useBelowTheSpotInput()) { setCompositionAreaUndecorated(true); } @@ -86,7 +88,7 @@ class CompositionAreaHandler implements InputMethodListener, } void setClientComponent(Component clientComponent) { - this.clientComponent = clientComponent; + this.clientComponent = new WeakReference<>(clientComponent); } /** @@ -256,8 +258,9 @@ class CompositionAreaHandler implements InputMethodListener, * the composed text are forwarded to the client component. */ InputMethodRequests getClientInputMethodRequests() { - if (clientComponent != null) { - return clientComponent.getInputMethodRequests(); + Component client = clientComponent.get(); + if (client != null) { + return client.getInputMethodRequests(); } return null; diff --git a/jdk/src/solaris/classes/sun/awt/X11InputMethod.java b/jdk/src/solaris/classes/sun/awt/X11InputMethod.java index b2a62c60ce8..b1939a67d9b 100644 --- a/jdk/src/solaris/classes/sun/awt/X11InputMethod.java +++ b/jdk/src/solaris/classes/sun/awt/X11InputMethod.java @@ -57,6 +57,7 @@ import java.io.File; import java.io.FileReader; import java.io.BufferedReader; import java.io.IOException; +import java.lang.ref.WeakReference; import sun.util.logging.PlatformLogger; import java.util.StringTokenizer; import java.util.regex.Pattern; @@ -104,7 +105,7 @@ public abstract class X11InputMethod extends InputMethodAdapter { //reset the XIC if necessary private boolean needResetXIC = false; - private Component needResetXICClient = null; + private WeakReference needResetXICClient = new WeakReference<>(null); // The use of compositionEnableSupported is to reduce unnecessary // native calls if set/isCompositionEnabled @@ -272,14 +273,14 @@ public abstract class X11InputMethod extends InputMethodAdapter { called on the passive client when endComposition is called. */ if (needResetXIC && haveActiveClient() && - getClientComponent() != needResetXICClient){ + getClientComponent() != needResetXICClient.get()){ resetXIC(); // needs to reset the last xic focussed component. lastXICFocussedComponent = null; isLastXICActive = false; - needResetXICClient = null; + needResetXICClient.clear(); needResetXIC = false; } } @@ -417,7 +418,7 @@ public abstract class X11InputMethod extends InputMethodAdapter { isLastXICActive = false; resetXIC(); - needResetXICClient = null; + needResetXICClient.clear(); needResetXIC = false; } } @@ -478,7 +479,7 @@ public abstract class X11InputMethod extends InputMethodAdapter { disableInputMethod(); if (needResetXIC) { resetXIC(); - needResetXICClient = null; + needResetXICClient.clear(); needResetXIC = false; } } @@ -877,7 +878,7 @@ public abstract class X11InputMethod extends InputMethodAdapter { boolean active = haveActiveClient(); if (active && composedText == null && committedText == null){ needResetXIC = true; - needResetXICClient = getClientComponent(); + needResetXICClient = new WeakReference<>(getClientComponent()); return; } diff --git a/jdk/test/java/awt/im/memoryleak/InputContextMemoryLeakTest.java b/jdk/test/java/awt/im/memoryleak/InputContextMemoryLeakTest.java new file mode 100644 index 00000000000..04e4a333cdd --- /dev/null +++ b/jdk/test/java/awt/im/memoryleak/InputContextMemoryLeakTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2013, 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.awt.FlowLayout; +import java.awt.Robot; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import test.java.awt.regtesthelpers.Util; + +/* + @test + @bug 7079260 + @summary XInputContext leaks memory by needRecetXXIClient field + @author Petr Pchelko + @library ../../regtesthelpers + @build Util + @compile InputContextMemoryLeakTest.java + @run main/othervm -Xmx20M InputContextMemoryLeakTest + */ +public class InputContextMemoryLeakTest { + + private static JFrame frame; + private static WeakReference text; + private static WeakReference p; + private static JButton button; + + public static void init() throws Throwable { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame = new JFrame(); + frame.setLayout(new FlowLayout()); + JPanel p1 = new JPanel(); + button = new JButton("Test"); + p1.add(button); + frame.add(p1); + text = new WeakReference(new JTextField("Text")); + p = new WeakReference(new JPanel(new FlowLayout())); + p.get().add(text.get()); + frame.add(p.get()); + frame.setBounds(500, 400, 200, 200); + frame.setVisible(true); + } + }); + + Util.focusComponent(text.get(), 500); + Util.clickOnComp(button, new Robot()); + //References to objects testes for memory leak are stored in Util. + //Need to clean them + Util.cleanUp(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame.remove(p.get()); + } + }); + + Util.waitForIdle(null); + //After the next caret blink it automatically TextField references + Thread.sleep(text.get().getCaret().getBlinkRate() * 2); + Util.waitForIdle(null); + assertGC(); + } + + public static void assertGC() throws Throwable { + List alloc = new ArrayList(); + int size = 1024 * 10; + while (true) { + try { + alloc.add(new byte[size]); + } catch (OutOfMemoryError err) { + break; + } + } + alloc = null; + if (text.get() != null) { + throw new Exception("Test failed: JTextField was not collected"); + } + } + + public static void main(String args[]) throws Throwable { + init(); + } +} diff --git a/jdk/test/java/awt/regtesthelpers/Util.java b/jdk/test/java/awt/regtesthelpers/Util.java index ebbfdf90463..90b28222552 100644 --- a/jdk/test/java/awt/regtesthelpers/Util.java +++ b/jdk/test/java/awt/regtesthelpers/Util.java @@ -463,6 +463,13 @@ public final class Util { return -1; } + //Cleans all the references + public static void cleanUp() { + apListener = null; + fgListener = null; + wgfListener = null; + } + //////////////////////////// // Some stuff to test focus. From 959ddfce4a7840aa855d6351961badff298a2c29 Mon Sep 17 00:00:00 2001 From: Petr Pchelko Date: Wed, 13 Feb 2013 15:32:50 +0000 Subject: [PATCH 30/39] 8005629: javac warnings compiling java.awt.EventDispatchThread and sun.awt.X11.XIconWindow Removed macosx specific workaround from shared code and made macosx use public API Reviewed-by: art, serb --- .../classes/sun/lwawt/macosx/CPrinterJob.java | 36 +++++++++++++---- .../sun/lwawt/macosx/EventDispatchAccess.java | 39 ------------------- jdk/src/macosx/native/sun/awt/CPrinterJob.m | 25 ------------ .../classes/java/awt/EventDispatchThread.java | 28 ------------- .../classes/sun/awt/X11/XIconWindow.java | 2 +- 5 files changed, 30 insertions(+), 100 deletions(-) delete mode 100644 jdk/src/macosx/classes/sun/lwawt/macosx/EventDispatchAccess.java diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java b/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java index 56f5ac7ecc6..791182c1565 100644 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java +++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CPrinterJob.java @@ -30,6 +30,8 @@ import java.awt.*; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.awt.print.*; +import java.security.AccessController; +import java.security.PrivilegedAction; import javax.print.*; import javax.print.attribute.PrintRequestAttributeSet; @@ -47,6 +49,8 @@ public class CPrinterJob extends RasterPrinterJob { private static String sShouldNotReachHere = "Should not reach here."; + private volatile SecondaryLoop printingLoop; + private boolean noDefaultPrinter = false; private static Font defaultFont; @@ -160,11 +164,22 @@ public class CPrinterJob extends RasterPrinterJob { volatile boolean onEventThread; + @Override + protected void cancelDoc() throws PrinterAbortException { + super.cancelDoc(); + if (printingLoop != null) { + printingLoop.exit(); + } + } + private void completePrintLoop() { Runnable r = new Runnable() { public void run() { synchronized(this) { performingPrinting = false; } + if (printingLoop != null) { + printingLoop.exit(); + } }}; if (onEventThread) { @@ -219,17 +234,21 @@ public class CPrinterJob extends RasterPrinterJob { onEventThread = true; + printingLoop = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public SecondaryLoop run() { + return Toolkit.getDefaultToolkit() + .getSystemEventQueue() + .createSecondaryLoop(); + } + }); + try { // Fire off the print rendering loop on the AppKit thread, and don't have // it wait and block this thread. if (printLoop(false, firstPage, lastPage)) { - // Fire off the EventConditional that will what until the condition is met, - // but will still process AWTEvent's as they occur. - new EventDispatchAccess() { - public boolean evaluate() { - return performingPrinting; - } - }.pumpEventsAndWait(); + // Start a secondary loop on EDT until printing operation is finished or cancelled + printingLoop.enter(); } } catch (Exception e) { e.printStackTrace(); @@ -253,6 +272,9 @@ public class CPrinterJob extends RasterPrinterJob { performingPrinting = false; notify(); } + if (printingLoop != null) { + printingLoop.exit(); + } } // Normalize the collated, # copies, numPages, first/last pages. Need to diff --git a/jdk/src/macosx/classes/sun/lwawt/macosx/EventDispatchAccess.java b/jdk/src/macosx/classes/sun/lwawt/macosx/EventDispatchAccess.java deleted file mode 100644 index 1124d123757..00000000000 --- a/jdk/src/macosx/classes/sun/lwawt/macosx/EventDispatchAccess.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2011, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package sun.lwawt.macosx; - -// This exists strictly to work around the fact that java.awt.Conditional isn't a public class. -// It uses java reflection to get the EventDispatchThread class and call a MacOSX only -// method on it. -// -// NOTE: This uses reflection in its implementation, so it is not for performance critical code. -// -// See java.awt.EventDispatchThread and apple.awt.CPrintJob for more. -// -public abstract class EventDispatchAccess { - public native void pumpEventsAndWait(); - public abstract boolean evaluate(); -} diff --git a/jdk/src/macosx/native/sun/awt/CPrinterJob.m b/jdk/src/macosx/native/sun/awt/CPrinterJob.m index 52976f31d26..3935240ff78 100644 --- a/jdk/src/macosx/native/sun/awt/CPrinterJob.m +++ b/jdk/src/macosx/native/sun/awt/CPrinterJob.m @@ -383,31 +383,6 @@ static void javaPrinterJobToNSPrintInfo(JNIEnv* env, jobject srcPrinterJob, jobj } } -/* - * Class: sun_lwawt_macosx_EventDispatchAccess - * Method: pumpEventsAndWait - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_lwawt_macosx_EventDispatchAccess_pumpEventsAndWait -(JNIEnv *env, jobject eda) -{ - static JNF_CLASS_CACHE(jc_Thread, "java/lang/Thread"); - static JNF_STATIC_MEMBER_CACHE(jm_currentThread, jc_Thread, "currentThread", "()Ljava/lang/Thread;"); - static JNF_CLASS_CACHE(jc_EventDispatchThread, "java/awt/EventDispatchThread"); - static JNF_MEMBER_CACHE(jm_macosxGetConditional, jc_EventDispatchThread, "_macosxGetConditional", "(Ljava/lang/Object;)Ljava/awt/Conditional;"); - static JNF_MEMBER_CACHE(jm_pumpEvents, jc_EventDispatchThread, "pumpEvents", "(Ljava/awt/Conditional;)V"); - -JNF_COCOA_DURING(env); - - jobject thread = JNFCallStaticObjectMethod(env, jm_currentThread); - jobject conditional = JNFCallObjectMethod(env, thread, jm_macosxGetConditional, eda); - if (conditional != NULL) { - JNFCallVoidMethod(env, thread, jm_pumpEvents, conditional); - } - -JNF_COCOA_HANDLE(env); -} - /* * Class: sun_lwawt_macosx_CPrinterJob * Method: abortDoc diff --git a/jdk/src/share/classes/java/awt/EventDispatchThread.java b/jdk/src/share/classes/java/awt/EventDispatchThread.java index 427ad7efeb7..c707f02abdb 100644 --- a/jdk/src/share/classes/java/awt/EventDispatchThread.java +++ b/jdk/src/share/classes/java/awt/EventDispatchThread.java @@ -107,34 +107,6 @@ class EventDispatchThread extends Thread { } } - // MacOSX change: - // This was added because this class (and java.awt.Conditional) are package private. - // There are certain instances where classes in other packages need to block the - // AWTEventQueue while still allowing it to process events. This uses reflection - // to call back into the caller in order to remove dependencies. - // - // NOTE: This uses reflection in its implementation, so it is not for performance critical code. - // - // cond is an instance of sun.lwawt.macosx.EventDispatchAccess - // - private Conditional _macosxGetConditional(final Object cond) { - try { - return new Conditional() { - final Method evaluateMethod = Class.forName("sun.lwawt.macosx.EventDispatchAccess").getMethod("evaluate", null); - public boolean evaluate() { - try { - return ((Boolean)evaluateMethod.invoke(cond, null)).booleanValue(); - } catch (Exception e) { - return false; - } - } - }; - } catch (Exception e) { - return new Conditional() { public boolean evaluate() { return false; } }; - } - } - - void pumpEvents(Conditional cond) { pumpEvents(ANY_EVENT, cond); } diff --git a/jdk/src/solaris/classes/sun/awt/X11/XIconWindow.java b/jdk/src/solaris/classes/sun/awt/X11/XIconWindow.java index 1d0e55d31ef..bf521db3b72 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XIconWindow.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XIconWindow.java @@ -92,7 +92,7 @@ public class XIconWindow extends XBaseWindow { } XIconSize[] sizeList = getIconSizes(); - log.finest("Icon sizes: {0}", sizeList); + log.finest("Icon sizes: {0}", (Object[]) sizeList); if (sizeList == null) { // No icon sizes so we simply fall back to 16x16 return new Dimension(16, 16); From 3d55cc1e02cd93a83c24f0426f6a9fcaa3089c0a Mon Sep 17 00:00:00 2001 From: Vinnie Ryan Date: Wed, 13 Feb 2013 16:01:26 +0000 Subject: [PATCH 31/39] 8007934: algorithm parameters for PBE Scheme 2 not decoded correctly in PKCS12 keystore Reviewed-by: mullan --- .../sun/security/pkcs12/PKCS12KeyStore.java | 49 ++++++---- jdk/test/java/security/KeyStore/PBETest.java | 95 +++++++++++++++---- 2 files changed, 111 insertions(+), 33 deletions(-) diff --git a/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index d40e033d9f0..32f1da53afa 100644 --- a/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/jdk/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -326,7 +326,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { DerValue val = new DerValue(encrInfo.getAlgorithm().encode()); DerInputStream in = val.toDerInputStream(); algOid = in.getOID(); - algParams = parseAlgParameters(in); + algParams = parseAlgParameters(algOid, in); } catch (IOException ioe) { UnrecoverableKeyException uke = @@ -342,7 +342,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi { try { // Use JCE SecretKey skey = getPBEKey(password); - Cipher cipher = Cipher.getInstance(algOid.toString()); + Cipher cipher = Cipher.getInstance( + mapPBEParamsToAlgorithm(algOid, algParams)); cipher.init(Cipher.DECRYPT_MODE, skey, algParams); keyInfo = cipher.doFinal(encryptedKey); break; @@ -759,8 +760,8 @@ public final class PKCS12KeyStore extends KeyStoreSpi { /* * parse Algorithm Parameters */ - private AlgorithmParameters parseAlgParameters(DerInputStream in) - throws IOException + private AlgorithmParameters parseAlgParameters(ObjectIdentifier algorithm, + DerInputStream in) throws IOException { AlgorithmParameters algParams = null; try { @@ -774,7 +775,11 @@ public final class PKCS12KeyStore extends KeyStoreSpi { } } if (params != null) { - algParams = AlgorithmParameters.getInstance("PBE"); + if (algorithm.equals(pbes2_OID)) { + algParams = AlgorithmParameters.getInstance("PBES2"); + } else { + algParams = AlgorithmParameters.getInstance("PBE"); + } algParams.init(params.toByteArray()); } } catch (Exception e) { @@ -834,13 +839,6 @@ public final class PKCS12KeyStore extends KeyStoreSpi { } else { algParams = getAlgorithmParameters(algorithm); } - ObjectIdentifier pbeOID = mapPBEAlgorithmToOID(algorithm); - if (pbeOID != null) { - algid = new AlgorithmId(pbeOID, algParams); - } else { - throw new IOException("PBE algorithm '" + algorithm + - " 'is not supported for key entry protection"); - } } else { // Check default key protection algorithm for PKCS12 keystores algorithm = AccessController.doPrivileged( @@ -856,12 +854,16 @@ public final class PKCS12KeyStore extends KeyStoreSpi { return prop; } }); - if (algorithm == null) { + if (algorithm == null || algorithm.isEmpty()) { algorithm = "PBEWithSHA1AndDESede"; } algParams = getAlgorithmParameters(algorithm); - algid = new AlgorithmId(pbeWithSHAAnd3KeyTripleDESCBC_OID, - algParams); + } + + ObjectIdentifier pbeOID = mapPBEAlgorithmToOID(algorithm); + if (pbeOID == null) { + throw new IOException("PBE algorithm '" + algorithm + + " 'is not supported for key entry protection"); } // Use JCE @@ -869,6 +871,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE, skey, algParams); byte[] encryptedKey = cipher.doFinal(data); + algid = new AlgorithmId(pbeOID, cipher.getParameters()); if (debug != null) { debug.println(" (Cipher algorithm: " + cipher.getAlgorithm() + @@ -894,7 +897,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { /* * Map a PBE algorithm name onto its object identifier */ - private ObjectIdentifier mapPBEAlgorithmToOID(String algorithm) + private static ObjectIdentifier mapPBEAlgorithmToOID(String algorithm) throws NoSuchAlgorithmException { // Check for PBES2 algorithms if (algorithm.toLowerCase().startsWith("pbewithhmacsha")) { @@ -903,6 +906,18 @@ public final class PKCS12KeyStore extends KeyStoreSpi { return AlgorithmId.get(algorithm).getOID(); } + /* + * Map a PBE algorithm parameters onto its algorithm name + */ + private static String mapPBEParamsToAlgorithm(ObjectIdentifier algorithm, + AlgorithmParameters algParams) throws NoSuchAlgorithmException { + // Check for PBES2 algorithms + if (algorithm.equals(pbes2_OID) && algParams != null) { + return algParams.toString(); + } + return algorithm.toString(); + } + /** * Assigns the given certificate to the given alias. * @@ -1933,7 +1948,7 @@ public final class PKCS12KeyStore extends KeyStoreSpi { // parse Algorithm parameters DerInputStream in = seq[1].toDerInputStream(); ObjectIdentifier algOid = in.getOID(); - AlgorithmParameters algParams = parseAlgParameters(in); + AlgorithmParameters algParams = parseAlgParameters(algOid, in); while (true) { try { diff --git a/jdk/test/java/security/KeyStore/PBETest.java b/jdk/test/java/security/KeyStore/PBETest.java index 2186165ea68..671e001a876 100644 --- a/jdk/test/java/security/KeyStore/PBETest.java +++ b/jdk/test/java/security/KeyStore/PBETest.java @@ -29,6 +29,7 @@ import java.io.*; import java.security.*; +import javax.crypto.*; import javax.crypto.spec.*; // Retrieve a keystore entry, protected by the default encryption algorithm. @@ -36,13 +37,20 @@ import javax.crypto.spec.*; public class PBETest { private final static String DIR = System.getProperty("test.src", "."); - //private static final String PBE_ALGO = "PBEWithHmacSHA1AndAES_128"; - private static final String PBE_ALGO = "PBEWithSHA1AndDESede"; + private final static String KEY_PROTECTION_PROPERTY = + "keystore.PKCS12.keyProtectionAlgorithm"; + private static final String[] PBE_ALGOS = { + "PBEWithSHA1AndDESede", + "PBEWithHmacSHA1AndAES_128", + "PBEWithHmacSHA224AndAES_128", + "PBEWithHmacSHA256AndAES_128", + "PBEWithHmacSHA384AndAES_128", + "PBEWithHmacSHA512AndAES_128" + }; private static final char[] PASSWORD = "passphrase".toCharArray(); private static final String KEYSTORE_TYPE = "JKS"; private static final String KEYSTORE = DIR + "/keystore.jks"; private static final String NEW_KEYSTORE_TYPE = "PKCS12"; - private static final String NEW_KEYSTORE = PBE_ALGO + ".p12"; private static final String ALIAS = "vajra"; private static final byte[] IV = { @@ -55,32 +63,87 @@ public class PBETest { private static final int ITERATION_COUNT = 1024; public static void main(String[] args) throws Exception { + for (String algo : PBE_ALGOS) { + String filename = algo + ".p12"; + main0(algo, filename, true); + main0(algo, filename, false); + Security.setProperty(KEY_PROTECTION_PROPERTY, algo); + main0(null, "PBE.p12", false); + Security.setProperty(KEY_PROTECTION_PROPERTY, ""); + } + main0(null, "default.p12", false); // default algorithm + } - new File(NEW_KEYSTORE).delete(); + private static void main0(String algo, String filename, boolean useParams) + throws Exception { KeyStore keystore = load(KEYSTORE_TYPE, KEYSTORE, PASSWORD); KeyStore.Entry entry = keystore.getEntry(ALIAS, new KeyStore.PasswordProtection(PASSWORD)); - System.out.println("Retrieved entry named '" + ALIAS + "'"); + System.out.println("Retrieved key entry named '" + ALIAS + "'"); + Key originalKey = null; + if (entry instanceof KeyStore.PrivateKeyEntry) { + originalKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey(); + } else if (entry instanceof KeyStore.SecretKeyEntry) { + originalKey = ((KeyStore.SecretKeyEntry) entry).getSecretKey(); + } // Set entry KeyStore keystore2 = load(NEW_KEYSTORE_TYPE, null, null); - keystore2.setEntry(ALIAS, entry, - new KeyStore.PasswordProtection(PASSWORD, PBE_ALGO, - new PBEParameterSpec(SALT, ITERATION_COUNT, - new IvParameterSpec(IV)))); - System.out.println("Encrypted entry using: " + PBE_ALGO); + if (useParams) { + keystore2.setEntry(ALIAS, entry, + new KeyStore.PasswordProtection(PASSWORD, algo, + new PBEParameterSpec(SALT, ITERATION_COUNT, + new IvParameterSpec(IV)))); + System.out.println("Encrypted key entry using: " + algo + + " (with PBE parameters)"); + } else if (algo != null) { + keystore2.setEntry(ALIAS, entry, + new KeyStore.PasswordProtection(PASSWORD, algo, null)); + System.out.println("Encrypted key entry using: " + algo + + " (without PBE parameters)"); + } else { + keystore2.setEntry(ALIAS, entry, + new KeyStore.PasswordProtection(PASSWORD)); + String prop = Security.getProperty(KEY_PROTECTION_PROPERTY); + if (prop == null || prop.isEmpty()) { + System.out.println("Encrypted key entry using: " + + "default PKCS12 key protection algorithm"); + } else { + System.out.println("Encrypted key entry using: " + + "keyProtectionAlgorithm=" + prop); + } + } - try (FileOutputStream outStream = new FileOutputStream(NEW_KEYSTORE)) { - System.out.println("Storing keystore to: " + NEW_KEYSTORE); + try (FileOutputStream outStream = new FileOutputStream(filename)) { + System.out.println("Storing keystore to: " + filename); keystore2.store(outStream, PASSWORD); } - keystore2 = load(NEW_KEYSTORE_TYPE, NEW_KEYSTORE, PASSWORD); - entry = keystore2.getEntry(ALIAS, - new KeyStore.PasswordProtection(PASSWORD)); - System.out.println("Retrieved entry named '" + ALIAS + "'"); + try { + keystore2 = load(NEW_KEYSTORE_TYPE, filename, PASSWORD); + entry = keystore2.getEntry(ALIAS, + new KeyStore.PasswordProtection(PASSWORD)); + Key key; + if (entry instanceof KeyStore.PrivateKeyEntry) { + key = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey(); + } else if (entry instanceof KeyStore.SecretKeyEntry) { + key = ((KeyStore.SecretKeyEntry) entry).getSecretKey(); + } else { + throw new Exception("Failed to retrieve key entry"); + } + if (originalKey.equals(key)) { + System.out.println("Retrieved key entry named '" + ALIAS + "'"); + System.out.println(); + } else { + throw new Exception( + "Failed: recovered key does not match the original key"); + } + + } finally { + new File(filename).delete(); + } } private static KeyStore load(String type, String path, char[] password) From 403e23ec706a8840ca0b51f759383e61c1174356 Mon Sep 17 00:00:00 2001 From: Dmitry Samersoff Date: Wed, 13 Feb 2013 21:06:30 +0400 Subject: [PATCH 32/39] 8008095: TEST_BUG: JDK-8002048 one more testcase failure on Solaris Fixed couple of more Solaris shell incompatibilities Reviewed-by: chegar --- jdk/test/sun/management/jdp/JdpTest.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jdk/test/sun/management/jdp/JdpTest.sh b/jdk/test/sun/management/jdp/JdpTest.sh index b92f6e9d0d3..dfdea7c1938 100644 --- a/jdk/test/sun/management/jdp/JdpTest.sh +++ b/jdk/test/sun/management/jdp/JdpTest.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -x # Copyright (c) 2011, 2012 Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -51,7 +51,7 @@ _do_compile(){ # sun.* packages is not included to symbol file lib/ct.sym so we have # to ignore it - if [ ! -f ${_testclasses} ] + if [ ! -d ${_testclasses} ] then mkdir -p ${_testclasses} fi @@ -295,12 +295,12 @@ do esac done -if [ ${_compile} = "yes" ] +if [ "${_compile}" = "yes" ] then _do_compile fi -if [ ${_jtreg} = "yes" ] +if [ "${_jtreg}" = "yes" ] then _testclasses=${TESTCLASSES} _testsrc=${TESTSRC} @@ -309,7 +309,7 @@ fi # Make sure _tesclasses is absolute path tt=`echo ${_testclasses} | sed -e 's,/,,'` -if [ ${tt} = ${_testclasses} ] +if [ "${tt}" = "${_testclasses}" ] then _testclasses="${_pwd}/${_testclasses}" fi @@ -319,7 +319,7 @@ _policyname="${_testclasses}/policy" rm -f ${_logname} rm -f ${_policyname} -if [ -e ${_testsrc}/policy.tpl ] +if [ -f ${_testsrc}/policy.tpl ] then cat ${_testsrc}/policy.tpl | \ From 8f58ebc26139f8ac32660be3486467111ba6d209 Mon Sep 17 00:00:00 2001 From: Vinnie Ryan Date: Wed, 13 Feb 2013 19:40:51 +0000 Subject: [PATCH 33/39] 8007755: Support the logical grouping of keystores Reviewed-by: mullan --- .../share/classes/java/security/KeyStore.java | 144 +++ .../sun/security/provider/DomainKeyStore.java | 900 ++++++++++++++++++ .../sun/security/provider/PolicyParser.java | 213 ++++- .../classes/sun/security/provider/Sun.java | 7 +- .../sun/security/provider/SunEntries.java | 1 + .../classes/sun/security/util/Resources.java | 2 + .../security/provider/KeyStore/DKSTest.java | 203 ++++ .../sun/security/provider/KeyStore/DKSTest.sh | 84 ++ .../security/provider/KeyStore/domains.cfg | 65 ++ .../security/tools/keytool/AltProviderPath.sh | 10 +- .../security/tools/keytool/DummyProvider.java | 2 +- 11 files changed, 1614 insertions(+), 17 deletions(-) create mode 100644 jdk/src/share/classes/sun/security/provider/DomainKeyStore.java create mode 100644 jdk/test/sun/security/provider/KeyStore/DKSTest.java create mode 100644 jdk/test/sun/security/provider/KeyStore/DKSTest.sh create mode 100644 jdk/test/sun/security/provider/KeyStore/domains.cfg diff --git a/jdk/src/share/classes/java/security/KeyStore.java b/jdk/src/share/classes/java/security/KeyStore.java index 96565684b0e..75d405771a7 100644 --- a/jdk/src/share/classes/java/security/KeyStore.java +++ b/jdk/src/share/classes/java/security/KeyStore.java @@ -218,6 +218,150 @@ public class KeyStore { public ProtectionParameter getProtectionParameter(); } + /** + * Configuration data that specifies the keystores in a keystore domain. + * A keystore domain is a collection of keystores that are presented as a + * single logical keystore. The configuration data is used during + * {@code KeyStore} + * {@link #load(KeyStore.LoadStoreParameter) load} and + * {@link #store(KeyStore.LoadStoreParameter) store} operations. + *

    + * The following syntax is supported for configuration data: + *

    +     *
    +     *     domain  [ ...] {
    +     *         keystore  [ ...] ;
    +     *         ...
    +     *     };
    +     *     ...
    +     *
    +     * 
    + * where {@code domainName} and {@code keystoreName} are identifiers + * and {@code property} is a key/value pairing. The key and value are + * separated by an 'equals' symbol and the value is enclosed in double + * quotes. A property value may be either a printable string or a binary + * string of colon-separated pairs of hexadecimal digits. Multi-valued + * properties are represented as a comma-separated list of values, + * enclosed in square brackets. + * See {@link Arrays#toString(java.lang.Object[])}. + *

    + * To ensure that keystore entries are uniquely identified, each + * entry's alias is prefixed by its {@code keystoreName} followed + * by the entry name separator and each {@code keystoreName} must be + * unique within its domain. Entry name prefixes are omitted when + * storing a keystore. + *

    + * Properties are context-sensitive: properties that apply to + * all the keystores in a domain are located in the domain clause, + * and properties that apply only to a specific keystore are located + * in that keystore's clause. + * Unless otherwise specified, a property in a keystore clause overrides + * a property of the same name in the domain clause. All property names + * are case-insensitive. The following properties are supported: + *

    + *
    {@code keystoreType=""}
    + *
    The keystore type.
    + *
    {@code keystoreURI=""}
    + *
    The keystore location.
    + *
    {@code keystoreProviderName=""}
    + *
    The name of the keystore's JCE provider.
    + *
    {@code keystorePasswordEnv=""}
    + *
    The environment variable that stores a keystore password. + * Alternatively, passwords may be supplied to the constructor + * method in a {@code Map}.
    + *
    {@code entryNameSeparator=""}
    + *
    The separator between a keystore name prefix and an entry name. + * When specified, it applies to all the entries in a domain. + * Its default value is a space.
    + *
    + *

    + * For example, configuration data for a simple keystore domain + * comprising three keystores is shown below: + *

    +     *
    +     * domain app1 {
    +     *     keystore app1-truststore
    +     *         keystoreURI="file:///app1/etc/truststore.jks"
    +     *
    +     *     keystore system-truststore
    +     *         keystoreURI="${java.home}/lib/security/cacerts"
    +     *
    +     *     keystore app1-keystore
    +     *         keystoreType="PKCS12"
    +     *         keystoreURI="file:///app1/etc/keystore.p12"
    +     * };
    +     *
    +     * 
    + * @since 1.8 + */ + public static final class DomainLoadStoreParameter + implements LoadStoreParameter { + + private final URI configuration; + private final Map protectionParams; + + /** + * Constructs a DomainLoadStoreParameter for a keystore domain with + * the parameters used to protect keystore data. + * + * @param configuration identifier for the domain configuration data. + * The name of the target domain should be specified in the + * {@code java.net.URI} fragment component when it is necessary + * to distinguish between several domain configurations at the + * same location. + * + * @param protectionParams the map from keystore name to the parameter + * used to protect keystore data. + * A {@code java.util.Collections.EMPTY_MAP} should be used + * when protection parameters are not required or when they have + * been specified by properties in the domain configuration data. + * It is cloned to prevent subsequent modification. + * + * @exception NullPointerExcetion if {@code configuration} or + * {@code protectionParams} is {@code null} + */ + public DomainLoadStoreParameter(URI configuration, + Map protectionParams) { + if (configuration == null || protectionParams == null) { + throw new NullPointerException("invalid null input"); + } + this.configuration = configuration; + this.protectionParams = + Collections.unmodifiableMap(new HashMap<>(protectionParams)); + } + + /** + * Gets the identifier for the domain configuration data. + * + * @return the identifier for the configuration data + */ + public URI getConfiguration() { + return configuration; + } + + /** + * Gets the keystore protection parameters for keystores in this + * domain. + * + * @return an unmodifiable map of keystore names to protection + * parameters + */ + public Map getProtectionParams() { + return protectionParams; + } + + /** + * Gets the keystore protection parameters for this domain. + * Keystore domains do not support a protection parameter. + * + * @return always returns {@code null} + */ + @Override + public KeyStore.ProtectionParameter getProtectionParameter() { + return null; + } + } + /** * A marker interface for keystore protection parameters. * diff --git a/jdk/src/share/classes/sun/security/provider/DomainKeyStore.java b/jdk/src/share/classes/sun/security/provider/DomainKeyStore.java new file mode 100644 index 00000000000..ae0dbfb067c --- /dev/null +++ b/jdk/src/share/classes/sun/security/provider/DomainKeyStore.java @@ -0,0 +1,900 @@ +/* + * Copyright (c) 2013, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.security.provider; + +import java.io.*; +import java.net.*; +import java.security.*; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateException; +import java.util.*; + +import sun.misc.IOUtils; +import sun.security.pkcs.EncryptedPrivateKeyInfo; +import sun.security.util.PolicyUtil; + +/** + * This class provides the domain keystore type identified as "DKS". + * DKS presents a collection of separate keystores as a single logical keystore. + * The collection of keystores is specified in a domain configuration file which + * is passed to DKS in a {@link KeyStore.DomainLoadStoreParameter}. + *

    + * The following properties are supported: + *

    + *
    {@code keystoreType=""}
    + *
    The keystore type.
    + *
    {@code keystoreURI=""}
    + *
    The keystore location.
    + *
    {@code keystoreProviderName=""}
    + *
    The name of the keystore's JCE provider.
    + *
    {@code keystorePasswordEnv=""}
    + *
    The environment variable that stores a keystore password. + *
    {@code entryNameSeparator=""}
    + *
    The separator between a keystore name prefix and an entry name. + * When specified, it applies to all the entries in a domain. + * Its default value is a space.
    + *
    + * + * @since 1.8 + */ + +abstract class DomainKeyStore extends KeyStoreSpi { + + // regular DKS + public static final class DKS extends DomainKeyStore { + String convertAlias(String alias) { + return alias.toLowerCase(Locale.ENGLISH); + } + } + + // DKS property names + private static final String ENTRY_NAME_SEPARATOR = "entrynameseparator"; + private static final String KEYSTORE_PROVIDER_NAME = "keystoreprovidername"; + private static final String KEYSTORE_TYPE = "keystoretype"; + private static final String KEYSTORE_URI = "keystoreuri"; + private static final String KEYSTORE_PASSWORD_ENV = "keystorepasswordenv"; + + // RegEx meta characters + private static final String REGEX_META = ".$|()[{^?*+\\"; + + // Default prefix for keystores loaded-by-stream + private static final String DEFAULT_STREAM_PREFIX = "iostream"; + private int streamCounter = 1; + private String entryNameSeparator = " "; + private String entryNameSeparatorRegEx = " "; + + // Default keystore type + private static final String DEFAULT_KEYSTORE_TYPE = + KeyStore.getDefaultType(); + + // Domain keystores + private final Map keystores = new HashMap<>(); + + DomainKeyStore() { + } + + // convert an alias to internal form, overridden in subclasses: + // lower case for regular DKS + abstract String convertAlias(String alias); + + /** + * Returns the key associated with the given alias, using the given + * password to recover it. + * + * @param alias the alias name + * @param password the password for recovering the key + * + * @return the requested key, or null if the given alias does not exist + * or does not identify a key entry. + * + * @exception NoSuchAlgorithmException if the algorithm for recovering the + * key cannot be found + * @exception UnrecoverableKeyException if the key cannot be recovered + * (e.g., the given password is wrong). + */ + public Key engineGetKey(String alias, char[] password) + throws NoSuchAlgorithmException, UnrecoverableKeyException + { + AbstractMap.SimpleEntry> pair = + getKeystoresForReading(alias); + Key key = null; + + try { + String entryAlias = pair.getKey(); + for (KeyStore keystore : pair.getValue()) { + key = keystore.getKey(entryAlias, password); + if (key != null) { + break; + } + } + } catch (KeyStoreException e) { + throw new IllegalStateException(e); + } + + return key; + } + + /** + * Returns the certificate chain associated with the given alias. + * + * @param alias the alias name + * + * @return the certificate chain (ordered with the user's certificate first + * and the root certificate authority last), or null if the given alias + * does not exist or does not contain a certificate chain (i.e., the given + * alias identifies either a trusted certificate entry or a + * key entry without a certificate chain). + */ + public Certificate[] engineGetCertificateChain(String alias) { + + AbstractMap.SimpleEntry> pair = + getKeystoresForReading(alias); + Certificate[] chain = null; + + try { + String entryAlias = pair.getKey(); + for (KeyStore keystore : pair.getValue()) { + chain = keystore.getCertificateChain(entryAlias); + if (chain != null) { + break; + } + } + } catch (KeyStoreException e) { + throw new IllegalStateException(e); + } + + return chain; + } + + /** + * Returns the certificate associated with the given alias. + * + *

    If the given alias name identifies a + * trusted certificate entry, the certificate associated with that + * entry is returned. If the given alias name identifies a + * key entry, the first element of the certificate chain of that + * entry is returned, or null if that entry does not have a certificate + * chain. + * + * @param alias the alias name + * + * @return the certificate, or null if the given alias does not exist or + * does not contain a certificate. + */ + public Certificate engineGetCertificate(String alias) { + + AbstractMap.SimpleEntry> pair = + getKeystoresForReading(alias); + Certificate cert = null; + + try { + String entryAlias = pair.getKey(); + for (KeyStore keystore : pair.getValue()) { + cert = keystore.getCertificate(entryAlias); + if (cert != null) { + break; + } + } + } catch (KeyStoreException e) { + throw new IllegalStateException(e); + } + + return cert; + } + + /** + * Returns the creation date of the entry identified by the given alias. + * + * @param alias the alias name + * + * @return the creation date of this entry, or null if the given alias does + * not exist + */ + public Date engineGetCreationDate(String alias) { + + AbstractMap.SimpleEntry> pair = + getKeystoresForReading(alias); + Date date = null; + + try { + String entryAlias = pair.getKey(); + for (KeyStore keystore : pair.getValue()) { + date = keystore.getCreationDate(entryAlias); + if (date != null) { + break; + } + } + } catch (KeyStoreException e) { + throw new IllegalStateException(e); + } + + return date; + } + + /** + * Assigns the given private key to the given alias, protecting + * it with the given password as defined in PKCS8. + * + *

    The given java.security.PrivateKey key must + * be accompanied by a certificate chain certifying the + * corresponding public key. + * + *

    If the given alias already exists, the keystore information + * associated with it is overridden by the given key and certificate + * chain. + * + * @param alias the alias name + * @param key the private key to be associated with the alias + * @param password the password to protect the key + * @param chain the certificate chain for the corresponding public + * key (only required if the given key is of type + * java.security.PrivateKey). + * + * @exception KeyStoreException if the given key is not a private key, + * cannot be protected, or this operation fails for some other reason + */ + public void engineSetKeyEntry(String alias, Key key, char[] password, + Certificate[] chain) + throws KeyStoreException + { + AbstractMap.SimpleEntry> pair = + getKeystoreForWriting(alias); + + if (pair == null) { + throw new KeyStoreException("Error setting key entry for '" + + alias + "'"); + } + String entryAlias = pair.getKey(); + Map.Entry keystore = pair.getValue(); + keystore.getValue().setKeyEntry(entryAlias, key, password, chain); + } + + /** + * Assigns the given key (that has already been protected) to the given + * alias. + * + *

    If the protected key is of type + * java.security.PrivateKey, it must be accompanied by a + * certificate chain certifying the corresponding public key. If the + * underlying keystore implementation is of type jks, + * key must be encoded as an + * EncryptedPrivateKeyInfo as defined in the PKCS #8 standard. + * + *

    If the given alias already exists, the keystore information + * associated with it is overridden by the given key (and possibly + * certificate chain). + * + * @param alias the alias name + * @param key the key (in protected format) to be associated with the alias + * @param chain the certificate chain for the corresponding public + * key (only useful if the protected key is of type + * java.security.PrivateKey). + * + * @exception KeyStoreException if this operation fails. + */ + public void engineSetKeyEntry(String alias, byte[] key, + Certificate[] chain) + throws KeyStoreException + { + AbstractMap.SimpleEntry> pair = + getKeystoreForWriting(alias); + + if (pair == null) { + throw new KeyStoreException( + "Error setting protected key entry for '" + alias + "'"); + } + String entryAlias = pair.getKey(); + Map.Entry keystore = pair.getValue(); + keystore.getValue().setKeyEntry(entryAlias, key, chain); + } + + /** + * Assigns the given certificate to the given alias. + * + *

    If the given alias already exists in this keystore and identifies a + * trusted certificate entry, the certificate associated with it is + * overridden by the given certificate. + * + * @param alias the alias name + * @param cert the certificate + * + * @exception KeyStoreException if the given alias already exists and does + * not identify a trusted certificate entry, or this operation + * fails for some other reason. + */ + public void engineSetCertificateEntry(String alias, Certificate cert) + throws KeyStoreException + { + AbstractMap.SimpleEntry> pair = + getKeystoreForWriting(alias); + + if (pair == null) { + throw new KeyStoreException("Error setting certificate entry for '" + + alias + "'"); + } + String entryAlias = pair.getKey(); + Map.Entry keystore = pair.getValue(); + keystore.getValue().setCertificateEntry(entryAlias, cert); + } + + /** + * Deletes the entry identified by the given alias from this keystore. + * + * @param alias the alias name + * + * @exception KeyStoreException if the entry cannot be removed. + */ + public void engineDeleteEntry(String alias) throws KeyStoreException + { + AbstractMap.SimpleEntry> pair = + getKeystoreForWriting(alias); + + if (pair == null) { + throw new KeyStoreException("Error deleting entry for '" + alias + + "'"); + } + String entryAlias = pair.getKey(); + Map.Entry keystore = pair.getValue(); + keystore.getValue().deleteEntry(entryAlias); + } + + /** + * Lists all the alias names of this keystore. + * + * @return enumeration of the alias names + */ + public Enumeration engineAliases() { + final Iterator> iterator = + keystores.entrySet().iterator(); + + return new Enumeration() { + private int index = 0; + private Map.Entry keystoresEntry = null; + private String prefix = null; + private Enumeration aliases = null; + + public boolean hasMoreElements() { + try { + if (aliases == null) { + if (iterator.hasNext()) { + keystoresEntry = iterator.next(); + prefix = keystoresEntry.getKey() + + entryNameSeparator; + aliases = keystoresEntry.getValue().aliases(); + } else { + return false; + } + } + if (aliases.hasMoreElements()) { + return true; + } else { + if (iterator.hasNext()) { + keystoresEntry = iterator.next(); + prefix = keystoresEntry.getKey() + + entryNameSeparator; + aliases = keystoresEntry.getValue().aliases(); + } else { + return false; + } + } + } catch (KeyStoreException e) { + return false; + } + + return aliases.hasMoreElements(); + } + + public String nextElement() { + if (hasMoreElements()) { + return prefix + aliases.nextElement(); + } + throw new NoSuchElementException(); + } + }; + } + + /** + * Checks if the given alias exists in this keystore. + * + * @param alias the alias name + * + * @return true if the alias exists, false otherwise + */ + public boolean engineContainsAlias(String alias) { + + AbstractMap.SimpleEntry> pair = + getKeystoresForReading(alias); + + try { + String entryAlias = pair.getKey(); + for (KeyStore keystore : pair.getValue()) { + if (keystore.containsAlias(entryAlias)) { + return true; + } + } + } catch (KeyStoreException e) { + throw new IllegalStateException(e); + } + + return false; + } + + /** + * Retrieves the number of entries in this keystore. + * + * @return the number of entries in this keystore + */ + public int engineSize() { + + int size = 0; + try { + for (KeyStore keystore : keystores.values()) { + size += keystore.size(); + } + } catch (KeyStoreException e) { + throw new IllegalStateException(e); + } + + return size; + } + + /** + * Returns true if the entry identified by the given alias is a + * key entry, and false otherwise. + * + * @return true if the entry identified by the given alias is a + * key entry, false otherwise. + */ + public boolean engineIsKeyEntry(String alias) { + + AbstractMap.SimpleEntry> pair = + getKeystoresForReading(alias); + + try { + String entryAlias = pair.getKey(); + for (KeyStore keystore : pair.getValue()) { + if (keystore.isKeyEntry(entryAlias)) { + return true; + } + } + } catch (KeyStoreException e) { + throw new IllegalStateException(e); + } + + return false; + } + + /** + * Returns true if the entry identified by the given alias is a + * trusted certificate entry, and false otherwise. + * + * @return true if the entry identified by the given alias is a + * trusted certificate entry, false otherwise. + */ + public boolean engineIsCertificateEntry(String alias) { + + AbstractMap.SimpleEntry> pair = + getKeystoresForReading(alias); + + try { + String entryAlias = pair.getKey(); + for (KeyStore keystore : pair.getValue()) { + if (keystore.isCertificateEntry(entryAlias)) { + return true; + } + } + } catch (KeyStoreException e) { + throw new IllegalStateException(e); + } + + return false; + } + + /* + * Returns a keystore entry alias and a list of target keystores. + * When the supplied alias prefix identifies a keystore then that single + * keystore is returned. When no alias prefix is supplied then all the + * keystores are returned. + */ + private AbstractMap.SimpleEntry> + getKeystoresForReading(String alias) { + + String[] splits = alias.split(this.entryNameSeparatorRegEx, 2); + if (splits.length == 2) { // prefixed alias + KeyStore keystore = keystores.get(splits[0]); + if (keystore != null) { + return new AbstractMap.SimpleEntry<>(splits[1], + (Collection) Collections.singleton(keystore)); + } + } else if (splits.length == 1) { // unprefixed alias + // Check all keystores for the first occurrence of the alias + return new AbstractMap.SimpleEntry<>(alias, keystores.values()); + } + return new AbstractMap.SimpleEntry<>("", + (Collection) Collections.emptyList()); + } + + /* + * Returns a keystore entry alias and a single target keystore. + * An alias prefix must be supplied. + */ + private + AbstractMap.SimpleEntry> + getKeystoreForWriting(String alias) { + + String[] splits = alias.split(this.entryNameSeparator, 2); + if (splits.length == 2) { // prefixed alias + KeyStore keystore = keystores.get(splits[0]); + if (keystore != null) { + return new AbstractMap.SimpleEntry<>(splits[1], + new AbstractMap.SimpleEntry<>(splits[0], keystore)); + } + } + return null; + } + + /** + * Returns the (alias) name of the first keystore entry whose certificate + * matches the given certificate. + * + *

    This method attempts to match the given certificate with each + * keystore entry. If the entry being considered + * is a trusted certificate entry, the given certificate is + * compared to that entry's certificate. If the entry being considered is + * a key entry, the given certificate is compared to the first + * element of that entry's certificate chain (if a chain exists). + * + * @param cert the certificate to match with. + * + * @return the (alias) name of the first entry with matching certificate, + * or null if no such entry exists in this keystore. + */ + public String engineGetCertificateAlias(Certificate cert) { + + try { + + String alias = null; + for (KeyStore keystore : keystores.values()) { + if ((alias = keystore.getCertificateAlias(cert)) != null) { + break; + } + } + return alias; + + } catch (KeyStoreException e) { + throw new IllegalStateException(e); + } + } + + /** + * Stores this keystore to the given output stream, and protects its + * integrity with the given password. + * + * @param stream the output stream to which this keystore is written. + * @param password the password to generate the keystore integrity check + * + * @exception IOException if there was an I/O problem with data + * @exception NoSuchAlgorithmException if the appropriate data integrity + * algorithm could not be found + * @exception CertificateException if any of the certificates included in + * the keystore data could not be stored + */ + public void engineStore(OutputStream stream, char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException + { + // Support storing to a stream only when a single keystore has been + // configured + try { + if (keystores.size() == 1) { + keystores.values().iterator().next().store(stream, password); + return; + } + } catch (KeyStoreException e) { + throw new IllegalStateException(e); + } + + throw new UnsupportedOperationException( + "This keystore must be stored using a " + + "KeyStore.DomainLoadStoreParameter"); + } + + @Override + public void engineStore(KeyStore.LoadStoreParameter param) + throws IOException, NoSuchAlgorithmException, CertificateException + { + if (param instanceof KeyStore.DomainLoadStoreParameter) { + KeyStore.DomainLoadStoreParameter domainParameter = + (KeyStore.DomainLoadStoreParameter) param; + List builders = getBuilders( + domainParameter.getConfiguration(), + domainParameter.getProtectionParams()); + + for (KeyStoreBuilderComponents builder : builders) { + + try { + + KeyStore.ProtectionParameter pp = builder.protection; + if (!(pp instanceof KeyStore.PasswordProtection)) { + throw new KeyStoreException( + new IllegalArgumentException("ProtectionParameter" + + " must be a KeyStore.PasswordPartection")); + } + char[] password = + ((KeyStore.PasswordProtection) builder.protection) + .getPassword(); + + // Store the keystores + KeyStore keystore = keystores.get(builder.name); + keystore.store(new FileOutputStream(builder.file), + password); + + } catch (KeyStoreException e) { + throw new IOException(e); + } + } + } else { + throw new UnsupportedOperationException( + "This keystore must be stored using a " + + "KeyStore.DomainLoadStoreParameter"); + } + } + + /** + * Loads the keystore from the given input stream. + * + *

    If a password is given, it is used to check the integrity of the + * keystore data. Otherwise, the integrity of the keystore is not checked. + * + * @param stream the input stream from which the keystore is loaded + * @param password the (optional) password used to check the integrity of + * the keystore. + * + * @exception IOException if there is an I/O or format problem with the + * keystore data + * @exception NoSuchAlgorithmException if the algorithm used to check + * the integrity of the keystore cannot be found + * @exception CertificateException if any of the certificates in the + * keystore could not be loaded + */ + public void engineLoad(InputStream stream, char[] password) + throws IOException, NoSuchAlgorithmException, CertificateException + { + // Support loading from a stream only for a JKS or default type keystore + try { + KeyStore keystore = null; + + try { + keystore = KeyStore.getInstance("JKS"); + keystore.load(stream, password); + + } catch (Exception e) { + // Retry + if (!"JKS".equalsIgnoreCase(DEFAULT_KEYSTORE_TYPE)) { + keystore = KeyStore.getInstance(DEFAULT_KEYSTORE_TYPE); + keystore.load(stream, password); + } else { + throw e; + } + } + String keystoreName = DEFAULT_STREAM_PREFIX + streamCounter++; + keystores.put(keystoreName, keystore); + + } catch (Exception e) { + throw new UnsupportedOperationException( + "This keystore must be loaded using a " + + "KeyStore.DomainLoadStoreParameter"); + } + } + + @Override + public void engineLoad(KeyStore.LoadStoreParameter param) + throws IOException, NoSuchAlgorithmException, CertificateException + { + if (param instanceof KeyStore.DomainLoadStoreParameter) { + KeyStore.DomainLoadStoreParameter domainParameter = + (KeyStore.DomainLoadStoreParameter) param; + List builders = getBuilders( + domainParameter.getConfiguration(), + domainParameter.getProtectionParams()); + + for (KeyStoreBuilderComponents builder : builders) { + + try { + // Load the keystores (file-based and non-file-based) + if (builder.file != null) { + keystores.put(builder.name, + KeyStore.Builder.newInstance(builder.type, + builder.provider, builder.file, + builder.protection) + .getKeyStore()); + } else { + keystores.put(builder.name, + KeyStore.Builder.newInstance(builder.type, + builder.provider, builder.protection) + .getKeyStore()); + } + } catch (KeyStoreException e) { + throw new IOException(e); + } + } + } else { + throw new UnsupportedOperationException( + "This keystore must be loaded using a " + + "KeyStore.DomainLoadStoreParameter"); + } + } + + /* + * Parse a keystore domain configuration file and associated collection + * of keystore passwords to create a collection of KeyStore.Builder. + */ + private List getBuilders(URI configuration, + Map passwords) + throws IOException { + + PolicyParser parser = new PolicyParser(true); // expand properties + Collection domains = null; + List builders = new ArrayList<>(); + String uriDomain = configuration.getFragment(); + + try (InputStreamReader configurationReader = + new InputStreamReader( + PolicyUtil.getInputStream(configuration.toURL()), "UTF-8")) { + parser.read(configurationReader); + domains = parser.getDomainEntries(); + + } catch (MalformedURLException mue) { + throw new IOException(mue); + + } catch (PolicyParser.ParsingException pe) { + throw new IOException(pe); + } + + for (PolicyParser.DomainEntry domain : domains) { + Map domainProperties = domain.getProperties(); + + if (uriDomain != null && + (!uriDomain.equalsIgnoreCase(domain.getName()))) { + continue; // skip this domain + } + + if (domainProperties.containsKey(ENTRY_NAME_SEPARATOR)) { + this.entryNameSeparator = + domainProperties.get(ENTRY_NAME_SEPARATOR); + // escape any regex meta characters + char ch = 0; + StringBuilder s = new StringBuilder(); + for (int i = 0; i < this.entryNameSeparator.length(); i++) { + ch = this.entryNameSeparator.charAt(i); + if (REGEX_META.indexOf(ch) != -1) { + s.append('\\'); + } + s.append(ch); + } + this.entryNameSeparatorRegEx = s.toString(); + } + + Collection keystores = + domain.getEntries(); + for (PolicyParser.KeyStoreEntry keystore : keystores) { + String keystoreName = keystore.getName(); + Map properties = + new HashMap<>(domainProperties); + properties.putAll(keystore.getProperties()); + + String keystoreType = DEFAULT_KEYSTORE_TYPE; + if (properties.containsKey(KEYSTORE_TYPE)) { + keystoreType = properties.get(KEYSTORE_TYPE); + } + + Provider keystoreProvider = null; + if (properties.containsKey(KEYSTORE_PROVIDER_NAME)) { + String keystoreProviderName = + properties.get(KEYSTORE_PROVIDER_NAME); + keystoreProvider = + Security.getProvider(keystoreProviderName); + if (keystoreProvider == null) { + throw new IOException("Error locating JCE provider: " + + keystoreProviderName); + } + } + + File keystoreFile = null; + if (properties.containsKey(KEYSTORE_URI)) { + String uri = properties.get(KEYSTORE_URI); + + try { + if (uri.startsWith("file://")) { + keystoreFile = new File(new URI(uri)); + } else { + keystoreFile = new File(uri); + } + + } catch (URISyntaxException | IllegalArgumentException e) { + throw new IOException( + "Error processing keystore property: " + + "keystoreURI=\"" + uri + "\"", e); + } + } + + KeyStore.ProtectionParameter keystoreProtection = null; + if (passwords.containsKey(keystoreName)) { + keystoreProtection = passwords.get(keystoreName); + + } else if (properties.containsKey(KEYSTORE_PASSWORD_ENV)) { + String env = properties.get(KEYSTORE_PASSWORD_ENV); + String pwd = System.getenv(env); + if (pwd != null) { + keystoreProtection = + new KeyStore.PasswordProtection(pwd.toCharArray()); + } else { + throw new IOException( + "Error processing keystore property: " + + "keystorePasswordEnv=\"" + env + "\""); + } + } else { + keystoreProtection = new KeyStore.PasswordProtection(null); + } + + builders.add(new KeyStoreBuilderComponents(keystoreName, + keystoreType, keystoreProvider, keystoreFile, + keystoreProtection)); + } + break; // skip other domains + } + if (builders.isEmpty()) { + throw new IOException("Error locating domain configuration data " + + "for: " + configuration); + } + + return builders; + } + +/* + * Utility class that holds the components used to construct a KeyStore.Builder + */ +class KeyStoreBuilderComponents { + String name; + String type; + Provider provider; + File file; + KeyStore.ProtectionParameter protection; + + KeyStoreBuilderComponents(String name, String type, Provider provider, + File file, KeyStore.ProtectionParameter protection) { + this.name = name; + this.type = type; + this.provider = provider; + this.file = file; + this.protection = protection; + } +} +} diff --git a/jdk/src/share/classes/sun/security/provider/PolicyParser.java b/jdk/src/share/classes/sun/security/provider/PolicyParser.java index b5247c76f9a..b13345f7c55 100644 --- a/jdk/src/share/classes/sun/security/provider/PolicyParser.java +++ b/jdk/src/share/classes/sun/security/provider/PolicyParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, 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 @@ -32,12 +32,7 @@ import java.net.URL; import java.security.GeneralSecurityException; import java.security.Principal; import java.text.MessageFormat; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Vector; -import java.util.StringTokenizer; +import java.util.*; import javax.security.auth.x500.X500Principal; import sun.security.util.Debug; @@ -97,6 +92,7 @@ public class PolicyParser { private Vector grantEntries; + private Map domainEntries; // Convenience variables for parsing private static final Debug debug = Debug.getInstance("parser", @@ -195,9 +191,10 @@ public class PolicyParser { */ lookahead = st.nextToken(); + GrantEntry ge = null; while (lookahead != StreamTokenizer.TT_EOF) { if (peek("grant")) { - GrantEntry ge = parseGrantEntry(); + ge = parseGrantEntry(); // could be null if we couldn't expand a property if (ge != null) add(ge); @@ -209,6 +206,24 @@ public class PolicyParser { // only one keystore passwordURL per policy file, others will be // ignored parseStorePassURL(); + } else if (ge == null && keyStoreUrlString == null && + storePassURL == null && peek("domain")) { + if (domainEntries == null) { + domainEntries = new TreeMap<>(); + } + DomainEntry de = parseDomainEntry(); + if (de != null) { + String domainName = de.getName(); + if (!domainEntries.containsKey(domainName)) { + domainEntries.put(domainName, de); + } else { + MessageFormat form = + new MessageFormat(ResourcesMgr.getString( + "duplicate.keystore.domain.name")); + Object[] source = {domainName}; + throw new ParsingException(form.format(source)); + } + } } else { // error? } @@ -304,6 +319,10 @@ public class PolicyParser { return grantEntries.elements(); } + public Collection getDomainEntries() { + return domainEntries.values(); + } + /** * write out the policy */ @@ -633,6 +652,67 @@ public class PolicyParser { return e; } + /** + * parse a domain entry + */ + private DomainEntry parseDomainEntry() + throws ParsingException, IOException + { + boolean ignoreEntry = false; + DomainEntry domainEntry; + String name = null; + Map properties = new HashMap<>(); + + match("domain"); + name = match("domain name"); + + while(!peek("{")) { + // get the domain properties + properties = parseProperties("{"); + } + match("{"); + domainEntry = new DomainEntry(name, properties); + + while(!peek("}")) { + + match("keystore"); + name = match("keystore name"); + // get the keystore properties + if (!peek("}")) { + properties = parseProperties(";"); + } + match(";"); + domainEntry.add(new KeyStoreEntry(name, properties)); + } + match("}"); + + return (ignoreEntry == true) ? null : domainEntry; + } + + /* + * Return a collection of domain properties or keystore properties. + */ + private Map parseProperties(String terminator) + throws ParsingException, IOException { + + Map properties = new HashMap<>(); + String key; + String value; + while (!peek(terminator)) { + key = match("property name"); + match("="); + + try { + value = expand(match("quoted string")); + } catch (PropertyExpander.ExpandException peee) { + throw new IOException(peee.getLocalizedMessage()); + } + properties.put(key.toLowerCase(), value); + } + + return properties; + } + // package-private: used by PolicyFile for static policy static String[] parseExtDirs(String codebase, int start) { @@ -708,6 +788,10 @@ public class PolicyParser { if (expect.equalsIgnoreCase("*")) found = true; break; + case ';': + if (expect.equalsIgnoreCase(";")) + found = true; + break; default: } @@ -739,6 +823,11 @@ public class PolicyParser { } else if (expect.equalsIgnoreCase("principal type")) { value = st.sval; lookahead = st.nextToken(); + } else if (expect.equalsIgnoreCase("domain name") || + expect.equalsIgnoreCase("keystore name") || + expect.equalsIgnoreCase("property name")) { + value = st.sval; + lookahead = st.nextToken(); } else { throw new ParsingException(st.lineno(), expect, st.sval); @@ -788,6 +877,12 @@ public class PolicyParser { else throw new ParsingException(st.lineno(), expect, "*"); break; + case '=': + if (expect.equalsIgnoreCase("=")) + lookahead = st.nextToken(); + else + throw new ParsingException(st.lineno(), expect, "="); + break; default: throw new ParsingException(st.lineno(), expect, new String(new char[] {(char)lookahead})); @@ -1185,6 +1280,108 @@ public class PolicyParser { } } + /** + * Each domain entry in the keystore domain configuration file is + * represented by a DomainEntry object. + */ + static class DomainEntry { + private final String name; + private final Map properties; + private final Map entries; + + DomainEntry(String name, Map properties) { + this.name = name; + this.properties = properties; + entries = new HashMap<>(); + } + + String getName() { + return name; + } + + Map getProperties() { + return properties; + } + + Collection getEntries() { + return entries.values(); + } + + void add(KeyStoreEntry entry) throws ParsingException { + String keystoreName = entry.getName(); + if (!entries.containsKey(keystoreName)) { + entries.put(keystoreName, entry); + } else { + MessageFormat form = new MessageFormat(ResourcesMgr.getString( + "duplicate.keystore.name")); + Object[] source = {keystoreName}; + throw new ParsingException(form.format(source)); + } + } + + @Override + public String toString() { + StringBuilder s = + new StringBuilder("\ndomain ").append(name); + + if (properties != null) { + for (Map.Entry property : + properties.entrySet()) { + s.append("\n ").append(property.getKey()).append('=') + .append(property.getValue()); + } + } + s.append(" {\n"); + + if (entries != null) { + for (KeyStoreEntry entry : entries.values()) { + s.append(entry).append("\n"); + } + } + s.append("}"); + + return s.toString(); + } + } + + /** + * Each keystore entry in the keystore domain configuration file is + * represented by a KeyStoreEntry object. + */ + + static class KeyStoreEntry { + private final String name; + private final Map properties; + + KeyStoreEntry(String name, Map properties) { + this.name = name; + this.properties = properties; + } + + String getName() { + return name; + } + + Map getProperties() { + return properties; + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder("\n keystore ").append(name); + if (properties != null) { + for (Map.Entry property : + properties.entrySet()) { + s.append("\n ").append(property.getKey()).append('=') + .append(property.getValue()); + } + } + s.append(";"); + + return s.toString(); + } + } + public static class ParsingException extends GeneralSecurityException { private static final long serialVersionUID = -4330692689482574072L; diff --git a/jdk/src/share/classes/sun/security/provider/Sun.java b/jdk/src/share/classes/sun/security/provider/Sun.java index 20edc86b275..4af2be50864 100644 --- a/jdk/src/share/classes/sun/security/provider/Sun.java +++ b/jdk/src/share/classes/sun/security/provider/Sun.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2013, 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 @@ -40,13 +40,14 @@ public final class Sun extends Provider { private static final String INFO = "SUN " + "(DSA key/parameter generation; DSA signing; SHA-1, MD5 digests; " + - "SecureRandom; X.509 certificates; JKS keystore; PKIX CertPathValidator; " + + "SecureRandom; X.509 certificates; JKS & DKS keystores; " + + "PKIX CertPathValidator; " + "PKIX CertPathBuilder; LDAP, Collection CertStores, JavaPolicy Policy; " + "JavaLoginConfig Configuration)"; public Sun() { /* We are the SUN provider */ - super("SUN", 1.7, INFO); + super("SUN", 1.8, INFO); // if there is no security manager installed, put directly into // the provider. Otherwise, create a temporary map and use a diff --git a/jdk/src/share/classes/sun/security/provider/SunEntries.java b/jdk/src/share/classes/sun/security/provider/SunEntries.java index 3876acbf3be..daa4e96760c 100644 --- a/jdk/src/share/classes/sun/security/provider/SunEntries.java +++ b/jdk/src/share/classes/sun/security/provider/SunEntries.java @@ -208,6 +208,7 @@ final class SunEntries { map.put("KeyStore.JKS", "sun.security.provider.JavaKeyStore$JKS"); map.put("KeyStore.CaseExactJKS", "sun.security.provider.JavaKeyStore$CaseExactJKS"); + map.put("KeyStore.DKS", "sun.security.provider.DomainKeyStore$DKS"); /* * Policy diff --git a/jdk/src/share/classes/sun/security/util/Resources.java b/jdk/src/share/classes/sun/security/util/Resources.java index ef073b0a1fd..50028264d14 100644 --- a/jdk/src/share/classes/sun/security/util/Resources.java +++ b/jdk/src/share/classes/sun/security/util/Resources.java @@ -127,6 +127,8 @@ public class Resources extends java.util.ListResourceBundle { {"multiple.Codebase.expressions", "multiple Codebase expressions"}, {"multiple.SignedBy.expressions","multiple SignedBy expressions"}, + {"duplicate.keystore.domain.name","duplicate keystore domain name: {0}"}, + {"duplicate.keystore.name","duplicate keystore name: {0}"}, {"SignedBy.has.empty.alias","SignedBy has empty alias"}, {"can.not.specify.Principal.with.a.wildcard.class.without.a.wildcard.name", "can not specify Principal with a wildcard class without a wildcard name"}, diff --git a/jdk/test/sun/security/provider/KeyStore/DKSTest.java b/jdk/test/sun/security/provider/KeyStore/DKSTest.java new file mode 100644 index 00000000000..c2b6baf3a42 --- /dev/null +++ b/jdk/test/sun/security/provider/KeyStore/DKSTest.java @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2013, 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. + */ + +/* + * see ./DKSTest.sh + */ + +import java.io.*; +import java.net.*; +import java.security.*; +import java.security.KeyStore; +import java.security.cert.*; +import java.security.cert.Certificate; +import java.util.*; + +// Load and store entries in domain keystores + +public class DKSTest { + + private static final String TEST_SRC = System.getProperty("test.src"); + private static final String CERT = TEST_SRC + "/../../pkcs12/trusted.pem"; + private static final String CONFIG = "file://" + TEST_SRC + "/domains.cfg"; + private static final Map PASSWORDS = + new HashMap() {{ + put("keystore", + new KeyStore.PasswordProtection("test123".toCharArray())); + put("policy_keystore", + new KeyStore.PasswordProtection( + "Alias.password".toCharArray())); + put("pw_keystore", + new KeyStore.PasswordProtection("test12".toCharArray())); + put("eckeystore1", + new KeyStore.PasswordProtection("password".toCharArray())); + put("eckeystore2", + new KeyStore.PasswordProtection("password".toCharArray())); + put("truststore", + new KeyStore.PasswordProtection("changeit".toCharArray())); + put("empty", + new KeyStore.PasswordProtection("passphrase".toCharArray())); + }}; + + public static void main(String[] args) throws Exception { + try { + main0(); + } finally { + // cleanup + new File(TEST_SRC + "/empty.jks").delete(); + new File(TEST_SRC + "/Alias.keystore_tmp").delete(); + new File(TEST_SRC + "/pw.jks_tmp").delete(); + new File(TEST_SRC + "/secp256r1server-secp384r1ca.p12_tmp").delete(); + new File(TEST_SRC + "/sect193r1server-rsa1024ca.p12_tmp").delete(); + } + } + + private static void main0() throws Exception { + /* + * domain keystore: system + */ + URI config = new URI(CONFIG + "#system"); + int cacertsCount; + int expected; + KeyStore keystore = KeyStore.getInstance("DKS"); + // load entries + keystore.load( + new KeyStore.DomainLoadStoreParameter(config, PASSWORDS)); + cacertsCount = expected = keystore.size(); + System.out.println("\nLoading domain keystore: " + config + "\t[" + + expected + " entries]"); + checkEntries(keystore, expected); + + /* + * domain keystore: system_plus + */ + config = new URI(CONFIG + "#system_plus"); + expected = cacertsCount + 1; + keystore = KeyStore.getInstance("DKS"); + // load entries + keystore.load( + new KeyStore.DomainLoadStoreParameter(config, PASSWORDS)); + System.out.println("\nLoading domain keystore: " + config + "\t[" + + expected + " entries]"); + checkEntries(keystore, expected); + + /* + * domain keystore: system_env + */ + config = new URI(CONFIG + "#system_env"); + expected = 1 + cacertsCount; + keystore = KeyStore.getInstance("DKS"); + // load entries + keystore.load( + new KeyStore.DomainLoadStoreParameter(config, + Collections.emptyMap())); + System.out.println("\nLoading domain keystore: " + config + "\t[" + + expected + " entries]"); + checkEntries(keystore, expected); + + /* + * domain keystore: empty + */ + KeyStore empty = KeyStore.getInstance("JKS"); + empty.load(null, null); + + try (OutputStream outStream = + new FileOutputStream(TEST_SRC + "/empty.jks")) { + empty.store(outStream, "passphrase".toCharArray()); + } + config = new URI(CONFIG + "#empty"); + expected = 0; + keystore = KeyStore.getInstance("DKS"); + // load entries + keystore.load( + new KeyStore.DomainLoadStoreParameter(config, PASSWORDS)); + System.out.println("\nLoading domain keystore: " + config + "\t[" + + expected + " entries]"); + checkEntries(keystore, expected); + + /* + * domain keystore: keystores + */ + config = new URI(CONFIG + "#keystores"); + expected = 2 + 1 + 1 + 1; + keystore = KeyStore.getInstance("DKS"); + // load entries + keystore.load( + new KeyStore.DomainLoadStoreParameter(config, PASSWORDS)); + System.out.println("\nLoading domain keystore: " + config + "\t[" + + expected + " entries]"); + checkEntries(keystore, expected); + // set a new trusted certificate entry + Certificate cert = loadCertificate(CERT); + String alias = "pw_keystore tmp-cert"; + System.out.println("Setting new trusted certificate entry: " + alias); + keystore.setEntry(alias, + new KeyStore.TrustedCertificateEntry(cert), null); + expected++; + // store entries + config = new URI(CONFIG + "#keystores_tmp"); + System.out.println("Storing domain keystore: " + config + "\t[" + + expected + " entries]"); + keystore.store( + new KeyStore.DomainLoadStoreParameter(config, PASSWORDS)); + keystore = KeyStore.getInstance("DKS"); + // reload entries + keystore.load( + new KeyStore.DomainLoadStoreParameter(config, PASSWORDS)); + System.out.println("Reloading domain keystore: " + config + "\t[" + + expected + " entries]"); + checkEntries(keystore, expected); + // get the new trusted certificate entry + System.out.println("Getting new trusted certificate entry: " + alias); + if (!keystore.isCertificateEntry(alias)) { + throw new Exception("Error: cannot retrieve certificate entry: " + + alias); + } + keystore.setEntry(alias, + new KeyStore.TrustedCertificateEntry(cert), null); + } + + private static void checkEntries(KeyStore keystore, int expected) + throws Exception { + int i = 0; + for (String alias : Collections.list(keystore.aliases())) { + System.out.print("."); + i++; + } + System.out.println(); + if (expected != i) { + throw new Exception("Error: unexpected entry count in keystore: " + + "loaded=" + i + ", expected=" + expected); + } + } + + private static Certificate loadCertificate(String certFile) + throws Exception { + X509Certificate cert = null; + try (FileInputStream certStream = new FileInputStream(certFile)) { + CertificateFactory factory = + CertificateFactory.getInstance("X.509"); + return factory.generateCertificate(certStream); + } + } +} diff --git a/jdk/test/sun/security/provider/KeyStore/DKSTest.sh b/jdk/test/sun/security/provider/KeyStore/DKSTest.sh new file mode 100644 index 00000000000..b789e414140 --- /dev/null +++ b/jdk/test/sun/security/provider/KeyStore/DKSTest.sh @@ -0,0 +1,84 @@ +#! /bin/sh + +# +# Copyright (c) 2013, 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 8007755 +# @summary Support the logical grouping of keystores + +# set a few environment variables so that the shell-script can run stand-alone +# in the source directory +if [ "${TESTSRC}" = "" ] ; then + TESTSRC="." +fi + +if [ "${TESTCLASSES}" = "" ] ; then + TESTCLASSES="." +fi + +if [ "${TESTJAVA}" = "" ] ; then + echo "TESTJAVA not set. Test cannot execute." + echo "FAILED!!!" + exit 1 +fi + +if [ "${COMPILEJAVA}" = "" ]; then + COMPILEJAVA="${TESTJAVA}" +fi + +# set platform-dependent variables +OS=`uname -s` +case "$OS" in + SunOS ) + PS=":" + FS="/" + ;; + Linux ) + PS=":" + FS="/" + ;; + Darwin ) + PS=":" + FS="/" + ;; + CYGWIN* ) + PS=";" + FS="/" + ;; + Windows* ) + PS=";" + FS="\\" + ;; + * ) + echo "Unrecognized system!" + exit 1; + ;; +esac + +${COMPILEJAVA}${FS}bin${FS}javac -d . ${TESTSRC}${FS}DKSTest.java + +KEYSTORE_PWD=test12 TRUSTSTORE_PWD=changeit \ + ${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Dtest.src=${TESTSRC} DKSTest + +exit $status diff --git a/jdk/test/sun/security/provider/KeyStore/domains.cfg b/jdk/test/sun/security/provider/KeyStore/domains.cfg new file mode 100644 index 00000000000..203d9d007ca --- /dev/null +++ b/jdk/test/sun/security/provider/KeyStore/domains.cfg @@ -0,0 +1,65 @@ +// domain containing a single keystore +domain system { + keystore truststore + keystoreType="JKS" + keystoreURI="${java.home}/lib/security/cacerts"; +}; + +// domain containing two JKS keystores +domain system_plus { + keystore truststore + keystoreType="JKS" + keystoreURI="${java.home}/lib/security/cacerts"; + keystore pw_keystore + keystoreType="JKS" + keystoreURI="${test.src}/pw.jks"; +}; + +// domain containing a mixture of keystores +domain keystores + keystoreType="PKCS12" { + keystore policy_keystore + keystoreType="JKS" + keystoreURI="${test.src}/../PolicyFile/Alias.keystore"; + keystore pw_keystore + keystoreType="CaseExactJKS" + keystoreURI="${test.src}/pw.jks"; + keystore eckeystore1 + keystoreURI="${test.src}/../../pkcs11/ec/pkcs12/sect193r1server-rsa1024ca.p12"; + keystore eckeystore2 + keystoreURI="${test.src}/../../pkcs11/ec/pkcs12/secp256r1server-secp384r1ca.p12"; +}; + +// domain containing a mixture of keystores +domain keystores_tmp + keystoreType="PKCS12" { + keystore policy_keystore + keystoreType="JKS" + keystoreURI="${test.src}/Alias.keystore_tmp"; + keystore pw_keystore + keystoreType="CaseExactJKS" + keystoreURI="${test.src}/pw.jks_tmp"; + keystore eckeystore1 + keystoreURI="${test.src}/sect193r1server-rsa1024ca.p12_tmp"; + keystore eckeystore2 + keystoreURI="${test.src}/secp256r1server-secp384r1ca.p12_tmp"; +}; + +// domain where passwords are supplied via environment variables +domain system_env + keystoreType="JKS" + keystorePasswordEnv="KEYSTORE_PWD" { + keystore env_keystore + keystoreURI="${test.src}/pw.jks"; + keystore env_truststore + keystoreURI="${java.home}/lib/security/cacerts" + keystorePasswordEnv="TRUSTSTORE_PWD"; +}; + +// empty domain +domain empty + keystoreType="JKS" + keystoreProviderName="SUN" { + keystore empty + keystoreURI="${test.src}/empty.jks"; +}; diff --git a/jdk/test/sun/security/tools/keytool/AltProviderPath.sh b/jdk/test/sun/security/tools/keytool/AltProviderPath.sh index 067a5eb7bf0..82bc65787ab 100644 --- a/jdk/test/sun/security/tools/keytool/AltProviderPath.sh +++ b/jdk/test/sun/security/tools/keytool/AltProviderPath.sh @@ -73,7 +73,7 @@ ${TESTJAVA}${FS}bin${FS}keytool -genkey -v -alias dummyTestCA \ -keyalg "RSA" -keysize 1024 -sigalg "ShA1WithRSA" \ -dname "cn=Dummy Test CA, ou=JSN, o=JavaSoft, c=US" -validity 3650 \ -keypass storepass -keystore keystoreCA.dks -storepass storepass \ - -storetype "dks" -provider "org.test.dummy.DummyProvider" \ + -storetype "dummyks" -provider "org.test.dummy.DummyProvider" \ -providerPath ${TESTCLASSES} if [ $? -ne 0 ]; then @@ -82,7 +82,7 @@ fi #Change keystore password ${TESTJAVA}${FS}bin${FS}keytool -storepasswd -new storepass2 \ - -keystore keystoreCA.dks -storetype "dks" -storepass storepass \ + -keystore keystoreCA.dks -storetype "dummyks" -storepass storepass \ -provider "org.test.dummy.DummyProvider" -providerPath ${TESTCLASSES} if [ $? -ne 0 ]; then @@ -93,7 +93,7 @@ fi #Change keystore key password ${TESTJAVA}${FS}bin${FS}keytool -keypasswd -alias "dummyTestCA" \ -keypass storepass -new keypass -keystore keystoreCA.dks \ - -storetype "dks" -storepass storepass2 \ + -storetype "dummyks" -storepass storepass2 \ -provider "org.test.dummy.DummyProvider" -providerPath ${TESTCLASSES} if [ $? -ne 0 ]; then @@ -102,7 +102,7 @@ fi #Export certificate ${TESTJAVA}${FS}bin${FS}keytool -v -export -rfc -alias "dummyTestCA" \ - -file "dummyTestCA.der" -keystore keystoreCA.dks -storetype "dks" \ + -file "dummyTestCA.der" -keystore keystoreCA.dks -storetype "dummyks" \ -storepass storepass2 -provider "org.test.dummy.DummyProvider" \ -providerPath ${TESTCLASSES} @@ -112,7 +112,7 @@ fi #list keystore ${TESTJAVA}${FS}bin${FS}keytool -v -list -keystore keystoreCA.dks \ - -storetype "dks" -storepass storepass2 \ + -storetype "dummyks" -storepass storepass2 \ -provider "org.test.dummy.DummyProvider" -providerPath ${TESTCLASSES} if [ $? -ne 0 ]; then diff --git a/jdk/test/sun/security/tools/keytool/DummyProvider.java b/jdk/test/sun/security/tools/keytool/DummyProvider.java index ae714702051..0c7ce10d587 100644 --- a/jdk/test/sun/security/tools/keytool/DummyProvider.java +++ b/jdk/test/sun/security/tools/keytool/DummyProvider.java @@ -40,7 +40,7 @@ public class DummyProvider extends Provider { // // KeyStore // - put("KeyStore.DKS", "sun.security.provider.JavaKeyStore$JKS"); + put("KeyStore.DummyKS", "sun.security.provider.JavaKeyStore$JKS"); // // Signature engines From 48a592be5a11afd43a08cd92ba40a525ae8bf7e2 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Wed, 13 Feb 2013 11:49:34 -0800 Subject: [PATCH 34/39] 8008161: Regression: j.u.TimeZone.getAvailableIDs(rawOffset) returns non-sorted list To return a sorted list Reviewed-by: lancea, naoto --- .../sun/util/calendar/ZoneInfoFile.java | 8 +++++++- .../sun/util/calendar/zi/TestZoneInfo310.java | 20 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java b/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java index ab1cf5c6dc9..2bddab21f2d 100644 --- a/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -92,7 +92,13 @@ public final class ZoneInfoFile { ids.add(id); } } - return ids.toArray(new String[ids.size()]); + // It appears the "zi" implementation returns the + // sorted list, though the specification does not + // specify it. Keep the same behavior for better + // compatibility. + String[] list = ids.toArray(new String[ids.size()]); + Arrays.sort(list); + return list; } public static ZoneInfo getZoneInfo(String zoneId) { diff --git a/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java b/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java index c9e2bd9e6f7..f1191c6e90c 100644 --- a/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java +++ b/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java @@ -23,7 +23,7 @@ /* *@test - *@bug 8007572 + *@bug 8007572 8008161 *@summary Test whether the TimeZone generated from JSR310 tzdb is the same *as the one from the tz data from javazic */ @@ -156,6 +156,24 @@ public class TestZoneInfo310 { sun.util.calendar.ZoneInfoFile.getVersion(), ver); throw new RuntimeException("Version test failed"); } + + // test getAvailableIDs(raw); + zids_new = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000); + //Arrays.sort(zids_new); + zids_old = ZoneInfoOld.getAvailableIDs(-8 * 60 * 60 * 1000); + if (!Arrays.equals(zids_new, zids_old)) { + System.out.println("------------------------"); + System.out.println("NEW.getAvailableIDs(-8:00)"); + for (String zid : zids_new) { + System.out.println(zid); + } + System.out.println("------------------------"); + System.out.println("OLD.getAvailableIDs(-8:00)"); + for (String zid : zids_old) { + System.out.println(zid); + } + throw new RuntimeException(" FAILED: availableIds(offset) don't match"); + } } private static void delete(File f) { From 4c2a4c9b4addb83531c2b781bb52ff7861922368 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Wed, 13 Feb 2013 12:56:46 -0800 Subject: [PATCH 35/39] 8005750: [parfait] Memory leak at jdk/src/share/bin/parse_manifest.c Reviewed-by: jjh --- jdk/src/share/bin/parse_manifest.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/jdk/src/share/bin/parse_manifest.c b/jdk/src/share/bin/parse_manifest.c index 61c5b883081..61b0bbf4884 100644 --- a/jdk/src/share/bin/parse_manifest.c +++ b/jdk/src/share/bin/parse_manifest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2013, 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 @@ -106,8 +106,9 @@ inflate_file(int fd, zentry *entry, int *size_out) *size_out = (int)entry->isize; } return (out); - } else - return (NULL); + } + free(in); + return (NULL); } static jboolean zip64_present = JNI_FALSE; From db31a896d88bc059633fc521ebdfebdd7df9a596 Mon Sep 17 00:00:00 2001 From: Bharadwaj Yadavalli Date: Wed, 13 Feb 2013 16:09:13 -0500 Subject: [PATCH 36/39] 8007888: jdk fix default method: VerifyError: Illegal use of nonvirtual Recognize VM generated method in old verifier. With 8004967 Reviewed-by: coleenp, acorn --- jdk/src/share/javavm/export/jvm.h | 7 +++++++ jdk/src/share/native/common/check_code.c | 8 +++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/javavm/export/jvm.h b/jdk/src/share/javavm/export/jvm.h index 1f785f1a108..44b0be576d4 100644 --- a/jdk/src/share/javavm/export/jvm.h +++ b/jdk/src/share/javavm/export/jvm.h @@ -821,6 +821,13 @@ JVM_GetMethodIxMaxStack(JNIEnv *env, jclass cb, int index); JNIEXPORT jboolean JNICALL JVM_IsConstructorIx(JNIEnv *env, jclass cb, int index); +/* + * Is the given method generated by the VM. + * The method is identified by method_index. + */ +JNIEXPORT jboolean JNICALL +JVM_IsVMGeneratedMethodIx(JNIEnv *env, jclass cb, int index); + /* * Returns the name of a given method in UTF format. * The result remains valid until JVM_ReleaseUTF is called. diff --git a/jdk/src/share/native/common/check_code.c b/jdk/src/share/native/common/check_code.c index c5e8855ee68..c761a3d9158 100644 --- a/jdk/src/share/native/common/check_code.c +++ b/jdk/src/share/native/common/check_code.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, 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 @@ -983,6 +983,12 @@ verify_method(context_type *context, jclass cb, int method_index, CCerror(context, "Inconsistent access bits."); } + // If this method is an overpass method, which is generated by the VM, + // we trust the code and no check needs to be done. + if (JVM_IsVMGeneratedMethodIx(env, cb, method_index)) { + return; + } + /* Run through the code. Mark the start of each instruction, and give * the instruction a number */ for (i = 0, offset = 0; offset < code_length; i++) { From ba9cf66b4823464b0e2ec9207b0bf5c7d3179ff5 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Wed, 13 Feb 2013 13:22:31 -0800 Subject: [PATCH 37/39] 8007935: java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh should use $COMPILEJAVA for javac Reviewed-by: sspitsyn, alanb --- .../instrument/RedefineSubclassWithTwoInterfaces.sh | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh index 8e1c81f3c17..6deb7ce6e44 100644 --- a/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh +++ b/jdk/test/java/lang/instrument/RedefineSubclassWithTwoInterfaces.sh @@ -23,6 +23,7 @@ # @test # @bug 7182152 +# @bug 8007935 # @summary Redefine a subclass that implements two interfaces and # verify that the right methods are called. # @author Daniel D. Daugherty @@ -38,6 +39,12 @@ then exit 1 fi +if [ "${COMPILEJAVA}" = "" ] +then + COMPILEJAVA="${TESTJAVA}" +fi +echo "COMPILEJAVA=${COMPILEJAVA}" + if [ "${TESTSRC}" = "" ] then echo "TESTSRC not set. Test cannot execute. Failed." @@ -50,7 +57,7 @@ then exit 1 fi -JAVAC="${TESTJAVA}"/bin/javac +JAVAC="${COMPILEJAVA}"/bin/javac JAVA="${TESTJAVA}"/bin/java echo "INFO: building the replacement classes." @@ -59,7 +66,8 @@ cp "${TESTSRC}"/RedefineSubclassWithTwoInterfacesTarget_1.java \ RedefineSubclassWithTwoInterfacesTarget.java cp "${TESTSRC}"/RedefineSubclassWithTwoInterfacesImpl_1.java \ RedefineSubclassWithTwoInterfacesImpl.java -"${JAVAC}" -cp "${TESTCLASSES}" -d . \ +"${JAVAC}" ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \ + -cp "${TESTCLASSES}" -d . \ RedefineSubclassWithTwoInterfacesTarget.java \ RedefineSubclassWithTwoInterfacesImpl.java status="$?" From 20987e6144293bd6be3e3be2e852a48cc7b16f70 Mon Sep 17 00:00:00 2001 From: Jia-Hong Chen Date: Wed, 13 Feb 2013 15:06:47 -0800 Subject: [PATCH 38/39] 8008017: The fix for 8005129 does not build on Windows Reviewed-by: prr, jgodinez --- jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16ext.c | 4 ++-- jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16nw.c | 4 ++-- jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8ext.c | 4 ++-- jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8nw.c | 4 ++-- jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16ext.c | 4 ++-- jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16nw.c | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16ext.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16ext.c index 845f9a56a22..70f3831bcc2 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16ext.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16ext.c @@ -1884,10 +1884,10 @@ mlib_status CONV_FUNC_MxN mlib_s32 nchannel, chan1, chan2; mlib_s32 i, j, c, swid; d64_2x32 dd; - GET_SRC_DST_PARAMETERS(DTYPE); - mlib_status status = MLIB_SUCCESS; + GET_SRC_DST_PARAMETERS(DTYPE); + if (scale > 30) { fscale *= 1.0/(1 << 30); scale -= 30; diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16nw.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16nw.c index 57dbca4c848..7fc3d5e0464 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16nw.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_16nw.c @@ -1651,10 +1651,10 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, DEF_VARS(DTYPE); mlib_s32 chan2; mlib_s32 *buffo, *buffi; - GET_SRC_DST_PARAMETERS(DTYPE); - mlib_status status = MLIB_SUCCESS; + GET_SRC_DST_PARAMETERS(DTYPE); + if (scale > 30) { fscale *= 1.0/(1 << 30); scale -= 30; diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8ext.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8ext.c index 961ade907b0..1ca321e1237 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8ext.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8ext.c @@ -1884,10 +1884,10 @@ mlib_status CONV_FUNC_MxN mlib_s32 nchannel, chan1, chan2; mlib_s32 i, j, c, swid; d64_2x32 dd; - GET_SRC_DST_PARAMETERS(DTYPE); - mlib_status status = MLIB_SUCCESS; + GET_SRC_DST_PARAMETERS(DTYPE); + if (scale > 30) { fscale *= 1.0/(1 << 30); scale -= 30; diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8nw.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8nw.c index 1f94eabba66..5c4de68db69 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8nw.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_8nw.c @@ -1652,10 +1652,10 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, DEF_VARS(DTYPE); mlib_s32 chan2; mlib_s32 *buffo, *buffi; - GET_SRC_DST_PARAMETERS(DTYPE); - mlib_status status = MLIB_SUCCESS; + GET_SRC_DST_PARAMETERS(DTYPE); + if (scale > 30) { fscale *= 1.0/(1 << 30); scale -= 30; diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16ext.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16ext.c index 9fb835c83fe..0369f57b250 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16ext.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16ext.c @@ -1884,10 +1884,10 @@ mlib_status CONV_FUNC_MxN mlib_s32 nchannel, chan1, chan2; mlib_s32 i, j, c, swid; d64_2x32 dd; - GET_SRC_DST_PARAMETERS(DTYPE); - mlib_status status = MLIB_SUCCESS; + GET_SRC_DST_PARAMETERS(DTYPE); + if (scale > 30) { fscale *= 1.0/(1 << 30); scale -= 30; diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16nw.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16nw.c index 68578a27af9..fe159095545 100644 --- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16nw.c +++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageConv_u16nw.c @@ -1651,10 +1651,10 @@ mlib_status CONV_FUNC(MxN)(mlib_image *dst, DEF_VARS(DTYPE); mlib_s32 chan2; mlib_s32 *buffo, *buffi; - GET_SRC_DST_PARAMETERS(DTYPE); - mlib_status status = MLIB_SUCCESS; + GET_SRC_DST_PARAMETERS(DTYPE); + if (scale > 30) { fscale *= 1.0/(1 << 30); scale -= 30; From 14251d648086938593a96e80d3dc7dde2af5a192 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 14 Feb 2013 11:44:09 -0800 Subject: [PATCH 39/39] Added tag jdk8-b77 for changeset e587650e9aa6 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index ea4808559e0..6622885bcd8 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -198,3 +198,4 @@ a996b57e554198f4592a5f3c30f2f9f4075e545d jdk8-b70 57d5d954462831ac353a1f40d3bb05ddb4620952 jdk8-b74 4a67fdb752b7d6329d9be9c28d3f9d6cf7eb9a3c jdk8-b75 3a263052866137b645ab86498a43693ff5c19e69 jdk8-b76 +b2fc8e31cecc35b76188e821d4c5dc0e0b74ac24 jdk8-b77